|
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>
|