patch-1.3.72 linux/fs/vfat/namei.c
Next file: linux/include/asm-i386/irq.h
Previous file: linux/fs/nfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 969
- Date:
Tue Mar 5 13:03:27 1996
- Orig file:
v1.3.71/linux/fs/vfat/namei.c
- Orig date:
Fri Feb 16 11:34:10 1996
diff -u --recursive --new-file v1.3.71/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
@@ -4,7 +4,10 @@
* Written 1992,1993 by Werner Almesberger
*
* Windows95/Windows NT compatible extended MSDOS filesystem
- * by Gordon Chaffee Copyright (C) 1995
+ * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
+ * VFAT filesystem to <chaffee@plateau.cs.berkeley.edu>. Specify
+ * what file operation caused you trouble and if you can duplicate
+ * the problem, send a script that demonstrates it.
*/
#include <linux/module.h>
@@ -15,6 +18,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/mm.h>
#include <asm/segment.h>
@@ -22,14 +26,37 @@
#include "../fat/tables.h"
#if 0
-#define PRINTK(x) printk x
+# define PRINTK(x) printk x
#else
-#define PRINTK(x)
+# define PRINTK(x)
#endif
+#ifndef DEBUG
+# define CHECK_STACK
+#else
+# define CHECK_STACK check_stack(__FILE__, __LINE__)
+#endif
-void vfat_read_inode(struct inode *inode);
+/*
+ * XXX: It would be better to use the tolower from linux/ctype.h,
+ * but _ctype is needed and it is not exported.
+ */
+#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
+struct vfat_find_info {
+ const char *name;
+ int len;
+ int new_filename;
+ int found;
+ int is_long;
+ off_t offset;
+ off_t short_offset;
+ int long_slots;
+ ino_t ino;
+ int posix;
+};
+
+void vfat_read_inode(struct inode *inode);
void vfat_put_super(struct super_block *sb)
{
@@ -49,29 +76,93 @@
NULL
};
+static int parse_options(char *options, char *uni_xlate, char *posix,
+ char *numtail)
+{
+ char *this_char,*value;
+
+ *uni_xlate = *posix = 0;
+ *numtail = 1;
+
+ if (!options) return 1;
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"uni_xlate")) {
+ if (value)
+ return 0;
+ *uni_xlate = 1;
+ }
+ else if (!strcmp(this_char,"posix")) {
+ if (value)
+ return 0;
+ *posix = 1;
+ }
+ else if (!strcmp(this_char,"nonumtail")) {
+ if (value)
+ return 0;
+ *numtail = 0;
+ }
+ }
+ return 1;
+}
+
struct super_block *vfat_read_super(struct super_block *sb,void *data,
int silent)
{
struct super_block *res;
+ char uni_xlate, posix, numtail;
MOD_INC_USE_COUNT;
sb->s_op = &vfat_sops;
+ if (!parse_options((char *) data,&uni_xlate,&posix,&numtail)) {
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ MSDOS_SB(sb)->unicode_xlate = uni_xlate;
+ MSDOS_SB(sb)->posix = posix;
+ MSDOS_SB(sb)->numtail = numtail;
+
res = fat_read_super(sb, data, silent);
if (res == NULL) {
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
} else {
- MSDOS_SB(sb)->vfat = 1;
- MSDOS_SB(sb)->dotsOK = 0;
+ MSDOS_SB(sb)->vfat = 1;
+ MSDOS_SB(sb)->dotsOK = 0;
}
return res;
}
+#ifdef DEBUG
+static void
+check_stack(const char *fname, int lineno)
+{
+ int stack_level;
+ char *pg_dir;
-#ifdef DEBUG
+ 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 (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
+ printk("******* vfat stack corruption detected in %s at line %d\n",
+ fname, lineno);
+ }
+}
+static int debug = 0;
static void dump_fat(struct super_block *sb,int start)
{
printk("[");
@@ -112,13 +203,8 @@
/* Characters that are undesirable in an MS-DOS file name */
-#if 1 /* Steve Searle's characters */
static char bad_chars[] = "*?<>|\":/\\";
static char bad_if_strict[] = "+=,; []";
-#else
-static char bad_chars[] = "*?<>|\"";
-static char bad_if_strict[] = "+=,; ";
-#endif
static char replace_chars[] = "[];,+=";
static int vfat_find(struct inode *dir,const char *name,int len,
@@ -129,7 +215,8 @@
/* Returns negative number on error, 0 for a normal
* return, and 1 for . or .. */
-static int vfat_valid_longname(const char *name, int len, int dot_dirs)
+static int vfat_valid_longname(const char *name, int len, int dot_dirs,
+ int xlate)
{
const char **reserved;
unsigned char c;
@@ -145,9 +232,12 @@
if (len >= 256) return -EINVAL;
for (i = 0; i < len; i++) {
c = name[i];
- if (strchr(bad_chars,c)) return -EINVAL;
+ if (xlate && c == ':') continue;
+ if (strchr(bad_chars,c)) {
+ return -EINVAL;
+ }
}
- if (len == 3 || len == 4) {
+ if (len == 3 || len == 4) {
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(name,*reserved,8)) return -EINVAL;
}
@@ -290,22 +380,18 @@
{
const char *ip, *ext_start, *end;
char *p;
- int valid;
int sz, extlen, baselen, totlen;
char msdos_name[13];
char base[9], ext[4];
int i;
int res;
- int ino;
int spaces;
- int count;
char buf[8];
struct slot_info sinfo;
const char *name_start;
PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
sz = 0; /* Make compiler happy */
- valid = 1;
if (len && name[len-1]==' ') return -EINVAL;
if (len <= 12) {
/* Do a case insensitive search if the name would be a valid
@@ -322,7 +408,6 @@
if (res > -1) {
PRINTK(("vfat_create_shortname 1\n"));
res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
- ino = sinfo.ino;
PRINTK(("vfat_create_shortname 2\n"));
if (res > -1) return -EEXIST;
return 0;
@@ -373,6 +458,7 @@
} else {
*p = *ip;
}
+ if (strchr(replace_chars, *p)) *p='_';
p++; baselen++;
}
ip++;
@@ -403,18 +489,21 @@
ext[extlen] = '\0';
base[baselen] = '\0';
- count = 0;
strcpy(msdos_name, base);
msdos_name[baselen] = '.';
strcpy(&msdos_name[baselen+1], ext);
totlen = baselen + extlen + 1;
res = 0;
+ if (MSDOS_SB(dir->i_sb)->numtail == 0) {
+ res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ }
+ i = 0;
while (res > -1) {
/* Create the next shortname to try */
- count++;
- if (count == 10000000) return -EEXIST;
- sprintf(buf, "%d", count);
+ i++;
+ if (i == 10000000) return -EEXIST;
+ sprintf(buf, "%d", i);
sz = strlen(buf);
if (sz + 1 > spaces) {
baselen = baselen - (sz + 1 - spaces);
@@ -427,7 +516,7 @@
msdos_name[baselen+sz+1] = '.';
strcpy(&msdos_name[baselen+sz+2], ext);
- totlen = baselen + sz + 2 + extlen;
+ totlen = baselen + sz + 1 + extlen + (extlen > 0);
res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
}
res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
@@ -483,39 +572,146 @@
if ((res = fat_add_cluster(dir)) < 0) return res;
ino = fat_get_entry(dir,&curr,&bh,&de);
}
- /* Should never get here, but if it does */
- printk("vfat_find_free_slots: Unable to find any\n");
return -ENOSPC;
}
-
-static int vfat_build_slots(struct inode *dir,const char *name,int len,
- int find_long, int new_filename,
- struct msdos_dir_slot *ds, struct msdos_dir_slot *ds_mask,
- int *slots, int *is_long)
+
+/* Translate a string, including coded sequences into Unicode */
+static int
+xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
{
- struct msdos_dir_slot *ps, *ps_mask;
- struct msdos_dir_entry *de, *de_mask;
- char msdos_name[MSDOS_NAME];
+ int i;
+ const unsigned char *ip;
+ char *op;
+ int fill;
+ unsigned char c1, c2, c3;
+
+ op = outname;
+ for (i = 0, ip = name, op = outname, *outlen = 0;
+ i < len && *outlen <= 260; i++, *outlen += 1)
+ {
+ if (escape && (i < len - 4) &&
+ (*ip == ':') &&
+ ((c1 = fat_code2uni[ip[1]]) != 255) &&
+ ((c2 = fat_code2uni[ip[2]]) != 255) &&
+ ((c3 = fat_code2uni[ip[3]]) != 255)) {
+ *op++ = (c1 << 4) + (c2 >> 2);
+ *op++ = ((c2 & 0x3) << 6) + c3;
+ ip += 4;
+ } else {
+ *op++ = fat_a2uni[*ip].uni1;
+ *op++ = fat_a2uni[*ip].uni2;
+ ip++;
+ }
+ }
+ if (*outlen > 260)
+ return -ENAMETOOLONG;
+
+ if (*outlen % 13) {
+ *op++ = 0;
+ *op++ = 0;
+ *outlen += 1;
+ if (*outlen % 13) {
+ fill = 13 - (*outlen % 13);
+ for (i = 0; i < fill; i++) {
+ *op++ = 0xff;
+ *op++ = 0xff;
+ }
+ *outlen += fill;
+ }
+ }
+
+ return 0;
+}
+
+static int
+vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
+ char *msdos_name, int *slots, int uni_xlate)
+{
+ struct msdos_dir_slot *ps;
+ struct msdos_dir_entry *de;
int res;
int slot;
+ unsigned char cksum;
+ char *uniname;
+ const char *ip;
+ unsigned long page;
+ int unilen;
int i;
- const unsigned char *ip;
loff_t offset;
- unsigned char alias_checksum;
+
+ if(!(page = __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ uniname = (char *) page;
+ res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate);
+ if (res < 0) {
+ free_page(page);
+ return res;
+ }
+
+ *slots = unilen / 13;
+ for (cksum = i = 0; i < 11; i++) {
+ cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
+ }
+ PRINTK(("vfat_fill_long_slots 3: slots=%d\n",*slots));
+
+ for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
+ int end, j;
+
+ PRINTK(("vfat_fill_long_slots 4\n"));
+ ps->id = slot;
+ ps->attr = ATTR_EXT;
+ ps->reserved = 0;
+ ps->alias_checksum = cksum;
+ ps->start[0] = 0;
+ ps->start[1] = 0;
+ PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
+ offset = (slot - 1) * 26;
+ ip = &uniname[offset];
+ j = offset;
+ end = 0;
+ for (i = 0; i < 10; i += 2) {
+ ps->name0_4[i] = *ip++;
+ ps->name0_4[i+1] = *ip++;
+ }
+ PRINTK(("vfat_fill_long_slots 6\n"));
+ for (i = 0; i < 12; i += 2) {
+ ps->name5_10[i] = *ip++;
+ ps->name5_10[i+1] = *ip++;
+ }
+ PRINTK(("vfat_fill_long_slots 7\n"));
+ for (i = 0; i < 4; i += 2) {
+ ps->name11_12[i] = *ip++;
+ ps->name11_12[i+1] = *ip++;
+ }
+ }
+ PRINTK(("vfat_fill_long_slots 8\n"));
+ ds[0].id |= 0x40;
+
+ de = (struct msdos_dir_entry *) ps;
+ PRINTK(("vfat_fill_long_slots 9\n"));
+ strncpy(de->name, msdos_name, MSDOS_NAME);
+
+ free_page(page);
+ return 0;
+}
+
+static int vfat_build_slots(struct inode *dir,const char *name,int len,
+ struct msdos_dir_slot *ds, int *slots, int *is_long)
+{
+ struct msdos_dir_entry *de;
+ char msdos_name[MSDOS_NAME];
+ int res, xlate;
PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
de = (struct msdos_dir_entry *) ds;
- de_mask = (struct msdos_dir_entry *) ds_mask;
+ xlate = MSDOS_SB(dir->i_sb)->unicode_xlate;
*slots = 1;
*is_long = 0;
- memset(ds_mask, 0, sizeof(struct msdos_dir_slot) * MSDOS_SLOTS);
if (len == 1 && name[0] == '.') {
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
- memset(de_mask, 0xff, MSDOS_NAME);
} else if (len == 2 && name[0] == '.' && name[1] == '.') {
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
- memset(de_mask, 0xff, MSDOS_NAME);
} else {
PRINTK(("vfat_build_slots 4\n"));
res = vfat_valid_shortname('x', name, len, 1);
@@ -523,327 +719,120 @@
PRINTK(("vfat_build_slots 5a\n"));
res = vfat_format_name('x', name, len, de->name, 1);
PRINTK(("vfat_build_slots 5b\n"));
- memset(de_mask->name, 0xff, MSDOS_NAME);
- PRINTK(("vfat_build_slots 5c\n"));
} else {
- PRINTK(("vfat_build_slots 5A: %s (len=%d) is an invalid shortname\n", name, len));
- if (new_filename) {
- unsigned char sum;
-
- PRINTK(("vfat_build_slots 5Z\n"));
- res = vfat_create_shortname(dir, name, len, msdos_name);
- PRINTK(("vfat_build_slots 5Y\n"));
- if (res < 0) {
- return res;
- }
-
- for (sum = i = 0; i < 11; i++) {
- sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + msdos_name[i];
- }
- PRINTK(("vfat_build_slots 5X: msdos_name=%s\n", msdos_name));
- alias_checksum = sum;
- } else {
- alias_checksum = 0;
+ res = vfat_create_shortname(dir, name, len, msdos_name);
+ if (res < 0) {
+ return res;
}
- if (!find_long) return -EINVAL;
- res = vfat_valid_longname(name, len, 1);
- if (res < 0) return res;
+ res = vfat_valid_longname(name, len, 1, xlate);
+ if (res < 0) {
+ return res;
+ }
*is_long = 1;
- *slots = (len + 12) / 13;
- PRINTK(("vfat_build_slots 6: slots=%d\n",*slots));
-
- for (ps = ds, slot = *slots, ps_mask = ds_mask;
- slot > 0; slot--, ps++, ps_mask++)
- {
- int end, j;
-
- PRINTK(("vfat_build_slots 6a\n"));
- ps->id = slot; ps_mask->id = 0xff;
- ps->attr = ATTR_EXT; ps_mask->attr = 0xff;
- ps->reserved = 0; ps_mask->reserved = 0xff;
- ps->alias_checksum = alias_checksum;
- ps_mask->alias_checksum = 0;
- ps->start[0] = 0; ps_mask->start[0] = 0xff;
- ps->start[1] = 0; ps_mask->start[1] = 0xff;
- PRINTK(("vfat_build_slots 6b: name=%s\n",name));
- offset = (slot - 1) * 13;
- ip = &name[offset];
- j = offset;
- end = 0;
- for (i = 0; i < 10; i += 2) {
- if (!end && j == len) {
- end = 1;
- ps->name0_4[i] = 0;
- ps_mask->name0_4[i] = 0xff;
- ps->name0_4[i+1] = 0;
- ps_mask->name0_4[i] = 0xff;
- continue;
- } else if (end) {
- ps->name0_4[i] = 0xff;
- ps_mask->name0_4[i] = 0xff;
- ps->name0_4[i+1] = 0xff;
- ps_mask->name0_4[i+1] = 0xff;
- continue;
- }
- ps->name0_4[i] = fat_a2uni[*ip].uni1;
- ps->name0_4[i+1] = fat_a2uni[*ip].uni2;
- if ((*ip >= 'a' && *ip <= 'z') ||
- (*ip >= 'A' && *ip <= 'Z')) {
- ps_mask->name0_4[i] = 0xdf;
- } else {
- ps_mask->name0_4[i] = 0xff;
- }
- ps_mask->name0_4[i+1] = 0xff;
- j++; ip++;
- }
- PRINTK(("vfat_build_slots 6c\n"));
- for (i = 0; i < 12; i += 2) {
- if (!end && j == len) {
- end = 1;
- ps->name5_10[i] = 0;
- ps->name5_10[i+1] = 0;
- continue;
- } else if (end) {
- ps->name5_10[i] = 0xff;
- ps_mask->name5_10[i] = 0xff;
- ps->name5_10[i+1] = 0xff;
- ps_mask->name5_10[i+1] = 0xff;
- continue;
- }
- ps->name5_10[i] = fat_a2uni[*ip].uni1;
- ps->name5_10[i+1] = fat_a2uni[*ip].uni2;
- if ((*ip >= 'a' && *ip <= 'z') ||
- (*ip >= 'A' && *ip <= 'Z')) {
- ps_mask->name5_10[i] = 0xdf;
- } else {
- ps_mask->name5_10[i] = 0xff;
- }
- ps_mask->name5_10[i+1] = 0xff;
- j++; ip++;
- }
- PRINTK(("vfat_build_slots 6d\n"));
- for (i = 0; i < 4; i += 2) {
- if (!end && j == len) {
- end = 1;
- ps->name11_12[i] = 0;
- ps->name11_12[i+1] = 0;
- continue;
- } else if (end) {
- ps->name11_12[i] = 0xff;
- ps_mask->name11_12[i] = 0xff;
- ps->name11_12[i+1] = 0xff;
- ps_mask->name11_12[i+1] = 0xff;
- continue;
- }
- ps->name11_12[i] = fat_a2uni[*ip].uni1;
- ps->name11_12[i+1] = fat_a2uni[*ip].uni2;
- if ((*ip >= 'a' && *ip <= 'z') ||
- (*ip >= 'A' && *ip <= 'Z')) {
- ps_mask->name11_12[i] = 0xdf;
- } else {
- ps_mask->name11_12[i] = 0xff;
- }
- ps_mask->name11_12[i+1] = 0xff;
- j++; ip++;
- }
- }
- PRINTK(("vfat_build_slots 6e\n"));
- ds[0].id |= 0x40;
- if (new_filename) {
- de = (struct msdos_dir_entry *) ps;
- de_mask = (struct msdos_dir_entry *) ps_mask;
-
- PRINTK(("vfat_build_slots 10\n"));
- strncpy(de->name, msdos_name, MSDOS_NAME);
- memset(de_mask->name, 0xff, MSDOS_NAME);
- }
+ return vfat_fill_long_slots(ds, name, len, msdos_name,
+ slots, xlate);
}
}
return 0;
}
-/* Given a shortname offset, see if there is an associated longname. Returns
- * the number of slots in the longname if one is found, else 0 */
-static int vfat_get_longname(struct inode *dir,loff_t short_offset,
- unsigned char checksum, loff_t *pos_out)
+static int vfat_readdir_cb(
+ filldir_t filldir,
+ void * buf,
+ const char * name,
+ int name_len,
+ int is_long,
+ off_t offset,
+ off_t short_offset,
+ int long_slots,
+ ino_t ino)
{
- struct super_block *sb = dir->i_sb;
- struct msdos_dir_slot *ps;
- struct msdos_dir_entry *de;
- struct buffer_head *bh;
- loff_t offset, temp;
- int id, res, slots;
+ struct vfat_find_info *vf = (struct vfat_find_info *) buf;
+ const char *s1, *s2;
+ int i;
+
+#ifdef DEBUG
+ if (debug) printk("cb: vf.name=%s, len=%d, name=%s, name_len=%d\n",
+ vf->name, vf->len, name, name_len);
+#endif
- /* printk("Short offset: %d\n", short_offset); */
- if (short_offset == 0) {
+ if (vf->len != name_len) {
return 0;
}
- slots = 0;
- id = 1;
- bh = NULL;
- offset = short_offset - sizeof(struct msdos_dir_slot);
- while (offset > 0) {
- temp = offset;
- res = fat_get_entry(dir,&temp,&bh,&de);
- if (res < 0) goto finish;
- ps = (struct msdos_dir_slot *) de;
- if (ps->alias_checksum != checksum) goto finish;
- if ((ps->id &~ 0x40) != id) goto finish;
- if (IS_FREE(de->name)) goto finish;
- if (ps->id & 0x40) {
- *pos_out = offset;
- slots = ps->id &~ 0x40;
- /* printk("Found a longname for the shortname: long_offset=%ld\n", offset); */
- goto finish;
- }
- offset -= sizeof(struct msdos_dir_slot);
- id++;
- }
- finish:
- if (bh) brelse(bh);
- return slots;
+ s1 = name; s2 = vf->name;
+ for (i = 0; i < name_len; i++) {
+ if (vf->new_filename && !vf->posix) {
+ if (tolower(*s1) != tolower(*s2))
+ return 0;
+ } else {
+ if (*s1 != *s2)
+ return 0;
+ }
+ s1++; s2++;
+ }
+ vf->found = 1;
+ vf->is_long = is_long;
+ vf->offset = (offset == 2) ? 0 : offset;
+ vf->short_offset = (short_offset == 2) ? 0 : short_offset;
+ vf->long_slots = long_slots;
+ vf->ino = ino;
+ return -1;
}
static int vfat_find(struct inode *dir,const char *name,int len,
int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
{
struct super_block *sb = dir->i_sb;
- const char *ip;
- char *op, *op_mask;
- int res;
- struct msdos_dir_slot ds[MSDOS_SLOTS], ds_mask[MSDOS_SLOTS];
- struct msdos_dir_slot *ps;
- struct msdos_dir_entry *de, *de_mask;
+ struct vfat_find_info vf;
+ struct file fil;
struct buffer_head *bh;
- int i, slot, slots;
- loff_t offset, start;
- int match;
+ struct msdos_dir_entry *de;
+ struct msdos_dir_slot *ps;
+ loff_t offset;
+ struct msdos_dir_slot ds[MSDOS_SLOTS];
int is_long;
- unsigned char alias_checksum = 0;
+ int slots, slot;
+ int res;
- PRINTK(("vfat_find 1: name=%s, len=%d\n",name,len));
+ PRINTK(("Entering vfat_find\n"));
+ fil.f_pos = 0;
+ vf.name = name;
+ vf.len = len;
+ vf.new_filename = new_filename;
+ vf.found = 0;
+ vf.posix = MSDOS_SB(sb)->posix;
+ res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
+ PRINTK(("vfat_find: Debug 1\n"));
+ if (res < 0) return res;
+ if (vf.found) {
+ if (new_filename) {
+ return -EEXIST;
+ }
+ sinfo_out->longname_offset = vf.offset;
+ sinfo_out->shortname_offset = vf.short_offset;
+ sinfo_out->is_long = vf.is_long;
+ sinfo_out->long_slots = vf.long_slots;
+ sinfo_out->total_slots = vf.long_slots + 1;
+ sinfo_out->ino = vf.ino;
- res = vfat_build_slots(dir, name, len, find_long, new_filename,
- ds, ds_mask, &slots, &is_long);
+ PRINTK(("vfat_find: Debug 2\n"));
+ return 0;
+ }
+
+ PRINTK(("vfat_find: Debug 3\n"));
+ if (!vf.found && !new_filename)
+ return -ENOENT;
+
+ res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
if (res < 0) return res;
de = (struct msdos_dir_entry *) ds;
- de_mask = (struct msdos_dir_entry *) ds_mask;
- PRINTK(("vfat_find 7\n"));
- offset = start = 0;
bh = NULL;
- sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
- while (sinfo_out->ino > -1 && slots > 0) {
- match = 1;
-
- ps = (struct msdos_dir_slot *) de;
- alias_checksum = ps->alias_checksum;
-
- for (slot = 0; slot < slots; slot++) {
- ip = (char *) de;
- ps = (struct msdos_dir_slot *) de;
- if (is_long && ps->alias_checksum != alias_checksum) {
- printk("Checksums don't match 1\n");
- match = 0;
- start = offset;
- break;
- }
-
- for (i = 0, ip = (char *) de, op = (char *) &ds[slot], op_mask = (char *) &ds_mask[slot];
- i < sizeof(struct msdos_dir_entry);
- i++, ip++, op++, op_mask++)
- {
-#if 0
- if (is_long && de->attr == ATTR_EXT)
- printk("%02x?%02x ",
- (unsigned char) *ip,
- (unsigned char) *op);
-#endif
- if ((*ip & *op_mask) != (*op & *op_mask)) {
- start = offset;
- match = 0;
- break;
- }
- }
-#if 0
- if (is_long && de->attr == ATTR_EXT) printk("\n");
-#endif
- if ((!is_long && !match) ||
- (de->attr == ATTR_VOLUME) ||
- (is_long && (match || slot == 0)))
- {
- sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
- /* if (ino >=0 && de->attr == ATTR_EXT) dump_de(de); */
- }
- if (!match) {
- break;
- }
- if (sinfo_out->ino == -1) {
- match = 0;
- goto breakout;
- }
- }
- if (match) {
- unsigned char sum;
-
- for (sum = i = 0; i < 11; i++) {
- sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
- }
-
- if (is_long) {
- if (sum != alias_checksum) {
- PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
- match = 0;
- }
- } else {
- int long_slots;
- long_slots = vfat_get_longname(dir, offset - sizeof(struct msdos_dir_entry), sum, &start);
- if (long_slots > 0) {
- slots = long_slots;
- is_long = 1;
- }
- }
-
-
- if (match) {
- PRINTK(("name: %s, alias: %c%c%c%c%c%c%c%c%c%c%c\n",
- name,
- de->name[0], de->name[1], de->name[2],
- de->name[3], de->name[4], de->name[5],
- de->name[6], de->name[7], de->name[8],
- de->name[9], de->name[10]));
- PRINTK(("vfat_find 10\n"));
- res = CF_LE_W(de->start);
-
- sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
- sinfo_out->longname_offset = start;
- sinfo_out->is_long = is_long;
- if (is_long) {
- sinfo_out->long_slots = slots;
- slots++;
- } else {
- sinfo_out->long_slots = 0;
- }
-
- sinfo_out->total_slots = slots;
- if (new_filename) {
- if (bh) brelse(bh);
- return -EEXIST;
- }
- if (bh) brelse(bh);
- return res;
- }
- }
- }
- breakout:
- PRINTK(("breakout\n"));
-
- if (bh) brelse(bh);
if (new_filename) {
PRINTK(("vfat_find: create file 1\n"));
if (is_long) slots++;
@@ -928,6 +917,12 @@
if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
+ if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) {
+ iput(dir);
+ if (!(*result = iget(dir->i_sb, ino)))
+ return -EACCES;
+ return 0;
+ }
PRINTK (("vfat_lookup 3\n"));
if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
iput(dir);
@@ -1000,6 +995,9 @@
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
CURRENT_TIME;
(*result)->i_dirt = 1;
+ (*result)->i_version = ++event;
+ dir->i_version = event;
+ dcache_add(dir, name, len, ino);
return 0;
}
@@ -1012,12 +1010,8 @@
if (!dir) return -ENOENT;
fat_lock_creation();
- if ((res = vfat_create_entry(dir,name,len,0,result)) < 0) {
- printk("vfat_create: unable to get new entry\n");
- fat_unlock_creation();
- iput(dir);
- return res;
- }
+ res = vfat_create_entry(dir,name,len,0,result);
+ if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
fat_unlock_creation();
iput(dir);
@@ -1121,7 +1115,7 @@
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
- while (fat_get_entry(dir,&pos,&bh,&de) > -1)
+ while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
/* Skip extended filename entries */
if (de->attr == ATTR_EXT) continue;
@@ -1131,6 +1125,7 @@
brelse(bh);
return -ENOTEMPTY;
}
+ }
if (bh)
brelse(bh);
}
@@ -1177,17 +1172,14 @@
struct super_block *sb = dir->i_sb;
struct inode *inode;
if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
- if (!S_ISREG(inode->i_mode) && nospc) {
- iput(inode);
- return -EPERM;
- }
- if (IS_IMMUTABLE(inode)){
+ if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) {
iput(inode);
return -EPERM;
}
inode->i_nlink = 0;
inode->i_mtime = dir->i_mtime = CURRENT_TIME;
inode->i_atime = dir->i_atime = CURRENT_TIME;
+ dir->i_version = ++event;
MSDOS_I(inode)->i_busy = 1;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
@@ -1254,6 +1246,7 @@
} else {
printk("Problem in vfat_rmdirx\n");
}
+ dir->i_version = ++event;
rmdir_done:
brelse(bh);
@@ -1385,9 +1378,18 @@
while (walk->i_ino != MSDOS_ROOT_INO) {
ino = fat_parent_ino(walk,1);
iput(walk);
- if (ino < 0) return ino;
- if (ino == old_ino) return -EINVAL;
- if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
+ if (ino < 0) {
+ res = ino;
+ goto rename_done;
+ }
+ if (ino == old_ino) {
+ res = -EINVAL;
+ goto rename_done;
+ }
+ if (!(walk = iget(new_dir->i_sb,ino))) {
+ res = -EIO;
+ goto rename_done;
+ }
}
iput(walk);
}
@@ -1458,6 +1460,7 @@
fat_cache_inval_inode(old_inode);
PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
old_inode->i_dirt = 1;
+ old_dir->i_version = ++event;
/* remove the old entry */
for (i = old_slots; i > 0; --i) {
@@ -1473,7 +1476,9 @@
PRINTK(("vfat_rename 15b\n"));
mark_buffer_dirty(new_bh, 1);
+ dcache_add(new_dir, new_name, new_len, new_ino);
iput(new_inode);
+
/* XXX: There is some code in the original MSDOS rename that
* is not duplicated here and it might cause a problem in
* certain circumstances.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this