2 * linux/fs/msdos/namei.c
4 * Written 1992,1993 by Werner Almesberger
5 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
6 * Rewritten for constant inumbers 1999 by Al Viro
10 #define __NO_VERSION__
11 #include <linux/module.h>
13 #include <linux/sched.h>
14 #include <linux/msdos_fs.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
18 #include <asm/uaccess.h>
23 /* MS-DOS "device special files" */
25 static const char *reserved_names[] = {
26 "CON ","PRN ","NUL ","AUX ",
27 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
28 "COM1 ","COM2 ","COM3 ","COM4 ",
32 /* Characters that are undesirable in an MS-DOS file name */
34 static char bad_chars[] = "*?<>|\"";
35 static char bad_if_strict_pc[] = "+=,; ";
36 static char bad_if_strict_atari[] = " "; /* GEMDOS is less restrictive */
37 #define bad_if_strict(opts) ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
40 void msdos_put_super(struct super_block *sb)
45 /***** Formats an MS-DOS file name. Rejects invalid names. */
46 static int msdos_format_name(const char *name,int len,
47 char *res,struct fat_mount_options *opts)
48 /* name is the proposed name, len is its length, res is
49 * the resulting name, opts->name_check is either (r)elaxed,
50 * (n)ormal or (s)trict, opts->dotsOK allows dots at the
51 * beginning of name (for hidden files)
55 const char **reserved;
59 if (name[0] == '.') { /* dotfile because . and .. already done */
61 /* Get rid of dot - test for it elsewhere */
64 else if (!opts->atari) return -EINVAL;
66 /* disallow names that _really_ start with a dot for MS-DOS, GEMDOS does
70 for (walk = res; len && walk-res < 8; walk++) {
73 if (opts->name_check != 'r' && strchr(bad_chars,c))
75 if (opts->name_check == 's' && strchr(bad_if_strict(opts),c))
77 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
79 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
80 /* 0xE5 is legal as a first character, but we must substitute 0x05 */
81 /* because 0xE5 marks deleted files. Yes, DOS really does this. */
82 /* It seems that Microsoft hacked DOS to support non-US characters */
83 /* after the 0xE5 character was already in use to mark deleted files. */
84 if((res==walk) && (c==0xE5)) c=0x05;
87 *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
89 if (space) return -EINVAL;
90 if (opts->name_check == 's' && len && c != '.') {
93 if (c != '.') return -EINVAL;
95 while (c != '.' && len--) c = *name++;
97 while (walk-res < 8) *walk++ = ' ';
98 while (len > 0 && walk-res < MSDOS_NAME) {
101 if (opts->name_check != 'r' && strchr(bad_chars,c))
103 if (opts->name_check == 's' &&
104 strchr(bad_if_strict(opts),c))
106 if (c < ' ' || c == ':' || c == '\\')
109 if (opts->name_check == 's')
113 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
116 *walk++ = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
118 if (space) return -EINVAL;
119 if (opts->name_check == 's' && len) return -EINVAL;
121 while (walk-res < MSDOS_NAME) *walk++ = ' ';
123 /* GEMDOS is less stupid and has no reserved names */
124 for (reserved = reserved_names; *reserved; reserved++)
125 if (!strncmp(res,*reserved,8)) return -EINVAL;
129 /***** Locates a directory entry. Uses unformatted name. */
130 static int msdos_find(struct inode *dir,const char *name,int len,
131 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
135 char msdos_name[MSDOS_NAME];
137 dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
138 res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
141 res = fat_scan(dir,msdos_name,bh,de,ino);
142 if (!res && dotsOK) {
144 if (!((*de)->attr & ATTR_HIDDEN))
147 if ((*de)->attr & ATTR_HIDDEN)
156 * Compute the hash for the msdos name corresponding to the dentry.
157 * Note: if the name is invalid, we leave the hash code unchanged so
158 * that the existing dentry can be used. The msdos fs routines will
159 * return ENOENT or EINVAL as appropriate.
161 static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
163 struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
165 char msdos_name[MSDOS_NAME];
167 error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
169 qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
174 * Compare two msdos names. If either of the names are invalid,
175 * we fall back to doing the standard name comparison.
177 static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
179 struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
181 char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
183 error = msdos_format_name(a->name, a->len, a_msdos_name, options);
186 error = msdos_format_name(b->name, b->len, b_msdos_name, options);
189 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
195 if (a->len == b->len)
196 error = memcmp(a->name, b->name, a->len);
201 static struct dentry_operations msdos_dentry_operations = {
203 d_compare: msdos_cmp,
207 * AV. Wrappers for FAT sb operations. Is it wise?
210 /***** Get inode using directory and name */
211 struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
213 struct super_block *sb = dir->i_sb;
214 struct inode *inode = NULL;
215 struct msdos_dir_entry *de;
216 struct buffer_head *bh = NULL;
219 PRINTK (("msdos_lookup\n"));
221 dentry->d_op = &msdos_dentry_operations;
223 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
230 inode = fat_build_inode(sb, de, ino, &res);
234 d_add(dentry, inode);
242 /***** Creates a directory entry (name is already formatted). */
243 static int msdos_add_entry(struct inode *dir, const char *name,
244 struct buffer_head **bh,
245 struct msdos_dir_entry **de,
247 int is_dir, int is_hid)
249 struct super_block *sb = dir->i_sb;
252 if ((res = fat_add_entries(dir, 1, bh, de, ino))<0)
255 * XXX all times should be set by caller upon successful completion.
257 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
258 mark_inode_dirty(dir);
259 memcpy((*de)->name,name,MSDOS_NAME);
260 (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
262 (*de)->attr |= ATTR_HIDDEN;
265 fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
267 fat_mark_buffer_dirty(sb, *bh);
272 * AV. Huh??? It's exported. Oughtta check usage.
275 /***** Create a file */
276 int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
278 struct super_block *sb = dir->i_sb;
279 struct buffer_head *bh;
280 struct msdos_dir_entry *de;
283 char msdos_name[MSDOS_NAME];
285 res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
286 msdos_name, &MSDOS_SB(sb)->options);
289 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
290 /* Have to do it due to foo vs. .foo conflicts */
291 if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
296 res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid);
299 inode = fat_build_inode(dir->i_sb, de, ino, &res);
303 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
304 mark_inode_dirty(inode);
305 d_instantiate(dentry, inode);
309 /***** Remove a directory */
310 int msdos_rmdir(struct inode *dir, struct dentry *dentry)
312 struct super_block *sb = dir->i_sb;
313 struct inode *inode = dentry->d_inode;
315 struct buffer_head *bh;
316 struct msdos_dir_entry *de;
319 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
324 * Check whether the directory is not in use, then check
325 * whether it is empty.
327 res = fat_dir_empty(inode);
331 de->name[0] = DELETED_FLAG;
332 fat_mark_buffer_dirty(sb, bh);
335 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
337 mark_inode_dirty(inode);
338 mark_inode_dirty(dir);
346 /***** Make a directory */
347 int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
349 struct super_block *sb = dir->i_sb;
350 struct buffer_head *bh;
351 struct msdos_dir_entry *de;
354 char msdos_name[MSDOS_NAME];
357 res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
358 msdos_name, &MSDOS_SB(sb)->options);
361 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
362 /* foo vs .foo situation */
363 if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0)
366 res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid);
369 inode = fat_build_inode(dir->i_sb, de, ino, &res);
377 inode->i_nlink = 2; /* no need to mark them dirty */
379 res = fat_new_dir(inode, dir, 0);
384 d_instantiate(dentry, inode);
391 printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanup\n", res);
393 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
395 mark_inode_dirty(inode);
396 mark_inode_dirty(dir);
397 de->name[0] = DELETED_FLAG;
398 fat_mark_buffer_dirty(sb, bh);
410 /***** Unlink a file */
411 int msdos_unlink( struct inode *dir, struct dentry *dentry)
413 struct super_block *sb = dir->i_sb;
414 struct inode *inode = dentry->d_inode;
416 struct buffer_head *bh;
417 struct msdos_dir_entry *de;
420 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
425 de->name[0] = DELETED_FLAG;
426 fat_mark_buffer_dirty(sb, bh);
430 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
431 mark_inode_dirty(inode);
432 mark_inode_dirty(dir);
438 static int do_msdos_rename(struct inode *old_dir, char *old_name,
439 struct dentry *old_dentry,
440 struct inode *new_dir,char *new_name, struct dentry *new_dentry,
441 struct buffer_head *old_bh,
442 struct msdos_dir_entry *old_de, int old_ino, int is_hid)
444 struct super_block *sb = old_dir->i_sb;
445 struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
446 struct msdos_dir_entry *new_de,*dotdot_de;
447 struct inode *old_inode,*new_inode;
448 int new_ino,dotdot_ino;
452 old_inode = old_dentry->d_inode;
453 new_inode = new_dentry->d_inode;
454 is_dir = S_ISDIR(old_inode->i_mode);
456 if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode)
457 goto degenerate_case;
460 error = fat_dir_empty(new_inode);
464 error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
465 &dotdot_de, &dotdot_ino);
468 "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
469 old_dentry->d_parent->d_name.name,
470 old_dentry->d_name.name, error);
475 error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
476 &new_ino, is_dir, is_hid);
480 new_dir->i_version = ++event;
485 fat_detach(new_inode);
486 old_de->name[0] = DELETED_FLAG;
487 fat_mark_buffer_dirty(sb, old_bh);
488 fat_detach(old_inode);
489 fat_attach(old_inode, new_ino);
491 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
493 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
494 mark_inode_dirty(old_inode);
495 old_dir->i_version = ++event;
496 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
497 mark_inode_dirty(old_dir);
499 new_inode->i_nlink--;
500 new_inode->i_ctime = CURRENT_TIME;
501 mark_inode_dirty(new_inode);
504 dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
505 dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
506 fat_mark_buffer_dirty(sb, dotdot_bh);
508 mark_inode_dirty(old_dir);
510 new_inode->i_nlink--;
511 mark_inode_dirty(new_inode);
514 mark_inode_dirty(new_dir);
519 fat_brelse(sb, new_bh);
520 fat_brelse(sb, dotdot_bh);
528 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
530 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
531 mark_inode_dirty(old_inode);
532 old_dir->i_version = ++event;
533 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
534 mark_inode_dirty(old_dir);
538 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
539 int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
540 struct inode *new_dir,struct dentry *new_dentry)
542 struct super_block *sb = old_dir->i_sb;
543 struct buffer_head *old_bh;
544 struct msdos_dir_entry *old_de;
546 int is_hid,old_hid; /* if new file and old file are hidden */
547 char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
549 error = msdos_format_name(old_dentry->d_name.name,
550 old_dentry->d_name.len,old_msdos_name,
551 &MSDOS_SB(old_dir->i_sb)->options);
554 error = msdos_format_name(new_dentry->d_name.name,
555 new_dentry->d_name.len,new_msdos_name,
556 &MSDOS_SB(new_dir->i_sb)->options);
560 is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
561 old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
562 error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino);
566 error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
567 new_dir, new_msdos_name, new_dentry,
568 old_bh, old_de, (ino_t)old_ino, is_hid);
569 fat_brelse(sb, old_bh);
576 /* The public inode operations for the msdos fs */
577 struct inode_operations msdos_dir_inode_operations = {
578 create: msdos_create,
579 lookup: msdos_lookup,
580 unlink: msdos_unlink,
583 rename: msdos_rename,
584 setattr: fat_notify_change,
587 struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
589 struct super_block *res;
591 MSDOS_SB(sb)->options.isvfat = 0;
592 res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
594 sb->s_root->d_op = &msdos_dentry_operations;