patch-2.1.80 linux/fs/vfat/namei.c
Next file: linux/include/asm-alpha/processor.h
Previous file: linux/fs/proc/root.c
Back to the patch index
Back to the overall index
- Lines: 337
- Date:
Tue Jan 13 20:07:28 1998
- Orig file:
v2.1.79/linux/fs/vfat/namei.c
- Orig date:
Fri Jan 2 14:37:02 1998
diff -u --recursive --new-file v2.1.79/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
@@ -57,6 +57,38 @@
static int vfat_valid_shortname(const char *,int, int, int);
static int vfat_format_name(const char *, int, char *, int, int);
static int vfat_valid_longname(const char *, int, int, int);
+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);
+static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int vfat_revalidate(struct dentry *dentry);
+
+static struct dentry_operations vfat_dentry_ops[4] = {
+ {
+ NULL, /* d_revalidate */
+ vfat_hashi,
+ vfat_cmpi,
+ NULL /* d_delete */
+ },
+ {
+ vfat_revalidate,
+ vfat_hashi,
+ vfat_cmpi,
+ NULL /* d_delete */
+ },
+ {
+ NULL, /* d_revalidate */
+ vfat_hash,
+ vfat_cmp,
+ NULL /* d_delete */
+ },
+ {
+ vfat_revalidate,
+ vfat_hash,
+ vfat_cmp,
+ NULL /* d_delete */
+ }
+};
static int strnicmp(const char *s1, const char *s2, int len)
{
@@ -80,6 +112,13 @@
MOD_DEC_USE_COUNT;
}
+static int vfat_revalidate(struct dentry *dentry)
+{
+ if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
+ return 1;
+ }
+ return 0;
+}
static struct super_operations vfat_sops = {
vfat_read_inode,
@@ -168,6 +207,27 @@
{
const char *name;
int len;
+
+ len = qstr->len;
+ name = qstr->name;
+ while (len && name[len-1] == '.')
+ len--;
+
+ qstr->hash = full_name_hash(name, len);
+
+ return 0;
+}
+
+/*
+ * Compute the hash for the vfat name corresponding to the dentry.
+ * Note: if the name is invalid, we leave the hash code unchanged so
+ * that the existing dentry can be used. The vfat fs routines will
+ * return ENOENT or EINVAL as appropriate.
+ */
+static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
+{
+ const char *name;
+ int len;
char c;
unsigned long hash;
@@ -187,9 +247,9 @@
}
/*
- * Compare two vfat names.
+ * Case insensitive compare of two vfat names.
*/
-static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
+static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
int alen, blen;
@@ -200,18 +260,33 @@
alen--;
while (blen && b->name[blen-1] == '.')
blen--;
- if (alen != blen)
- return 1;
-
- return strnicmp(a->name, b->name, alen);
+ if (alen == blen) {
+ if (strnicmp(a->name, b->name, alen) == 0)
+ return 0;
+ }
+ return 1;
}
-static struct dentry_operations vfat_dentry_operations = {
- NULL, /* d_revalidate */
- vfat_hash,
- vfat_cmp,
- NULL /* d_delete */
-};
+/*
+ * Case sensitive compare of two vfat names.
+ */
+static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+ int alen, blen;
+
+ /* A filename cannot end in '.' or we treat it like it has none */
+ alen = a->len;
+ blen = b->len;
+ while (alen && a->name[alen-1] == '.')
+ alen--;
+ while (blen && b->name[blen-1] == '.')
+ blen--;
+ if (alen == blen) {
+ if (strncmp(a->name, b->name, alen) == 0)
+ return 0;
+ }
+ return 1;
+}
struct super_block *vfat_read_super(struct super_block *sb,void *data,
int silent)
@@ -235,7 +310,9 @@
} else {
MSDOS_SB(sb)->options.dotsOK = 0;
if (MSDOS_SB(sb)->options.name_check != 's') {
- sb->s_root->d_op = &vfat_dentry_operations;
+ sb->s_root->d_op = &vfat_dentry_ops[0];
+ } else {
+ sb->s_root->d_op = &vfat_dentry_ops[2];
}
}
@@ -321,7 +398,7 @@
static int vfat_find(struct inode *dir,struct qstr* name,
int find_long,int new_filename,int is_dir,
- struct slot_info *sinfo_out);
+ struct vfat_slot_info *sinfo_out);
/* Checks the validity of a long MS-DOS filename */
/* Returns negative number on error, 0 for a normal
@@ -519,7 +596,7 @@
int res;
int spaces;
char buf[8];
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
const char *name_start;
struct qstr qname;
@@ -778,7 +855,6 @@
len--;
op = outname;
if (nls) {
- /* XXX: i is incorrectly computed. */
for (i = 0, ip = name, op = outname, *outlen = 0;
i < len && *outlen <= 260; i++, *outlen += 1)
{
@@ -992,7 +1068,7 @@
}
static int vfat_find(struct inode *dir,struct qstr* qname,
- int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
+ int find_long, int new_filename,int is_dir,struct vfat_slot_info *sinfo_out)
{
struct super_block *sb = dir->i_sb;
struct vfat_find_info vf;
@@ -1118,37 +1194,36 @@
int vfat_lookup(struct inode *dir,struct dentry *dentry)
{
int res;
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
struct inode *result;
+ int table;
PRINTK (("vfat_lookup: name=%s, len=%d\n",
dentry->d_name.name, dentry->d_name.len));
- if (MSDOS_SB(dir->i_sb)->options.name_check != 's') {
- dentry->d_op = &vfat_dentry_operations;
- }
+ table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
+ dentry->d_op = &vfat_dentry_ops[table];
result = NULL;
if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) {
- d_add(dentry,NULL);
- return 0;
+ result = NULL;
+ table++;
+ goto error;
}
PRINTK (("vfat_lookup 4.5\n"));
if (!(result = iget(dir->i_sb,sinfo.ino)))
return -EACCES;
PRINTK (("vfat_lookup 5\n"));
- if (!result->i_sb ||
- (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
- /* crossed a mount point into a non-msdos fs */
- d_add(dentry,NULL);
- return 0;
- }
if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
iput(result);
- d_add(dentry,NULL);
- return 0;
+ result = NULL;
+ table++;
+ goto error;
}
PRINTK (("vfat_lookup 6\n"));
+error:
+ dentry->d_op = &vfat_dentry_ops[table];
+ dentry->d_time = dentry->d_parent->d_inode->i_version;
d_add(dentry,result);
return 0;
}
@@ -1162,7 +1237,7 @@
loff_t offset;
struct buffer_head *bh;
struct msdos_dir_entry *de;
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
*result=0;
PRINTK(("vfat_create_entry 1\n"));
@@ -1210,6 +1285,7 @@
if (res < 0) {
PRINTK(("vfat_create: unable to get new entry\n"));
} else {
+ dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry,result);
}
return res;
@@ -1388,7 +1464,7 @@
return 0;
}
-static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
+static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
struct buffer_head **bh,struct dentry* dentry,
int is_dir,int nospc)
{
@@ -1422,13 +1498,31 @@
return 0;
}
+static void vfat_delete_dentries(struct dentry *dentry)
+{
+ struct list_head *head, *next, *tmp;
+ struct dentry *alias;
+
+ head = &dentry->d_inode->i_dentry;
+ if (dentry->d_inode) {
+ next = dentry->d_inode->i_dentry.next;
+ while (next != head) {
+ tmp = next;
+ next = tmp->next;
+ alias = list_entry(tmp, struct dentry, d_alias);
+ d_delete(alias);
+ }
+ } else {
+ d_delete(dentry);
+ }
+}
static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
@@ -1450,7 +1544,7 @@
int res;
res = vfat_rmdirx(dir, dentry);
if (res >= 0) {
- d_delete(dentry);
+ vfat_delete_dentries(dentry);
}
return res;
}
@@ -1463,7 +1557,7 @@
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
bh = NULL;
res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
@@ -1498,6 +1592,7 @@
res = vfat_create_dotdirs(inode, dir);
fat_unlock_creation();
MSDOS_I(inode)->i_busy = 0;
+ dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry,inode);
if (res < 0) {
if (vfat_rmdir(dir,dentry) < 0)
@@ -1513,7 +1608,7 @@
res = vfat_unlinkx (dir,dentry,1);
if (res >= 0) {
- d_delete(dentry);
+ vfat_delete_dentries(dentry);
}
return res;
}
@@ -1540,7 +1635,7 @@
struct dentry *walk;
int res, is_dir, i;
int locked = 0;
- struct slot_info sinfo;
+ struct vfat_slot_info sinfo;
PRINTK(("vfat_rename 1\n"));
if (old_dir == new_dir &&
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov