msdos_rmdir(): kill BS comment
[muen/linux.git] / fs / fat / namei_msdos.c
1 /*
2  *  linux/fs/msdos/namei.c
3  *
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
7  */
8
9 #include <linux/module.h>
10 #include <linux/iversion.h>
11 #include "fat.h"
12
13 /* Characters that are undesirable in an MS-DOS file name */
14 static unsigned char bad_chars[] = "*?<>|\"";
15 static unsigned char bad_if_strict[] = "+=,; ";
16
17 /***** Formats an MS-DOS file name. Rejects invalid names. */
18 static int msdos_format_name(const unsigned char *name, int len,
19                              unsigned char *res, struct fat_mount_options *opts)
20         /*
21          * name is the proposed name, len is its length, res is
22          * the resulting name, opts->name_check is either (r)elaxed,
23          * (n)ormal or (s)trict, opts->dotsOK allows dots at the
24          * beginning of name (for hidden files)
25          */
26 {
27         unsigned char *walk;
28         unsigned char c;
29         int space;
30
31         if (name[0] == '.') {   /* dotfile because . and .. already done */
32                 if (opts->dotsOK) {
33                         /* Get rid of dot - test for it elsewhere */
34                         name++;
35                         len--;
36                 } else
37                         return -EINVAL;
38         }
39         /*
40          * disallow names that _really_ start with a dot
41          */
42         space = 1;
43         c = 0;
44         for (walk = res; len && walk - res < 8; walk++) {
45                 c = *name++;
46                 len--;
47                 if (opts->name_check != 'r' && strchr(bad_chars, c))
48                         return -EINVAL;
49                 if (opts->name_check == 's' && strchr(bad_if_strict, c))
50                         return -EINVAL;
51                 if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
52                         return -EINVAL;
53                 if (c < ' ' || c == ':' || c == '\\')
54                         return -EINVAL;
55         /*
56          * 0xE5 is legal as a first character, but we must substitute
57          * 0x05 because 0xE5 marks deleted files.  Yes, DOS really
58          * does this.
59          * It seems that Microsoft hacked DOS to support non-US
60          * characters after the 0xE5 character was already in use to
61          * mark deleted files.
62          */
63                 if ((res == walk) && (c == 0xE5))
64                         c = 0x05;
65                 if (c == '.')
66                         break;
67                 space = (c == ' ');
68                 *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
69         }
70         if (space)
71                 return -EINVAL;
72         if (opts->name_check == 's' && len && c != '.') {
73                 c = *name++;
74                 len--;
75                 if (c != '.')
76                         return -EINVAL;
77         }
78         while (c != '.' && len--)
79                 c = *name++;
80         if (c == '.') {
81                 while (walk - res < 8)
82                         *walk++ = ' ';
83                 while (len > 0 && walk - res < MSDOS_NAME) {
84                         c = *name++;
85                         len--;
86                         if (opts->name_check != 'r' && strchr(bad_chars, c))
87                                 return -EINVAL;
88                         if (opts->name_check == 's' &&
89                             strchr(bad_if_strict, c))
90                                 return -EINVAL;
91                         if (c < ' ' || c == ':' || c == '\\')
92                                 return -EINVAL;
93                         if (c == '.') {
94                                 if (opts->name_check == 's')
95                                         return -EINVAL;
96                                 break;
97                         }
98                         if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
99                                 return -EINVAL;
100                         space = c == ' ';
101                         if (!opts->nocase && c >= 'a' && c <= 'z')
102                                 *walk++ = c - 32;
103                         else
104                                 *walk++ = c;
105                 }
106                 if (space)
107                         return -EINVAL;
108                 if (opts->name_check == 's' && len)
109                         return -EINVAL;
110         }
111         while (walk - res < MSDOS_NAME)
112                 *walk++ = ' ';
113
114         return 0;
115 }
116
117 /***** Locates a directory entry.  Uses unformatted name. */
118 static int msdos_find(struct inode *dir, const unsigned char *name, int len,
119                       struct fat_slot_info *sinfo)
120 {
121         struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
122         unsigned char msdos_name[MSDOS_NAME];
123         int err;
124
125         err = msdos_format_name(name, len, msdos_name, &sbi->options);
126         if (err)
127                 return -ENOENT;
128
129         err = fat_scan(dir, msdos_name, sinfo);
130         if (!err && sbi->options.dotsOK) {
131                 if (name[0] == '.') {
132                         if (!(sinfo->de->attr & ATTR_HIDDEN))
133                                 err = -ENOENT;
134                 } else {
135                         if (sinfo->de->attr & ATTR_HIDDEN)
136                                 err = -ENOENT;
137                 }
138                 if (err)
139                         brelse(sinfo->bh);
140         }
141         return err;
142 }
143
144 /*
145  * Compute the hash for the msdos name corresponding to the dentry.
146  * Note: if the name is invalid, we leave the hash code unchanged so
147  * that the existing dentry can be used. The msdos fs routines will
148  * return ENOENT or EINVAL as appropriate.
149  */
150 static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
151 {
152         struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
153         unsigned char msdos_name[MSDOS_NAME];
154         int error;
155
156         error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
157         if (!error)
158                 qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
159         return 0;
160 }
161
162 /*
163  * Compare two msdos names. If either of the names are invalid,
164  * we fall back to doing the standard name comparison.
165  */
166 static int msdos_cmp(const struct dentry *dentry,
167                 unsigned int len, const char *str, const struct qstr *name)
168 {
169         struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
170         unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
171         int error;
172
173         error = msdos_format_name(name->name, name->len, a_msdos_name, options);
174         if (error)
175                 goto old_compare;
176         error = msdos_format_name(str, len, b_msdos_name, options);
177         if (error)
178                 goto old_compare;
179         error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
180 out:
181         return error;
182
183 old_compare:
184         error = 1;
185         if (name->len == len)
186                 error = memcmp(name->name, str, len);
187         goto out;
188 }
189
190 static const struct dentry_operations msdos_dentry_operations = {
191         .d_hash         = msdos_hash,
192         .d_compare      = msdos_cmp,
193 };
194
195 /*
196  * AV. Wrappers for FAT sb operations. Is it wise?
197  */
198
199 /***** Get inode using directory and name */
200 static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
201                                    unsigned int flags)
202 {
203         struct super_block *sb = dir->i_sb;
204         struct fat_slot_info sinfo;
205         struct inode *inode;
206         int err;
207
208         mutex_lock(&MSDOS_SB(sb)->s_lock);
209         err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
210         switch (err) {
211         case -ENOENT:
212                 inode = NULL;
213                 break;
214         case 0:
215                 inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
216                 brelse(sinfo.bh);
217                 break;
218         default:
219                 inode = ERR_PTR(err);
220         }
221         mutex_unlock(&MSDOS_SB(sb)->s_lock);
222         return d_splice_alias(inode, dentry);
223 }
224
225 /***** Creates a directory entry (name is already formatted). */
226 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
227                            int is_dir, int is_hid, int cluster,
228                            struct timespec *ts, struct fat_slot_info *sinfo)
229 {
230         struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
231         struct msdos_dir_entry de;
232         __le16 time, date;
233         int err;
234
235         memcpy(de.name, name, MSDOS_NAME);
236         de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
237         if (is_hid)
238                 de.attr |= ATTR_HIDDEN;
239         de.lcase = 0;
240         fat_time_unix2fat(sbi, ts, &time, &date, NULL);
241         de.cdate = de.adate = 0;
242         de.ctime = 0;
243         de.ctime_cs = 0;
244         de.time = time;
245         de.date = date;
246         fat_set_start(&de, cluster);
247         de.size = 0;
248
249         err = fat_add_entries(dir, &de, 1, sinfo);
250         if (err)
251                 return err;
252
253         dir->i_ctime = dir->i_mtime = *ts;
254         if (IS_DIRSYNC(dir))
255                 (void)fat_sync_inode(dir);
256         else
257                 mark_inode_dirty(dir);
258
259         return 0;
260 }
261
262 /***** Create a file */
263 static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
264                         bool excl)
265 {
266         struct super_block *sb = dir->i_sb;
267         struct inode *inode = NULL;
268         struct fat_slot_info sinfo;
269         struct timespec ts;
270         unsigned char msdos_name[MSDOS_NAME];
271         int err, is_hid;
272
273         mutex_lock(&MSDOS_SB(sb)->s_lock);
274
275         err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
276                                 msdos_name, &MSDOS_SB(sb)->options);
277         if (err)
278                 goto out;
279         is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
280         /* Have to do it due to foo vs. .foo conflicts */
281         if (!fat_scan(dir, msdos_name, &sinfo)) {
282                 brelse(sinfo.bh);
283                 err = -EINVAL;
284                 goto out;
285         }
286
287         ts = current_time(dir);
288         err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
289         if (err)
290                 goto out;
291         inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
292         brelse(sinfo.bh);
293         if (IS_ERR(inode)) {
294                 err = PTR_ERR(inode);
295                 goto out;
296         }
297         inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
298         /* timestamp is already written, so mark_inode_dirty() is unneeded. */
299
300         d_instantiate(dentry, inode);
301 out:
302         mutex_unlock(&MSDOS_SB(sb)->s_lock);
303         if (!err)
304                 err = fat_flush_inodes(sb, dir, inode);
305         return err;
306 }
307
308 /***** Remove a directory */
309 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
310 {
311         struct super_block *sb = dir->i_sb;
312         struct inode *inode = d_inode(dentry);
313         struct fat_slot_info sinfo;
314         int err;
315
316         mutex_lock(&MSDOS_SB(sb)->s_lock);
317         err = fat_dir_empty(inode);
318         if (err)
319                 goto out;
320         err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
321         if (err)
322                 goto out;
323
324         err = fat_remove_entries(dir, &sinfo);  /* and releases bh */
325         if (err)
326                 goto out;
327         drop_nlink(dir);
328
329         clear_nlink(inode);
330         inode->i_ctime = current_time(inode);
331         fat_detach(inode);
332 out:
333         mutex_unlock(&MSDOS_SB(sb)->s_lock);
334         if (!err)
335                 err = fat_flush_inodes(sb, dir, inode);
336
337         return err;
338 }
339
340 /***** Make a directory */
341 static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
342 {
343         struct super_block *sb = dir->i_sb;
344         struct fat_slot_info sinfo;
345         struct inode *inode;
346         unsigned char msdos_name[MSDOS_NAME];
347         struct timespec ts;
348         int err, is_hid, cluster;
349
350         mutex_lock(&MSDOS_SB(sb)->s_lock);
351
352         err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
353                                 msdos_name, &MSDOS_SB(sb)->options);
354         if (err)
355                 goto out;
356         is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
357         /* foo vs .foo situation */
358         if (!fat_scan(dir, msdos_name, &sinfo)) {
359                 brelse(sinfo.bh);
360                 err = -EINVAL;
361                 goto out;
362         }
363
364         ts = current_time(dir);
365         cluster = fat_alloc_new_dir(dir, &ts);
366         if (cluster < 0) {
367                 err = cluster;
368                 goto out;
369         }
370         err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
371         if (err)
372                 goto out_free;
373         inc_nlink(dir);
374
375         inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
376         brelse(sinfo.bh);
377         if (IS_ERR(inode)) {
378                 err = PTR_ERR(inode);
379                 /* the directory was completed, just return a error */
380                 goto out;
381         }
382         set_nlink(inode, 2);
383         inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
384         /* timestamp is already written, so mark_inode_dirty() is unneeded. */
385
386         d_instantiate(dentry, inode);
387
388         mutex_unlock(&MSDOS_SB(sb)->s_lock);
389         fat_flush_inodes(sb, dir, inode);
390         return 0;
391
392 out_free:
393         fat_free_clusters(dir, cluster);
394 out:
395         mutex_unlock(&MSDOS_SB(sb)->s_lock);
396         return err;
397 }
398
399 /***** Unlink a file */
400 static int msdos_unlink(struct inode *dir, struct dentry *dentry)
401 {
402         struct inode *inode = d_inode(dentry);
403         struct super_block *sb = inode->i_sb;
404         struct fat_slot_info sinfo;
405         int err;
406
407         mutex_lock(&MSDOS_SB(sb)->s_lock);
408         err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
409         if (err)
410                 goto out;
411
412         err = fat_remove_entries(dir, &sinfo);  /* and releases bh */
413         if (err)
414                 goto out;
415         clear_nlink(inode);
416         inode->i_ctime = current_time(inode);
417         fat_detach(inode);
418 out:
419         mutex_unlock(&MSDOS_SB(sb)->s_lock);
420         if (!err)
421                 err = fat_flush_inodes(sb, dir, inode);
422
423         return err;
424 }
425
426 static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
427                            struct dentry *old_dentry,
428                            struct inode *new_dir, unsigned char *new_name,
429                            struct dentry *new_dentry, int is_hid)
430 {
431         struct buffer_head *dotdot_bh;
432         struct msdos_dir_entry *dotdot_de;
433         struct inode *old_inode, *new_inode;
434         struct fat_slot_info old_sinfo, sinfo;
435         struct timespec ts;
436         loff_t new_i_pos;
437         int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
438
439         old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
440         old_inode = d_inode(old_dentry);
441         new_inode = d_inode(new_dentry);
442
443         err = fat_scan(old_dir, old_name, &old_sinfo);
444         if (err) {
445                 err = -EIO;
446                 goto out;
447         }
448
449         is_dir = S_ISDIR(old_inode->i_mode);
450         update_dotdot = (is_dir && old_dir != new_dir);
451         if (update_dotdot) {
452                 if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
453                         err = -EIO;
454                         goto out;
455                 }
456         }
457
458         old_attrs = MSDOS_I(old_inode)->i_attrs;
459         err = fat_scan(new_dir, new_name, &sinfo);
460         if (!err) {
461                 if (!new_inode) {
462                         /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
463                         if (sinfo.de != old_sinfo.de) {
464                                 err = -EINVAL;
465                                 goto out;
466                         }
467                         if (is_hid)
468                                 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
469                         else
470                                 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
471                         if (IS_DIRSYNC(old_dir)) {
472                                 err = fat_sync_inode(old_inode);
473                                 if (err) {
474                                         MSDOS_I(old_inode)->i_attrs = old_attrs;
475                                         goto out;
476                                 }
477                         } else
478                                 mark_inode_dirty(old_inode);
479
480                         inode_inc_iversion(old_dir);
481                         old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
482                         if (IS_DIRSYNC(old_dir))
483                                 (void)fat_sync_inode(old_dir);
484                         else
485                                 mark_inode_dirty(old_dir);
486                         goto out;
487                 }
488         }
489
490         ts = current_time(old_inode);
491         if (new_inode) {
492                 if (err)
493                         goto out;
494                 if (is_dir) {
495                         err = fat_dir_empty(new_inode);
496                         if (err)
497                                 goto out;
498                 }
499                 new_i_pos = MSDOS_I(new_inode)->i_pos;
500                 fat_detach(new_inode);
501         } else {
502                 err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
503                                       &ts, &sinfo);
504                 if (err)
505                         goto out;
506                 new_i_pos = sinfo.i_pos;
507         }
508         inode_inc_iversion(new_dir);
509
510         fat_detach(old_inode);
511         fat_attach(old_inode, new_i_pos);
512         if (is_hid)
513                 MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
514         else
515                 MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
516         if (IS_DIRSYNC(new_dir)) {
517                 err = fat_sync_inode(old_inode);
518                 if (err)
519                         goto error_inode;
520         } else
521                 mark_inode_dirty(old_inode);
522
523         if (update_dotdot) {
524                 fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
525                 mark_buffer_dirty_inode(dotdot_bh, old_inode);
526                 if (IS_DIRSYNC(new_dir)) {
527                         err = sync_dirty_buffer(dotdot_bh);
528                         if (err)
529                                 goto error_dotdot;
530                 }
531                 drop_nlink(old_dir);
532                 if (!new_inode)
533                         inc_nlink(new_dir);
534         }
535
536         err = fat_remove_entries(old_dir, &old_sinfo);  /* and releases bh */
537         old_sinfo.bh = NULL;
538         if (err)
539                 goto error_dotdot;
540         inode_inc_iversion(old_dir);
541         old_dir->i_ctime = old_dir->i_mtime = ts;
542         if (IS_DIRSYNC(old_dir))
543                 (void)fat_sync_inode(old_dir);
544         else
545                 mark_inode_dirty(old_dir);
546
547         if (new_inode) {
548                 drop_nlink(new_inode);
549                 if (is_dir)
550                         drop_nlink(new_inode);
551                 new_inode->i_ctime = ts;
552         }
553 out:
554         brelse(sinfo.bh);
555         brelse(dotdot_bh);
556         brelse(old_sinfo.bh);
557         return err;
558
559 error_dotdot:
560         /* data cluster is shared, serious corruption */
561         corrupt = 1;
562
563         if (update_dotdot) {
564                 fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
565                 mark_buffer_dirty_inode(dotdot_bh, old_inode);
566                 corrupt |= sync_dirty_buffer(dotdot_bh);
567         }
568 error_inode:
569         fat_detach(old_inode);
570         fat_attach(old_inode, old_sinfo.i_pos);
571         MSDOS_I(old_inode)->i_attrs = old_attrs;
572         if (new_inode) {
573                 fat_attach(new_inode, new_i_pos);
574                 if (corrupt)
575                         corrupt |= fat_sync_inode(new_inode);
576         } else {
577                 /*
578                  * If new entry was not sharing the data cluster, it
579                  * shouldn't be serious corruption.
580                  */
581                 int err2 = fat_remove_entries(new_dir, &sinfo);
582                 if (corrupt)
583                         corrupt |= err2;
584                 sinfo.bh = NULL;
585         }
586         if (corrupt < 0) {
587                 fat_fs_error(new_dir->i_sb,
588                              "%s: Filesystem corrupted (i_pos %lld)",
589                              __func__, sinfo.i_pos);
590         }
591         goto out;
592 }
593
594 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
595 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
596                         struct inode *new_dir, struct dentry *new_dentry,
597                         unsigned int flags)
598 {
599         struct super_block *sb = old_dir->i_sb;
600         unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
601         int err, is_hid;
602
603         if (flags & ~RENAME_NOREPLACE)
604                 return -EINVAL;
605
606         mutex_lock(&MSDOS_SB(sb)->s_lock);
607
608         err = msdos_format_name(old_dentry->d_name.name,
609                                 old_dentry->d_name.len, old_msdos_name,
610                                 &MSDOS_SB(old_dir->i_sb)->options);
611         if (err)
612                 goto out;
613         err = msdos_format_name(new_dentry->d_name.name,
614                                 new_dentry->d_name.len, new_msdos_name,
615                                 &MSDOS_SB(new_dir->i_sb)->options);
616         if (err)
617                 goto out;
618
619         is_hid =
620              (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
621
622         err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
623                               new_dir, new_msdos_name, new_dentry, is_hid);
624 out:
625         mutex_unlock(&MSDOS_SB(sb)->s_lock);
626         if (!err)
627                 err = fat_flush_inodes(sb, old_dir, new_dir);
628         return err;
629 }
630
631 static const struct inode_operations msdos_dir_inode_operations = {
632         .create         = msdos_create,
633         .lookup         = msdos_lookup,
634         .unlink         = msdos_unlink,
635         .mkdir          = msdos_mkdir,
636         .rmdir          = msdos_rmdir,
637         .rename         = msdos_rename,
638         .setattr        = fat_setattr,
639         .getattr        = fat_getattr,
640 };
641
642 static void setup(struct super_block *sb)
643 {
644         MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
645         sb->s_d_op = &msdos_dentry_operations;
646         sb->s_flags |= SB_NOATIME;
647 }
648
649 static int msdos_fill_super(struct super_block *sb, void *data, int silent)
650 {
651         return fat_fill_super(sb, data, silent, 0, setup);
652 }
653
654 static struct dentry *msdos_mount(struct file_system_type *fs_type,
655                         int flags, const char *dev_name,
656                         void *data)
657 {
658         return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
659 }
660
661 static struct file_system_type msdos_fs_type = {
662         .owner          = THIS_MODULE,
663         .name           = "msdos",
664         .mount          = msdos_mount,
665         .kill_sb        = kill_block_super,
666         .fs_flags       = FS_REQUIRES_DEV,
667 };
668 MODULE_ALIAS_FS("msdos");
669
670 static int __init init_msdos_fs(void)
671 {
672         return register_filesystem(&msdos_fs_type);
673 }
674
675 static void __exit exit_msdos_fs(void)
676 {
677         unregister_filesystem(&msdos_fs_type);
678 }
679
680 MODULE_LICENSE("GPL");
681 MODULE_AUTHOR("Werner Almesberger");
682 MODULE_DESCRIPTION("MS-DOS filesystem support");
683
684 module_init(init_msdos_fs)
685 module_exit(exit_msdos_fs)