patch-2.4.13 linux/fs/vfat/namei.c

Next file: linux/fs/vfat/vfatfs_syms.c
Previous file: linux/fs/ufs/namei.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.12/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
@@ -9,13 +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@bszh.de>
+ *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
  *
  *  Support Multibyte character and cleanup by
  *  				OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -29,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
@@ -48,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);
@@ -117,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;
@@ -142,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) = ',';
@@ -157,167 +170,7 @@
 	}
 	return 1;
 }
-#if 0 /* not used functions */
-static inline unsigned char
-vfat_getlower(struct nls_table *t, unsigned char c)
-{
-	return t->charset2lower[c];
-}
-
-static inline unsigned char
-vfat_getupper(struct nls_table *t, unsigned char c)
-{
-	return t->charset2upper[c];
-}
-
-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 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_format_name(struct nls_table *nls, wchar_t *name,
-				int len, char *res)
-{
-	char *walk;
-	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
-	int chi, chl;
-	int space;
-
-	if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
-		return -EINVAL;
-
-	if (IS_FREE(charbuf))
-		return -EINVAL;
-
-	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];
-			}
-		}
-		if (space) return -EINVAL;
-		if (len) return -EINVAL;
-	}
-	while (walk-res < MSDOS_NAME) *walk++ = ' ';
-
-	return 0;
-}
-
-static inline int
-vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound)
-{
-	int chl;
-
-	if ( (chl = t->uni2char(uc, op, bound)) < 0)
-		chl = 0;
-
-	if (chl == 1)
-		op[0] = vfat_toupper(t, op[0]);
-
-	return chl;
-}
-#endif
 static inline unsigned char
 vfat_tolower(struct nls_table *t, unsigned char c)
 {
@@ -437,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("[");
@@ -510,8 +336,10 @@
 /* Characters that are undesirable in an MS-DOS file name */
 
 static wchar_t bad_chars[] = {
-	/*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/'     `\' */
-	0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, 0x005C, 0,
+	/*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/' */
+	0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F,
+	/*  `\' */
+	0x005C, 0,
 };
 #define IS_BADCHAR(uni)	(vfat_unistrchr(bad_chars, (uni)) != NULL)
 
@@ -521,6 +349,13 @@
 };
 #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)
@@ -582,47 +417,119 @@
 	return 0;
 }
 
-static wchar_t skip_chars[] = {
-	/*  `.'     ` ' */
-	0x002E, 0x0020, 0,
+/* 
+ * 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 IS_SKIPCHAR(uni) \
-	((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
+#define INIT_SHORTNAME_INFO(x)	do {		\
+	(x)->lower = 1;				\
+	(x)->upper = 1;				\
+	(x)->valid = 1;				\
+} while (0);
 
-/* Given a valid longname, create a unique shortname.  Make sure the
+static inline unsigned char
+shortname_info_to_lcase(struct shortname_info *base,
+			struct shortname_info *ext)
+{
+	unsigned char lcase = 0;
+
+	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;
+	}
+
+	return lcase;
+}
+
+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;
+		}
+	} else {
+		info->lower = 0;
+		info->upper = 0;
+	}
+	
+	return len;
+}
+
+/*
+ * 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 *uname, int ulen,
-				 char *name_res)
+				 char *name_res, unsigned char *lcase)
 {
 	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 = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
-	int is_uppercase, is_shortname;
+	int is_shortname;
+	struct shortname_info base_info, ext_info;
+	unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
 
-	/* 
-	 * 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.
-	 *     
-	 * 2) File name is 8.3 format, but it contain the lowercase
-	 * alphabet 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 .
-	 */
-	is_uppercase = 1;
 	is_shortname = 1;
+	INIT_SHORTNAME_INFO(&base_info);
+	INIT_SHORTNAME_INFO(&ext_info);
 
 	/* Now, we need to create a shortname from the long name */
 	ext_start = end = &uname[ulen];
@@ -662,31 +569,11 @@
 
 	numtail_baselen = 6;
 	numtail2_baselen = 2;
-	for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++)
-	{
-		if (IS_SKIPCHAR(*ip)) {
-			is_shortname = 0;
+	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 (IS_REPLACECHAR(*ip)) {
-			is_shortname = 0;
-			charbuf[0] = '_';
-			chl = 1;
-		} else {
-			chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
-			if (chl <= 0) {
-				is_shortname = 0;
-				charbuf[0]  = '_';
-				chl = 1;
-			} else if (chl == 1) {
-				unsigned char c = charbuf[0];
-				charbuf[0] = vfat_toupper(nls, charbuf[0]);
-				if (c >= 0x7F || charbuf[0] != c)
-					is_uppercase = 0;
-			} else {
-				is_uppercase = 0;
-			}
-		}
 
 		if (baselen < 2 && (baselen + chl) > 2)
 			numtail2_baselen = baselen;
@@ -711,30 +598,11 @@
 	extlen = 0;
 	if (ext_start) {
 		for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
-			if (IS_SKIPCHAR(*ip)) {
-				is_shortname = 0;
+			chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
+						ip, &ext_info);
+			if (chl == 0)
 				continue;
-			}
-			if (IS_REPLACECHAR(*ip)) {
-				is_shortname = 0;
-				charbuf[0] = '_';
-				chl = 1;
-			} else {
-				chl = nls->uni2char(*ip, charbuf, sizeof(charbuf));
-				if (chl <= 0) {
-					is_shortname = 0;
-					charbuf[0] = '_';
-					chl = 1;
-				} else if (chl == 1) {
-					unsigned char c = charbuf[0];
-					charbuf[0] = vfat_toupper(nls, charbuf[0]);
-					if (c >= 0x7F || charbuf[0] != c)
-						is_uppercase = 0;
-				} else {
-					is_uppercase = 0;
-				}
-			}
-				
+
 			if ((extlen + chl) > 3) {
 				is_shortname = 0;
 				break;
@@ -763,14 +631,26 @@
 	 */
 
 	memset(name_res, ' ', MSDOS_NAME);
-	memcpy(name_res,base,baselen);
-	memcpy(name_res+8,ext,extlen);
-
-	if (is_shortname) {
-		if (vfat_find_form(dir, name_res) < 0)
-			return is_uppercase;
-		else
+	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)
@@ -866,7 +746,6 @@
 				} else {
 					if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0)
 						return -EINVAL;
-
 					ip += charlen;
 					i += charlen;
 					op += 2;
@@ -904,31 +783,31 @@
 
 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;
 
@@ -937,15 +816,17 @@
 	if (res < 0)
 		goto out_free;
 
-	res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name);
+	res = vfat_create_shortname(dir, nls_disk, uname, ulen,
+				    msdos_name, &lcase);
 	if (res < 0)
 		goto out_free;
 	else if (res == 1) {
-		strncpy(de->name, msdos_name, MSDOS_NAME);
+		de = (struct msdos_dir_entry *)ds;
 		res = 0;
-		goto out_free;
+		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];
@@ -958,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);
@@ -978,96 +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);
+	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;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)