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
9 #include <linux/module.h>
10 #include <linux/time.h>
11 #include <linux/buffer_head.h>
12 #include <linux/msdos_fs.h>
13 #include <linux/smp_lock.h>
15 /* MS-DOS "device special files" */
16 static const unsigned char *reserved_names[] = {
17 "CON ", "PRN ", "NUL ", "AUX ",
18 "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ",
19 "COM1 ", "COM2 ", "COM3 ", "COM4 ",
23 /* Characters that are undesirable in an MS-DOS file name */
24 static unsigned char bad_chars[] = "*?<>|\"";
25 static unsigned char bad_if_strict_pc[] = "+=,; ";
26 /* GEMDOS is less restrictive */
27 static unsigned char bad_if_strict_atari[] = " ";
29 #define bad_if_strict(opts) \
30 ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
32 /***** Formats an MS-DOS file name. Rejects invalid names. */
33 static int msdos_format_name(const unsigned char *name, int len,
34 unsigned char *res, struct fat_mount_options *opts)
36 * name is the proposed name, len is its length, res is
37 * the resulting name, opts->name_check is either (r)elaxed,
38 * (n)ormal or (s)trict, opts->dotsOK allows dots at the
39 * beginning of name (for hidden files)
43 const unsigned char **reserved;
47 if (name[0] == '.') { /* dotfile because . and .. already done */
49 /* Get rid of dot - test for it elsewhere */
52 } else if (!opts->atari)
56 * disallow names that _really_ start with a dot for MS-DOS,
57 * GEMDOS does not care
61 for (walk = res; len && walk - res < 8; walk++) {
64 if (opts->name_check != 'r' && strchr(bad_chars, c))
66 if (opts->name_check == 's' && strchr(bad_if_strict(opts), c))
68 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
70 if (c < ' ' || c == ':' || c == '\\')
73 * 0xE5 is legal as a first character, but we must substitute
74 * 0x05 because 0xE5 marks deleted files. Yes, DOS really
76 * It seems that Microsoft hacked DOS to support non-US
77 * characters after the 0xE5 character was already in use to
80 if ((res == walk) && (c == 0xE5))
85 *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
89 if (opts->name_check == 's' && len && c != '.') {
95 while (c != '.' && len--)
98 while (walk - res < 8)
100 while (len > 0 && walk - res < MSDOS_NAME) {
103 if (opts->name_check != 'r' && strchr(bad_chars, c))
105 if (opts->name_check == 's' &&
106 strchr(bad_if_strict(opts), c))
108 if (c < ' ' || c == ':' || c == '\\')
111 if (opts->name_check == 's')
115 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
118 if (!opts->nocase && c >= 'a' && c <= 'z')
125 if (opts->name_check == 's' && len)
128 while (walk - res < MSDOS_NAME)
131 /* GEMDOS is less stupid and has no reserved names */
132 for (reserved = reserved_names; *reserved; reserved++)
133 if (!strncmp(res, *reserved, 8))
138 /***** Locates a directory entry. Uses unformatted name. */
139 static int msdos_find(struct inode *dir, const unsigned char *name, int len,
140 struct buffer_head **bh, struct msdos_dir_entry **de,
143 unsigned char msdos_name[MSDOS_NAME];
147 dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
148 res = msdos_format_name(name, len, msdos_name,
149 &MSDOS_SB(dir->i_sb)->options);
152 res = fat_scan(dir, msdos_name, bh, de, i_pos);
153 if (!res && dotsOK) {
154 if (name[0] == '.') {
155 if (!((*de)->attr & ATTR_HIDDEN))
158 if ((*de)->attr & ATTR_HIDDEN)
166 * Compute the hash for the msdos name corresponding to the dentry.
167 * Note: if the name is invalid, we leave the hash code unchanged so
168 * that the existing dentry can be used. The msdos fs routines will
169 * return ENOENT or EINVAL as appropriate.
171 static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
173 struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
174 unsigned char msdos_name[MSDOS_NAME];
177 error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
179 qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
184 * Compare two msdos names. If either of the names are invalid,
185 * we fall back to doing the standard name comparison.
187 static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
189 struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
190 unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
193 error = msdos_format_name(a->name, a->len, a_msdos_name, options);
196 error = msdos_format_name(b->name, b->len, b_msdos_name, options);
199 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
205 if (a->len == b->len)
206 error = memcmp(a->name, b->name, a->len);
210 static struct dentry_operations msdos_dentry_operations = {
211 .d_hash = msdos_hash,
212 .d_compare = msdos_cmp,
216 * AV. Wrappers for FAT sb operations. Is it wise?
219 /***** Get inode using directory and name */
220 static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
221 struct nameidata *nd)
223 struct super_block *sb = dir->i_sb;
224 struct inode *inode = NULL;
225 struct msdos_dir_entry *de;
226 struct buffer_head *bh = NULL;
230 dentry->d_op = &msdos_dentry_operations;
233 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
239 inode = fat_build_inode(sb, de, i_pos, &res);
244 dentry = d_splice_alias(inode, dentry);
246 dentry->d_op = &msdos_dentry_operations;
255 /***** Creates a directory entry (name is already formatted). */
256 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
257 struct buffer_head **bh,
258 struct msdos_dir_entry **de,
259 loff_t *i_pos, int is_dir, int is_hid)
263 res = fat_add_entries(dir, 1, bh, de, i_pos);
268 * XXX all times should be set by caller upon successful completion.
270 dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
271 mark_inode_dirty(dir);
273 memcpy((*de)->name, name, MSDOS_NAME);
274 (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
276 (*de)->attr |= ATTR_HIDDEN;
279 fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
281 mark_buffer_dirty(*bh);
285 /***** Create a file */
286 static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
287 struct nameidata *nd)
289 struct super_block *sb = dir->i_sb;
290 struct buffer_head *bh;
291 struct msdos_dir_entry *de;
295 unsigned char msdos_name[MSDOS_NAME];
298 res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
299 msdos_name, &MSDOS_SB(sb)->options);
304 is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
305 /* Have to do it due to foo vs. .foo conflicts */
306 if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
312 res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
317 inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
323 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
324 mark_inode_dirty(inode);
325 d_instantiate(dentry, inode);
330 /***** Remove a directory */
331 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
333 struct inode *inode = dentry->d_inode;
336 struct buffer_head *bh;
337 struct msdos_dir_entry *de;
341 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
346 * Check whether the directory is not in use, then check
347 * whether it is empty.
349 res = fat_dir_empty(inode);
353 de->name[0] = DELETED_FLAG;
354 mark_buffer_dirty(bh);
357 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
359 mark_inode_dirty(inode);
360 mark_inode_dirty(dir);
369 /***** Make a directory */
370 static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
372 struct super_block *sb = dir->i_sb;
373 struct buffer_head *bh;
374 struct msdos_dir_entry *de;
377 unsigned char msdos_name[MSDOS_NAME];
381 res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
382 msdos_name, &MSDOS_SB(sb)->options);
387 is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
388 /* foo vs .foo situation */
389 if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
392 res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
395 inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
403 inode->i_nlink = 2; /* no need to mark them dirty */
405 res = fat_new_dir(inode, dir, 0);
410 d_instantiate(dentry, inode);
419 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
421 mark_inode_dirty(inode);
422 mark_inode_dirty(dir);
423 de->name[0] = DELETED_FLAG;
424 mark_buffer_dirty(bh);
436 /***** Unlink a file */
437 static int msdos_unlink(struct inode *dir, struct dentry *dentry)
439 struct inode *inode = dentry->d_inode;
442 struct buffer_head *bh;
443 struct msdos_dir_entry *de;
447 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
452 de->name[0] = DELETED_FLAG;
453 mark_buffer_dirty(bh);
457 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
458 mark_inode_dirty(inode);
459 mark_inode_dirty(dir);
466 static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
467 struct dentry *old_dentry,
468 struct inode *new_dir, unsigned char *new_name,
469 struct dentry *new_dentry,
470 struct buffer_head *old_bh,
471 struct msdos_dir_entry *old_de, loff_t old_i_pos,
474 struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
475 struct msdos_dir_entry *new_de, *dotdot_de;
476 struct inode *old_inode, *new_inode;
477 loff_t new_i_pos, dotdot_i_pos;
481 old_inode = old_dentry->d_inode;
482 new_inode = new_dentry->d_inode;
483 is_dir = S_ISDIR(old_inode->i_mode);
485 if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 &&
487 goto degenerate_case;
490 error = fat_dir_empty(new_inode);
494 if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
495 &dotdot_de, &dotdot_i_pos) < 0) {
501 error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
502 &new_i_pos, is_dir, is_hid);
506 new_dir->i_version++;
511 fat_detach(new_inode);
512 old_de->name[0] = DELETED_FLAG;
513 mark_buffer_dirty(old_bh);
514 fat_detach(old_inode);
515 fat_attach(old_inode, new_i_pos);
517 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
519 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
520 mark_inode_dirty(old_inode);
521 old_dir->i_version++;
522 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
523 mark_inode_dirty(old_dir);
525 new_inode->i_nlink--;
526 new_inode->i_ctime = CURRENT_TIME_SEC;
527 mark_inode_dirty(new_inode);
530 dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
532 cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
533 mark_buffer_dirty(dotdot_bh);
535 mark_inode_dirty(old_dir);
537 new_inode->i_nlink--;
538 mark_inode_dirty(new_inode);
541 mark_inode_dirty(new_dir);
552 if (new_de != old_de)
555 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
557 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
558 mark_inode_dirty(old_inode);
559 old_dir->i_version++;
560 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
561 mark_inode_dirty(old_dir);
565 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
566 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
567 struct inode *new_dir, struct dentry *new_dentry)
569 struct buffer_head *old_bh;
570 struct msdos_dir_entry *old_de;
572 int error, is_hid, old_hid; /* if new file and old file are hidden */
573 unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
576 error = msdos_format_name(old_dentry->d_name.name,
577 old_dentry->d_name.len, old_msdos_name,
578 &MSDOS_SB(old_dir->i_sb)->options);
581 error = msdos_format_name(new_dentry->d_name.name,
582 new_dentry->d_name.len, new_msdos_name,
583 &MSDOS_SB(new_dir->i_sb)->options);
588 (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
590 (old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
592 error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
596 error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
597 new_dir, new_msdos_name, new_dentry,
598 old_bh, old_de, old_i_pos, is_hid);
606 static struct inode_operations msdos_dir_inode_operations = {
607 .create = msdos_create,
608 .lookup = msdos_lookup,
609 .unlink = msdos_unlink,
610 .mkdir = msdos_mkdir,
611 .rmdir = msdos_rmdir,
612 .rename = msdos_rename,
613 .setattr = fat_notify_change,
616 static int msdos_fill_super(struct super_block *sb, void *data, int silent)
620 res = fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, 0);
624 sb->s_root->d_op = &msdos_dentry_operations;
628 static struct super_block *msdos_get_sb(struct file_system_type *fs_type,
629 int flags, const char *dev_name,
632 return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
635 static struct file_system_type msdos_fs_type = {
636 .owner = THIS_MODULE,
638 .get_sb = msdos_get_sb,
639 .kill_sb = kill_block_super,
640 .fs_flags = FS_REQUIRES_DEV,
643 static int __init init_msdos_fs(void)
645 return register_filesystem(&msdos_fs_type);
648 static void __exit exit_msdos_fs(void)
650 unregister_filesystem(&msdos_fs_type);
653 MODULE_LICENSE("GPL");
654 MODULE_AUTHOR("Werner Almesberger");
655 MODULE_DESCRIPTION("MS-DOS filesystem support");
657 module_init(init_msdos_fs)
658 module_exit(exit_msdos_fs)