From: Andy P. <at...@us...> - 2002-04-09 15:08:17
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/vfat In directory usw-pr-cvs1:/tmp/cvs-serv32005/vfat Modified Files: namei.c vfatfs_syms.c Log Message: synch 2.4.15 commit 14 Index: namei.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/vfat/namei.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- namei.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ namei.c 9 Apr 2002 13:30:20 -0000 1.2 @@ -9,10 +9,12 @@ * what file operation caused you trouble and if you can duplicate * the problem, send a script that demonstrates it. * - * Short name translation 1999 by Wolfram Pienkoss <wp...@bs...> + * Short name translation 1999, 2001 by Wolfram Pienkoss <wp...@bs...> + * + * Support Multibyte character and cleanup by + * OGAWA Hirofumi <hir...@ma...> */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/sched.h> @@ -26,8 +28,6 @@ #include <linux/mm.h> #include <linux/slab.h> -#include "../fat/msbuffer.h" - #define DEBUG_LEVEL 0 #if (DEBUG_LEVEL >= 1) # define PRINTK1(x) printk x @@ -45,12 +45,6 @@ # define PRINTK3(x) #endif -#ifndef DEBUG -# define CHECK_STACK -#else -# define CHECK_STACK check_stack(__FILE__, __LINE__) -#endif - static int vfat_hashi(struct dentry *parent, struct qstr *qstr); static int vfat_hash(struct dentry *parent, struct qstr *qstr); static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); @@ -114,6 +108,13 @@ opts->unicode_xlate = opts->posixfs = 0; opts->numtail = 1; opts->utf8 = 0; + opts->shortname = VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95; + /* for backward compatible */ + if (opts->nocase) { + opts->nocase = 0; + opts->shortname = VFAT_SFN_DISPLAY_WIN95 + | VFAT_SFN_CREATE_WIN95; + } if (!options) return 1; save = 0; @@ -139,6 +140,21 @@ if (ret) { opts->numtail = !val; } + } else if (!strcmp(this_char, "shortname")) { + if (!strcmp(value, "lower")) + opts->shortname = VFAT_SFN_DISPLAY_LOWER + | VFAT_SFN_CREATE_WIN95; + else if (!strcmp(value, "win95")) + opts->shortname = VFAT_SFN_DISPLAY_WIN95 + | VFAT_SFN_CREATE_WIN95; + else if (!strcmp(value, "winnt")) + opts->shortname = VFAT_SFN_DISPLAY_WINNT + | VFAT_SFN_CREATE_WINNT; + else if (!strcmp(value, "mixed")) + opts->shortname = VFAT_SFN_DISPLAY_WINNT + | VFAT_SFN_CREATE_WIN95; + else + ret = 0; } if (this_char != options) *(this_char-1) = ','; @@ -156,12 +172,6 @@ } static inline unsigned char -vfat_getlower(struct nls_table *t, unsigned char c) -{ - return t->charset2lower[c]; -} - -static inline unsigned char vfat_tolower(struct nls_table *t, unsigned char c) { unsigned char nc = t->charset2lower[c]; @@ -170,12 +180,6 @@ } static inline unsigned char -vfat_getupper(struct nls_table *t, unsigned char c) -{ - return t->charset2upper[c]; -} - -static inline unsigned char vfat_toupper(struct nls_table *t, unsigned char c) { unsigned char nc = t->charset2upper[c]; @@ -194,31 +198,6 @@ return 0; } -static inline int -vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound) -{ - int charlen; - - if ( (charlen = t->uni2char(uc, op, bound)) < 0) - charlen = 0; - - return charlen; -} - -static inline int -vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound) -{ - int chi, chl; - - if ( (chl = t->uni2char(uc, op, bound)) < 0) - chl = 0; - - for (chi = 0; chi < chl; chi++) - op[chi] = vfat_toupper(t, op[chi]); - - return chl; -} - /* * Compute the hash for the vfat name corresponding to the dentry. * Note: if the name is invalid, we leave the hash code unchanged so @@ -311,33 +290,6 @@ #ifdef DEBUG -static void -check_stack(const char *fname, int lineno) -{ - int stack_level; - char *pg_dir; - - stack_level = (long)(&pg_dir)-current->kernel_stack_page; - if (stack_level < 0) - printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n", - fname, lineno, stack_level); - else if (stack_level < 500) - printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n", - fname, lineno, stack_level); -#if 0 - else - printk("------- vfat kstack ok in %s line %d: SL=%d\n", - fname, lineno, stack_level); -#endif -#if 0 - if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) { - printk("******* vfat stack corruption detected in %s at line %d\n", - fname, lineno); - } -#endif -} - -static int debug = 0; static void dump_fat(struct super_block *sb,int start) { printk("["); @@ -383,8 +335,44 @@ /* Characters that are undesirable in an MS-DOS file name */ -static char bad_chars[] = "*?<>|\":/\\"; -static char replace_chars[] = "[];,+="; +static wchar_t bad_chars[] = { + /* `*' `?' `<' `>' `|' `"' `:' `/' */ + 0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, + /* `\' */ + 0x005C, 0, +}; +#define IS_BADCHAR(uni) (vfat_unistrchr(bad_chars, (uni)) != NULL) + +static wchar_t replace_chars[] = { + /* `[' `]' `;' `,' `+' `=' */ + 0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0, +}; +#define IS_REPLACECHAR(uni) (vfat_unistrchr(replace_chars, (uni)) != NULL) + +static wchar_t skip_chars[] = { + /* `.' ` ' */ + 0x002E, 0x0020, 0, +}; +#define IS_SKIPCHAR(uni) \ + ((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1]) + +static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c) +{ + for(; *s != c; ++s) + if (*s == 0) + return NULL; + return (wchar_t *) s; +} + +static inline int vfat_is_used_badchars(const wchar_t *s, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (s[i] < 0x0020 || IS_BADCHAR(s[i])) + return -EINVAL; + return 0; +} /* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal @@ -393,18 +381,10 @@ static int vfat_valid_longname(const char *name, int len, int xlate) { const char **reserved, *walk; - unsigned char c; - int i, baselen; + int baselen; if (len && name[len-1] == ' ') return -EINVAL; if (len >= 256) return -EINVAL; - for (i = 0; i < len; i++) { - c = name[i]; - if (xlate && c == ':') continue; - if (strchr(bad_chars,c)) { - return -EINVAL; - } - } if (len < 3) return 0; for (walk = name; *walk != 0 && *walk != '.'; walk++); @@ -424,72 +404,6 @@ return 0; } -static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) -{ - wchar_t *walk; - unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE]; - int chl, chi; - int space; - - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; - - if (IS_FREE(charbuf)) - return -EINVAL; - - chl = 0; - c = 0; - space = 1; /* disallow names starting with a dot */ - for (walk = name; len && walk-name < 8;) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) return -EINVAL; - if (c < ' '|| c==':') return -EINVAL; - if (c == '.') goto dot; - space = c == ' '; - } - } -dot:; - if (space) return -EINVAL; - if (len && c != '.') { - len--; - if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { - if (charbuf[0] != '.') return -EINVAL; - } else - return -EINVAL; - c = '.'; - } - if (c == '.') { - if (len >= 4) return -EINVAL; - while (len > 0) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) - return -EINVAL; - if (c < ' ' || c == '.'|| c==':') - return -EINVAL; - space = c == ' '; - } - } - if (space) return -EINVAL; - } - - return 0; -} - static int vfat_find_form(struct inode *dir,char *name) { struct msdos_dir_entry *de; @@ -503,127 +417,134 @@ return 0; } -static int vfat_format_name(struct nls_table *nls, wchar_t *name, - int len, char *res) +/* + * 1) Valid characters for the 8.3 format alias are any combination of + * letters, uppercase alphabets, digits, any of the + * following special characters: + * $ % ' ` - @ { } ~ ! # ( ) & _ ^ + * In this case Longfilename is not stored in disk. + * + * WinNT's Extension: + * File name and extension name is contain uppercase/lowercase + * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT. + * + * 2) File name is 8.3 format, but it contain the uppercase and + * lowercase char, muliti bytes char, etc. In this case numtail is not + * added, but Longfilename is stored. + * + * 3) When the one except for the above, or the following special + * character are contained: + * . [ ] ; , + = + * numtail is added, and Longfilename must be stored in disk . + */ +struct shortname_info { + unsigned char lower:1, + upper:1, + valid:1; +}; +#define INIT_SHORTNAME_INFO(x) do { \ + (x)->lower = 1; \ + (x)->upper = 1; \ + (x)->valid = 1; \ +} while (0); + +static inline unsigned char +shortname_info_to_lcase(struct shortname_info *base, + struct shortname_info *ext) { - char *walk; - unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; - int chi, chl; - int space; + unsigned char lcase = 0; - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; + if (base->valid && ext->valid) { + if (!base->upper && base->lower && (ext->lower || ext->upper)) + lcase |= CASE_LOWER_BASE; + if (!ext->upper && ext->lower && (base->lower || base->upper)) + lcase |= CASE_LOWER_EXT; + } - if (IS_FREE(charbuf)) - return -EINVAL; + return lcase; +} - space = 1; /* disallow names starting with a dot */ - for (walk = res; len--; ) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == '.') goto dot; - if (!charbuf[chi]) return -EINVAL; - if (walk-res == 8) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) return -EINVAL; - if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; - space = charbuf[chi] == ' '; - *walk = charbuf[chi]; - walk++; - } - } -dot:; - if (space) return -EINVAL; - if (len >= 0) { - while (walk-res < 8) *walk++ = ' '; - while (len > 0 && walk-res < MSDOS_NAME) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (len < chl) - chl = len; - len -= chl; - for (chi = 0; chi < chl; chi++){ - if (!charbuf[chi]) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) - return -EINVAL; - if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') - return -EINVAL; - space = charbuf[chi] == ' '; - *walk++ = charbuf[chi]; - } +static inline int to_shortname_char(struct nls_table *nls, + char *buf, int buf_size, wchar_t *src, + struct shortname_info *info) +{ + int len; + + if (IS_SKIPCHAR(*src)) { + info->valid = 0; + return 0; + } + if (IS_REPLACECHAR(*src)) { + info->valid = 0; + buf[0] = '_'; + return 1; + } + + len = nls->uni2char(*src, buf, buf_size); + if (len <= 0) { + info->valid = 0; + buf[0] = '_'; + len = 1; + } else if (len == 1) { + unsigned char prev = buf[0]; + + if (buf[0] >= 0x7F) { + info->lower = 0; + info->upper = 0; + } + + buf[0] = vfat_toupper(nls, buf[0]); + if (isalpha(buf[0])) { + if (buf[0] == prev) + info->lower = 0; + else + info->upper = 0; } - if (space) return -EINVAL; - if (len) return -EINVAL; + } else { + info->lower = 0; + info->upper = 0; } - while (walk-res < MSDOS_NAME) *walk++ = ' '; - - return 0; + + return len; } -static char skip_chars[] = ".:\"?<>| "; - -/* Given a valid longname, create a unique shortname. Make sure the +/* + * Given a valid longname, create a unique shortname. Make sure the * shortname does not exist + * Returns negative number on error, 0 for a normal + * return, and 1 for valid shortname */ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, - wchar_t *name, int len, - char *name_res) + wchar_t *uname, int ulen, + char *name_res, unsigned char *lcase) { - wchar_t *ip, *op, *ext_start, *end, *name_start; - wchar_t msdos_name[13]; - char base[9], ext[4], buf[8], *p; + wchar_t *ip, *ext_start, *end, *name_start; + unsigned char base[9], ext[4], buf[8], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; - int sz, extlen, baselen, i; + int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; + int is_shortname; + struct shortname_info base_info, ext_info; + unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname; + + is_shortname = 1; + INIT_SHORTNAME_INFO(&base_info); + INIT_SHORTNAME_INFO(&ext_info); - PRINTK2(("Entering vfat_create_shortname\n")); - chl = 0; - sz = 0; /* Make compiler happy */ - if (len <= 12) { - /* Do a case insensitive search if the name would be a valid - * shortname if is were all capitalized. However, do not - * allow spaces in short names because Win95 scandisk does - * not like that */ - for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) { - if (i == len) { - if (vfat_format_name(nls, &msdos_name[0], len, - name_res) < 0) - break; - PRINTK3(("vfat_create_shortname 1\n")); - if (vfat_find_form(dir, name_res) < 0) - return 0; - return -EEXIST; - } - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == ' ') - break; - } - if (chi < chl) - break; - - *op = *ip; - } - } - - PRINTK3(("vfat_create_shortname 3\n")); /* Now, we need to create a shortname from the long name */ - ext_start = end = &name[len]; - while (--ext_start >= name) { - chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++) { - if (charbuf[chi] == '.') { - if (ext_start == end - 1) { - sz = len; - ext_start = NULL; - } - goto stop0; + ext_start = end = &uname[ulen]; + while (--ext_start >= uname) { + if (*ext_start == 0x002E) { /* is `.' */ + if (ext_start == end - 1) { + sz = ulen; + ext_start = NULL; } + break; } } -stop0:; - if (ext_start == name - 1) { - sz = len; + + if (ext_start == uname - 1) { + sz = ulen; ext_start = NULL; } else if (ext_start) { /* @@ -631,45 +552,43 @@ * an extension eg. "...test". In this case Win95 * uses the extension as the name and sets no extension. */ - name_start = &name[0]; - while (name_start < ext_start) - { - chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) + name_start = &uname[0]; + while (name_start < ext_start) { + if (!IS_SKIPCHAR(*name_start)) break; - for (chi = 0; chi < chl; chi++) - if (!strchr(skip_chars, charbuf[chi])) { - goto stop1; - } name_start++; } -stop1:; if (name_start != ext_start) { - sz = ext_start - name; + sz = ext_start - uname; ext_start++; } else { - sz = len; + sz = ulen; ext_start=NULL; } } - for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++) - { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0){ - *p++ = '_'; - baselen++; + numtail_baselen = 6; + numtail2_baselen = 2; + for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) { + chl = to_shortname_char(nls, charbuf, sizeof(charbuf), + ip, &base_info); + if (chl == 0) continue; - } + if (baselen < 2 && (baselen + chl) > 2) + numtail2_baselen = baselen; + if (baselen < 6 && (baselen + chl) > 6) + numtail_baselen = baselen; for (chi = 0; chi < chl; chi++){ - if (!strchr(skip_chars, charbuf[chi])){ - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; baselen++; - } + *p++ = charbuf[chi]; + baselen++; + if (baselen >= 8) + break; + } + if (baselen >= 8) { + if ((chi < chl - 1) || (ip + 1) - uname < sz) + is_shortname = 0; + break; } } if (baselen == 0) { @@ -679,21 +598,23 @@ extlen = 0; if (ext_start) { for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) { - *p++ = '_'; - extlen++; + chl = to_shortname_char(nls, charbuf, sizeof(charbuf), + ip, &ext_info); + if (chl == 0) continue; - } + if ((extlen + chl) > 3) { + is_shortname = 0; + break; + } for (chi = 0; chi < chl; chi++) { - if (!strchr(skip_chars, charbuf[chi])) { - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; extlen++; - } + *p++ = charbuf[chi]; + extlen++; + } + if (extlen >= 3) { + if (ip + 1 != end) + is_shortname = 0; + break; } } } @@ -701,8 +622,8 @@ base[baselen] = '\0'; /* Yes, it can happen. ".\xe5" would do it. */ - if (IS_FREE(base)) - base[0]='_'; + if (base[0] == DELETED_FLAG) + base[0] = 0x05; /* OK, at this point we know that base is not longer than 8 symbols, * ext is not longer than 3, base is nonempty, both don't contain @@ -710,8 +631,28 @@ */ memset(name_res, ' ', MSDOS_NAME); - memcpy(name_res,base,baselen); - memcpy(name_res+8,ext,extlen); + memcpy(name_res, base, baselen); + memcpy(name_res + 8, ext, extlen); + *lcase = 0; + if (is_shortname && base_info.valid && ext_info.valid) { + if (vfat_find_form(dir, name_res) == 0) + return -EEXIST; + + if (opt_shortname & VFAT_SFN_CREATE_WIN95) { + return (base_info.upper && ext_info.upper); + } else if (opt_shortname & VFAT_SFN_CREATE_WINNT) { + if ((base_info.upper || base_info.lower) + && (ext_info.upper || ext_info.lower)) { + *lcase = shortname_info_to_lcase(&base_info, + &ext_info); + return 1; + } + return 0; + } else { + BUG(); + } + } + if (MSDOS_SB(dir->i_sb)->options.numtail == 0) if (vfat_find_form(dir, name_res) < 0) return 0; @@ -724,8 +665,10 @@ * values for part of the base. */ - if (baselen>6) - baselen = 6; + if (baselen>6) { + baselen = numtail_baselen; + name_res[7] = ' '; + } name_res[baselen] = '~'; for (i = 1; i < 10; i++) { name_res[baselen+1] = i + '0'; @@ -735,8 +678,10 @@ i = jiffies & 0xffff; sz = (jiffies >> 16) & 0x7; - if (baselen>2) - baselen = 2; + if (baselen>2) { + baselen = numtail2_baselen; + name_res[7] = ' '; + } name_res[baselen+4] = '~'; name_res[baselen+5] = '1' + sz; while (1) { @@ -801,7 +746,6 @@ } else { if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0) return -EINVAL; - ip += charlen; i += charlen; op += 2; @@ -839,45 +783,50 @@ static int vfat_fill_slots(struct inode *dir, struct msdos_dir_slot *ds, const char *name, - int len, int *slots, int uni_xlate) + int len, int *slots, int is_dir, int uni_xlate) { struct nls_table *nls_io, *nls_disk; wchar_t *uname; struct msdos_dir_slot *ps; struct msdos_dir_entry *de; unsigned long page; - unsigned char cksum; - const char *ip; + unsigned char cksum, lcase; char *uniname, msdos_name[MSDOS_NAME]; int res, utf8, slot, ulen, unilen, i; loff_t offset; - de = (struct msdos_dir_entry *) ds; + *slots = 0; utf8 = MSDOS_SB(dir->i_sb)->options.utf8; nls_io = MSDOS_SB(dir->i_sb)->nls_io; nls_disk = MSDOS_SB(dir->i_sb)->nls_disk; - if (name[len-1] == '.') len--; + if (name[len-1] == '.') + len--; if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; - uniname = (char *) page; + uniname = (char *) page; res = xlate_to_uni(name, len, uniname, &ulen, &unilen, uni_xlate, - utf8, nls_io); + utf8, nls_io); if (res < 0) goto out_free; uname = (wchar_t *) page; - if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) { - res = vfat_format_name(nls_disk, uname, ulen, de->name); - if (!res) - goto out_free; - } + res = vfat_is_used_badchars(uname, ulen); + if (res < 0) + goto out_free; - res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name); - if (res) + res = vfat_create_shortname(dir, nls_disk, uname, ulen, + msdos_name, &lcase); + if (res < 0) goto out_free; + else if (res == 1) { + de = (struct msdos_dir_entry *)ds; + res = 0; + goto shortname; + } + /* build the entry of long file name */ *slots = unilen / 13; for (cksum = i = 0; i < 11; i++) { cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i]; @@ -890,18 +839,26 @@ ps->reserved = 0; ps->alias_checksum = cksum; ps->start = 0; - offset = (slot - 1) * 26; - ip = &uniname[offset]; - memcpy(ps->name0_4, ip, 10); - memcpy(ps->name5_10, ip+10, 12); - memcpy(ps->name11_12, ip+22, 4); + offset = (slot - 1) * 13; + fatwchar_to16(ps->name0_4, uname + offset, 5); + fatwchar_to16(ps->name5_10, uname + offset + 5, 6); + fatwchar_to16(ps->name11_12, uname + offset + 11, 2); } ds[0].id |= 0x40; - de = (struct msdos_dir_entry *) ps; + +shortname: PRINTK3(("vfat_fill_slots 9\n")); - strncpy(de->name, msdos_name, MSDOS_NAME); + /* build the entry of 8.3 alias name */ (*slots)++; + strncpy(de->name, msdos_name, MSDOS_NAME); + de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; + de->lcase = lcase; + de->adate = de->cdate = de->date = 0; + de->ctime_ms = de->ctime = de->time = 0; + de->start = 0; + de->starthi = 0; + de->size = 0; out_free: free_page(page); @@ -910,95 +867,92 @@ /* We can't get "." or ".." here - VFS takes care of those cases */ -static int vfat_build_slots(struct inode *dir,const char *name,int len, - struct msdos_dir_slot *ds, int *slots) +static int vfat_build_slots(struct inode *dir, const char *name, int len, + struct msdos_dir_slot *ds, int *slots, int is_dir) { int res, xlate; xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate; - *slots = 1; res = vfat_valid_longname(name, len, xlate); if (res < 0) return res; - return vfat_fill_slots(dir, ds, name, len, slots, xlate); + + return vfat_fill_slots(dir, ds, name, len, slots, is_dir, xlate); } static int vfat_add_entry(struct inode *dir,struct qstr* qname, - int is_dir,struct vfat_slot_info *sinfo_out, - struct buffer_head **bh, struct msdos_dir_entry **de) + int is_dir, struct vfat_slot_info *sinfo_out, + struct buffer_head **bh, struct msdos_dir_entry **de) { struct super_block *sb = dir->i_sb; - struct msdos_dir_slot *ps; + struct msdos_dir_slot *dir_slots; loff_t offset; - struct msdos_dir_slot *ds; int slots, slot; - int res; - struct msdos_dir_entry *de1; - struct buffer_head *bh1; - int ino; - int len; + int res, len; + struct msdos_dir_entry *dummy_de; + struct buffer_head *dummy_bh; + int dummy_ino; loff_t dummy; - ds = (struct msdos_dir_slot *) - kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL); - if (ds == NULL) return -ENOMEM; + dir_slots = (struct msdos_dir_slot *) + kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL); + if (dir_slots == NULL) + return -ENOMEM; len = qname->len; while (len && qname->name[len-1] == '.') len--; res = fat_search_long(dir, qname->name, len, - (MSDOS_SB(sb)->options.name_check != 's') || - !MSDOS_SB(sb)->options.posixfs, - &dummy, &dummy); + (MSDOS_SB(sb)->options.name_check != 's') + || !MSDOS_SB(sb)->options.posixfs, + &dummy, &dummy); if (res > 0) /* found */ res = -EEXIST; if (res) goto cleanup; - res = vfat_build_slots(dir, qname->name, len, ds, &slots); - if (res < 0) goto cleanup; + res = vfat_build_slots(dir, qname->name, len, + dir_slots, &slots, is_dir); + if (res < 0) + goto cleanup; - offset = fat_add_entries(dir, slots, &bh1, &de1, &ino); + /* build the empty directory entry of number of slots */ + offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino); if (offset < 0) { res = offset; goto cleanup; } - fat_brelse(sb, bh1); + fat_brelse(sb, dummy_bh); /* Now create the new entry */ *bh = NULL; - for (slot = 0, ps = ds; slot < slots; slot++, ps++) { - if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) { + for (slot = 0; slot < slots; slot++) { + if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) { res = -EIO; goto cleanup; } - memcpy(*de, ps, sizeof(struct msdos_dir_slot)); + memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot)); fat_mark_buffer_dirty(sb, *bh); } + res = 0; + /* update timestamp */ dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; mark_inode_dirty(dir); - fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date); - (*de)->ctime_ms = 0; + fat_date_unix2dos(dir->i_mtime, &(*de)->time, &(*de)->date); (*de)->ctime = (*de)->time; (*de)->adate = (*de)->cdate = (*de)->date; - (*de)->start = 0; - (*de)->starthi = 0; - (*de)->size = 0; - (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH; - (*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT; - fat_mark_buffer_dirty(sb, *bh); /* slots can't be less than 1 */ sinfo_out->long_slots = slots - 1; - sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots; - res = 0; + sinfo_out->longname_offset = + offset - sizeof(struct msdos_dir_slot) * slots; cleanup: - kfree(ds); + kfree(dir_slots); return res; } Index: vfatfs_syms.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/vfat/vfatfs_syms.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- vfatfs_syms.c 14 Jan 2001 16:28:32 -0000 1.1.1.1 +++ vfatfs_syms.c 9 Apr 2002 13:30:20 -0000 1.2 @@ -5,8 +5,6 @@ * These symbols are used by dmsdos. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> |