Linux 2.2.0
[davej-history.git] / fs / msdos / namei.c
blob055d700d99a137061aaf3f17d3b8fe15d1bfc34c
1 /*
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 */
9 #define __NO_VERSION__
10 #include <linux/config.h>
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>
20 #include "../fat/msbuffer.h"
22 #define MSDOS_DEBUG 0
23 #define PRINTK(x)
25 /* MS-DOS "device special files" */
27 static const char *reserved_names[] = {
28 #ifndef CONFIG_ATARI /* GEMDOS is less stupid */
29 "CON ","PRN ","NUL ","AUX ",
30 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
31 "COM1 ","COM2 ","COM3 ","COM4 ",
32 #endif
33 NULL };
36 /* Characters that are undesirable in an MS-DOS file name */
38 static char bad_chars[] = "*?<>|\"";
39 #ifdef CONFIG_ATARI
40 /* GEMDOS is less restrictive */
41 static char bad_if_strict[] = " ";
42 #else
43 static char bad_if_strict[] = "+=,; ";
44 #endif
46 void msdos_put_super(struct super_block *sb)
48 fat_put_super(sb);
49 MOD_DEC_USE_COUNT;
52 struct super_operations msdos_sops = {
53 msdos_read_inode,
54 fat_write_inode,
55 fat_put_inode,
56 fat_delete_inode,
57 fat_notify_change,
58 msdos_put_super,
59 NULL, /* added in 0.96c */
60 fat_statfs,
61 NULL
64 /***** Formats an MS-DOS file name. Rejects invalid names. */
65 static int msdos_format_name(char conv,const char *name,int len,
66 char *res,int dot_dirs,char dotsOK)
67 /* conv is relaxed/normal/strict, name is proposed name,
68 * len is the length of the proposed name, res is the result name,
69 * dot_dirs is . and .. are OK, dotsOK is if hidden files get dots.
72 char *walk;
73 const char **reserved;
74 unsigned char c;
75 int space;
77 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
78 if (!dot_dirs) return -EEXIST;
79 memset(res+1,' ',10);
80 while (len--) *res++ = '.';
81 return 0;
83 if (name[0] == '.') { /* dotfile because . and .. already done */
84 if (!dotsOK) return -EINVAL;
85 /* Get rid of dot - test for it elsewhere */
86 name++; len--;
88 #ifndef CONFIG_ATARI
89 space = 1; /* disallow names that _really_ start with a dot */
90 #else
91 space = 0; /* GEMDOS does not care */
92 #endif
93 c = 0;
94 for (walk = res; len && walk-res < 8; walk++) {
95 c = *name++;
96 len--;
97 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
98 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
99 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
100 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
101 /* 0xE5 is legal as a first character, but we must substitute 0x05 */
102 /* because 0xE5 marks deleted files. Yes, DOS really does this. */
103 /* It seems that Microsoft hacked DOS to support non-US characters */
104 /* after the 0xE5 character was already in use to mark deleted files. */
105 if((res==walk) && (c==0xE5)) c=0x05;
106 if (c == '.') break;
107 space = (c == ' ');
108 *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
110 if (space) return -EINVAL;
111 if (conv == 's' && len && c != '.') {
112 c = *name++;
113 len--;
114 if (c != '.') return -EINVAL;
116 while (c != '.' && len--) c = *name++;
117 if (c == '.') {
118 while (walk-res < 8) *walk++ = ' ';
119 while (len > 0 && walk-res < MSDOS_NAME) {
120 c = *name++;
121 len--;
122 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
123 if (conv == 's' && strchr(bad_if_strict,c))
124 return -EINVAL;
125 if (c < ' ' || c == ':' || c == '\\')
126 return -EINVAL;
127 if (c == '.') {
128 if (conv == 's')
129 return -EINVAL;
130 break;
132 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
133 space = c == ' ';
134 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
136 if (space) return -EINVAL;
137 if (conv == 's' && len) return -EINVAL;
139 while (walk-res < MSDOS_NAME) *walk++ = ' ';
140 for (reserved = reserved_names; *reserved; reserved++)
141 if (!strncmp(res,*reserved,8)) return -EINVAL;
142 return 0;
146 /***** Locates a directory entry. Uses unformatted name. */
147 static int msdos_find(struct inode *dir,const char *name,int len,
148 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
150 int res;
151 char dotsOK;
152 char scantype;
153 char msdos_name[MSDOS_NAME];
155 dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
156 res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
157 name,len, msdos_name,1,dotsOK);
158 if (res < 0)
159 return -ENOENT;
160 if((name[0]=='.') && dotsOK){
161 switch(len){
162 case 0: panic("Empty name in msdos_find!");
163 case 1: scantype = SCAN_ANY; break;
164 case 2: scantype = ((name[1]=='.')?SCAN_ANY:SCAN_HID); break;
165 default: scantype = SCAN_HID;
167 } else {
168 scantype = (dotsOK ? SCAN_NOTHID : SCAN_ANY);
170 return fat_scan(dir,msdos_name,bh,de,ino,scantype);
174 * Compute the hash for the msdos name corresponding to the dentry.
175 * Note: if the name is invalid, we leave the hash code unchanged so
176 * that the existing dentry can be used. The msdos fs routines will
177 * return ENOENT or EINVAL as appropriate.
179 static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
181 struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
182 int error;
183 char msdos_name[MSDOS_NAME];
185 error = msdos_format_name(options->name_check, qstr->name, qstr->len,
186 msdos_name, 1, options->dotsOK);
187 if (!error)
188 qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
189 return 0;
193 * Compare two msdos names. If either of the names are invalid,
194 * we fall back to doing the standard name comparison.
196 static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
198 struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
199 int error;
200 char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
202 error = msdos_format_name(options->name_check, a->name, a->len,
203 a_msdos_name, 1, options->dotsOK);
204 if (error)
205 goto old_compare;
206 error = msdos_format_name(options->name_check, b->name, b->len,
207 b_msdos_name, 1, options->dotsOK);
208 if (error)
209 goto old_compare;
210 error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
211 out:
212 return error;
214 old_compare:
215 error = 1;
216 if (a->len == b->len)
217 error = memcmp(a->name, b->name, a->len);
218 goto out;
222 static struct dentry_operations msdos_dentry_operations = {
223 NULL, /* d_revalidate */
224 msdos_hash,
225 msdos_cmp,
226 NULL, /* d_delete */
227 NULL,
228 NULL
231 struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
233 struct super_block *res;
235 MOD_INC_USE_COUNT;
237 MSDOS_SB(sb)->options.isvfat = 0;
238 sb->s_op = &msdos_sops;
239 res = fat_read_super(sb, data, silent);
240 if (res == NULL)
241 goto out_fail;
242 sb->s_root->d_op = &msdos_dentry_operations;
243 return res;
245 out_fail:
246 sb->s_dev = 0;
247 MOD_DEC_USE_COUNT;
248 return NULL;
252 /***** Get inode using directory and name */
253 int msdos_lookup(struct inode *dir,struct dentry *dentry)
255 struct super_block *sb = dir->i_sb;
256 struct inode *inode = NULL;
257 struct msdos_dir_entry *de;
258 struct buffer_head *bh;
259 int ino,res;
261 PRINTK (("msdos_lookup\n"));
263 dentry->d_op = &msdos_dentry_operations;
265 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
266 &de, &ino);
268 if (res == -ENOENT)
269 goto add;
270 if (res < 0)
271 goto out;
272 if (bh)
273 fat_brelse(sb, bh);
275 /* try to get the inode */
276 res = -EACCES;
277 inode = iget(sb, ino);
278 if (!inode)
279 goto out;
280 if (!inode->i_sb ||
281 (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
282 printk(KERN_WARNING "msdos_lookup: foreign inode??\n");
284 /* mkdir in progress? */
285 if (MSDOS_I(inode)->i_busy) {
286 printk(KERN_WARNING "msdos_lookup: %s/%s busy\n",
287 dentry->d_parent->d_name.name, dentry->d_name.name);
288 iput(inode);
289 goto out;
291 add:
292 d_add(dentry, inode);
293 res = 0;
294 out:
295 return res;
299 /***** Creates a directory entry (name is already formatted). */
300 static int msdos_create_entry(struct inode *dir, const char *name,
301 int is_dir, int is_hid, struct inode **result)
303 struct super_block *sb = dir->i_sb;
304 struct buffer_head *bh;
305 struct msdos_dir_entry *de;
306 int res,ino;
308 *result = NULL;
309 if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
310 if (res != -ENOENT) return res;
311 if ((dir->i_ino == MSDOS_ROOT_INO) &&
312 (MSDOS_SB(sb)->fat_bits != 32))
313 return -ENOSPC;
314 if ((res = fat_add_cluster(dir)) < 0) return res;
315 if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
318 * XXX all times should be set by caller upon successful completion.
320 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
321 mark_inode_dirty(dir);
322 memcpy(de->name,name,MSDOS_NAME);
323 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
324 de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
325 de->start = 0;
326 de->starthi = 0;
327 fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
328 de->size = 0;
329 fat_mark_buffer_dirty(sb, bh, 1);
330 if ((*result = iget(dir->i_sb,ino)) != NULL)
331 msdos_read_inode(*result);
332 fat_brelse(sb, bh);
333 if (!*result) return -EIO;
334 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
335 CURRENT_TIME;
336 mark_inode_dirty(*result);
337 return 0;
340 /***** Create a file or directory */
341 int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
343 struct super_block *sb = dir->i_sb;
344 struct buffer_head *bh;
345 struct msdos_dir_entry *de;
346 struct inode *inode;
347 int ino,res,is_hid;
348 char msdos_name[MSDOS_NAME];
350 res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
351 dentry->d_name.name,dentry->d_name.len,
352 msdos_name,0,
353 MSDOS_SB(sb)->options.dotsOK);
354 if (res < 0)
355 return res;
356 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
357 fat_lock_creation();
358 /* Scan for existing file twice, so that creating a file fails
359 * with -EINVAL if the other (dotfile/nondotfile) exists.
360 * Else SCAN_ANY would do. Maybe use EACCES, EBUSY, ENOSPC, ENFILE?
362 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
363 fat_unlock_creation();
364 fat_brelse(sb, bh);
365 return is_hid ? -EEXIST : -EINVAL;
367 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
368 fat_unlock_creation();
369 fat_brelse(sb, bh);
370 return is_hid ? -EINVAL : -EEXIST;
372 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),is_hid,
373 &inode);
374 fat_unlock_creation();
375 if (!res)
376 d_instantiate(dentry, inode);
377 return res;
381 #ifdef DEBUG
383 static void dump_fat(struct super_block *sb,int start)
385 printk("[");
386 while (start) {
387 printk("%d ",start);
388 start = fat_access(sb,start,-1);
389 if (!start) {
390 printk("ERROR");
391 break;
393 if (start == -1) break;
395 printk("]\n");
398 #endif
400 /***** See if directory is empty */
401 static int msdos_empty(struct inode *dir)
403 loff_t pos;
404 struct buffer_head *bh;
405 struct msdos_dir_entry *de;
406 int result = 0;
408 if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
409 pos = 0;
410 bh = NULL;
411 while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
412 /* Ignore vfat longname entries */
413 if (de->attr == ATTR_EXT)
414 continue;
415 if (!IS_FREE(de->name) &&
416 strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
417 strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
418 result = -ENOTEMPTY;
419 break;
422 if (bh)
423 fat_brelse(dir->i_sb, bh);
425 return result;
428 /***** Remove a directory */
429 int msdos_rmdir(struct inode *dir, struct dentry *dentry)
431 struct super_block *sb = dir->i_sb;
432 struct inode *inode = dentry->d_inode;
433 int res,ino;
434 struct buffer_head *bh;
435 struct msdos_dir_entry *de;
437 bh = NULL;
438 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
439 &bh, &de, &ino);
440 if (res < 0)
441 goto rmdir_done;
443 * Check whether the directory is not in use, then check
444 * whether it is empty.
446 res = -EBUSY;
447 if (!list_empty(&dentry->d_hash)) {
448 #ifdef MSDOS_DEBUG
449 printk("msdos_rmdir: %s/%s busy, d_count=%d\n",
450 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
451 #endif
452 goto rmdir_done;
454 res = msdos_empty(inode);
455 if (res)
456 goto rmdir_done;
458 inode->i_nlink = 0;
459 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
460 dir->i_nlink--;
461 mark_inode_dirty(inode);
462 mark_inode_dirty(dir);
464 * Do the d_delete before any blocking operations.
465 * We must make a negative dentry, as the FAT code
466 * apparently relies on the inode being iput().
468 d_delete(dentry);
469 de->name[0] = DELETED_FLAG;
470 fat_mark_buffer_dirty(sb, bh, 1);
471 res = 0;
473 rmdir_done:
474 fat_brelse(sb, bh);
475 return res;
478 /***** Make a directory */
479 int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
481 struct super_block *sb = dir->i_sb;
482 struct buffer_head *bh;
483 struct msdos_dir_entry *de;
484 struct inode *inode,*dot;
485 int ino,res,is_hid;
486 char msdos_name[MSDOS_NAME];
488 res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
489 dentry->d_name.name,dentry->d_name.len,
490 msdos_name,0,
491 MSDOS_SB(sb)->options.dotsOK);
492 if (res < 0)
493 return res;
494 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
495 fat_lock_creation();
496 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0)
497 goto out_exist;
499 res = msdos_create_entry(dir,msdos_name,1,is_hid, &inode);
500 if (res < 0)
501 goto out_unlock;
503 dir->i_nlink++;
504 inode->i_nlink = 2; /* no need to mark them dirty */
506 #ifdef whatfor
508 * He's dead, Jim. We don't d_instantiate anymore. Should do it
509 * from the very beginning, actually.
511 MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
512 #endif
514 if ((res = fat_add_cluster(inode)) < 0)
515 goto mkdir_error;
516 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
517 goto mkdir_error;
518 dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
519 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
520 MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
521 dot->i_nlink = inode->i_nlink;
522 mark_inode_dirty(dot);
523 iput(dot);
525 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,0,&dot)) < 0)
526 goto mkdir_error;
527 dot->i_size = dir->i_size;
528 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
529 MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
530 dot->i_nlink = dir->i_nlink;
531 mark_inode_dirty(dot);
532 #ifdef whatfor
533 MSDOS_I(inode)->i_busy = 0;
534 #endif
535 iput(dot);
536 d_instantiate(dentry, inode);
537 res = 0;
539 out_unlock:
540 fat_unlock_creation();
541 return res;
543 mkdir_error:
544 printk("msdos_mkdir: error=%d, attempting cleanup\n", res);
545 bh = NULL;
546 fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY);
547 inode->i_nlink = 0;
548 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
549 dir->i_nlink--;
550 mark_inode_dirty(inode);
551 mark_inode_dirty(dir);
552 iput(inode);
553 de->name[0] = DELETED_FLAG;
554 fat_mark_buffer_dirty(sb, bh, 1);
555 fat_brelse(sb, bh);
556 goto out_unlock;
558 out_exist:
559 fat_brelse(sb, bh);
560 res = -EEXIST;
561 goto out_unlock;
564 /***** Unlink a file */
565 static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc)
567 struct super_block *sb = dir->i_sb;
568 struct inode *inode = dentry->d_inode;
569 int res,ino;
570 struct buffer_head *bh;
571 struct msdos_dir_entry *de;
573 bh = NULL;
574 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
575 &bh, &de, &ino);
576 if (res < 0)
577 goto unlink_done;
578 res = -EPERM;
579 if (!S_ISREG(inode->i_mode) && nospc)
580 goto unlink_done;
581 /* N.B. check for busy files? */
583 inode->i_nlink = 0;
584 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
585 MSDOS_I(inode)->i_busy = 1;
586 mark_inode_dirty(inode);
587 mark_inode_dirty(dir);
588 d_delete(dentry); /* This also frees the inode */
589 de->name[0] = DELETED_FLAG;
590 fat_mark_buffer_dirty(sb, bh, 1);
591 res = 0;
592 unlink_done:
593 fat_brelse(sb, bh);
594 return res;
597 /***** Unlink, as called for msdosfs */
598 int msdos_unlink(struct inode *dir,struct dentry *dentry)
600 return msdos_unlinkx (dir,dentry,1);
603 /***** Unlink, as called for umsdosfs */
604 int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry)
606 return msdos_unlinkx (dir,dentry,0);
609 #define MSDOS_CHECK_BUSY 1
611 /***** Rename within a directory */
612 static int msdos_rename_same(struct inode *old_dir,char *old_name,
613 struct dentry *old_dentry,
614 struct inode *new_dir,char *new_name,struct dentry *new_dentry,
615 struct buffer_head *old_bh,
616 struct msdos_dir_entry *old_de, int old_ino, int is_hid)
618 struct super_block *sb = old_dir->i_sb;
619 struct buffer_head *new_bh;
620 struct msdos_dir_entry *new_de;
621 struct inode *new_inode,*old_inode;
622 int new_ino, exists, error;
624 if (!strncmp(old_name, new_name, MSDOS_NAME))
625 goto set_hid;
626 error = -ENOENT;
627 if (*(unsigned char *) old_de->name == DELETED_FLAG)
628 goto out;
630 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
631 if (exists) {
632 error = -EIO;
633 new_inode = new_dentry->d_inode;
634 /* Make sure it really exists ... */
635 if (!new_inode) {
636 printk(KERN_ERR
637 "msdos_rename_same: %s/%s inode NULL, ino=%d\n",
638 new_dentry->d_parent->d_name.name,
639 new_dentry->d_name.name, new_ino);
640 d_drop(new_dentry);
641 goto out_error;
643 error = S_ISDIR(new_inode->i_mode)
644 ? (old_de->attr & ATTR_DIR)
645 ? msdos_empty(new_inode)
646 : -EPERM
647 : (old_de->attr & ATTR_DIR)
648 ? -EPERM
649 : 0;
650 if (error)
651 goto out_error;
652 error = -EPERM;
653 if ((old_de->attr & ATTR_SYS))
654 goto out_error;
656 if (S_ISDIR(new_inode->i_mode)) {
657 /* make sure it's empty */
658 error = msdos_empty(new_inode);
659 if (error)
660 goto out_error;
661 #ifdef MSDOS_CHECK_BUSY
662 /* check for a busy dentry */
663 error = -EBUSY;
664 shrink_dcache_parent(new_dentry);
665 if (new_dentry->d_count > 1) {
666 printk("msdos_rename_same: %s/%s busy, count=%d\n",
667 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
668 new_dentry->d_count);
669 goto out_error;
671 #endif
672 new_dir->i_nlink--;
673 mark_inode_dirty(new_dir);
675 new_inode->i_nlink = 0;
676 MSDOS_I(new_inode)->i_busy = 1;
677 mark_inode_dirty(new_inode);
679 * Make it negative if it's not busy;
680 * otherwise let d_move() drop it.
682 if (new_dentry->d_count == 1)
683 d_delete(new_dentry);
685 new_de->name[0] = DELETED_FLAG;
686 fat_mark_buffer_dirty(sb, new_bh, 1);
687 fat_brelse(sb, new_bh);
689 memcpy(old_de->name, new_name, MSDOS_NAME);
690 /* Update the dcache */
691 d_move(old_dentry, new_dentry);
692 set_hid:
693 old_de->attr = is_hid
694 ? (old_de->attr | ATTR_HIDDEN)
695 : (old_de->attr &~ ATTR_HIDDEN);
696 fat_mark_buffer_dirty(sb, old_bh, 1);
697 /* update binary info for conversion, i_attrs */
698 old_inode = old_dentry->d_inode;
699 MSDOS_I(old_inode)->i_attrs = is_hid
700 ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
701 : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
702 error = 0;
703 out:
704 return error;
706 out_error:
707 fat_brelse(sb, new_bh);
708 goto out;
711 /***** Rename across directories - a nonphysical move */
712 static int msdos_rename_diff(struct inode *old_dir, char *old_name,
713 struct dentry *old_dentry,
714 struct inode *new_dir,char *new_name, struct dentry *new_dentry,
715 struct buffer_head *old_bh,
716 struct msdos_dir_entry *old_de, int old_ino, int is_hid)
718 struct super_block *sb = old_dir->i_sb;
719 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
720 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
721 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode;
722 int new_ino,free_ino,dotdot_ino;
723 int error, exists;
725 error = -EINVAL;
726 if (old_ino == new_dir->i_ino)
727 goto out;
728 /* prevent moving directory below itself */
729 if (is_subdir(new_dentry, old_dentry))
730 goto out;
732 error = -ENOENT;
733 if (*(unsigned char *) old_de->name == DELETED_FLAG)
734 goto out;
736 /* find free spot */
737 while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de, &free_ino,
738 SCAN_ANY)) < 0) {
739 if (error != -ENOENT)
740 goto out;
741 error = fat_add_cluster(new_dir);
742 if (error)
743 goto out;
746 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
747 if (exists) { /* Trash the old file! */
748 error = -EIO;
749 new_inode = new_dentry->d_inode;
750 /* Make sure it really exists ... */
751 if (!new_inode) {
752 printk(KERN_ERR
753 "msdos_rename_diff: %s/%s inode NULL, ino=%d\n",
754 new_dentry->d_parent->d_name.name,
755 new_dentry->d_name.name, new_ino);
756 d_drop(new_dentry);
757 goto out_new;
759 error = S_ISDIR(new_inode->i_mode)
760 ? (old_de->attr & ATTR_DIR)
761 ? msdos_empty(new_inode)
762 : -EPERM
763 : (old_de->attr & ATTR_DIR)
764 ? -EPERM
765 : 0;
766 if (error)
767 goto out_new;
768 error = -EPERM;
769 if ((old_de->attr & ATTR_SYS))
770 goto out_new;
772 #ifdef MSDOS_CHECK_BUSY
773 /* check for a busy dentry */
774 error = -EBUSY;
775 if (new_dentry->d_count > 1) {
776 shrink_dcache_parent(new_dentry);
777 if (new_dentry->d_count > 1) {
778 printk("msdos_rename_diff: target %s/%s busy, count=%d\n",
779 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
780 new_dentry->d_count);
781 goto out_new;
784 #endif
785 if (S_ISDIR(new_inode->i_mode)) {
786 /* make sure it's empty */
787 error = msdos_empty(new_inode);
788 if (error)
789 goto out_new;
790 new_dir->i_nlink--;
791 mark_inode_dirty(new_dir);
793 new_inode->i_nlink = 0;
794 MSDOS_I(new_inode)->i_busy = 1;
795 mark_inode_dirty(new_inode);
797 * Make it negative if it's not busy;
798 * otherwise let d_move() drop it.
800 if (new_dentry->d_count == 1)
801 d_delete(new_dentry);
802 new_de->name[0] = DELETED_FLAG;
803 fat_mark_buffer_dirty(sb, new_bh, 1);
804 fat_brelse(sb, new_bh);
807 old_inode = old_dentry->d_inode;
808 /* Get the dotdot inode if we'll need it ... */
809 dotdot_bh = NULL;
810 dotdot_inode = NULL;
811 if (S_ISDIR(old_inode->i_mode)) {
812 error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
813 &dotdot_de, &dotdot_ino, SCAN_ANY);
814 if (error < 0) {
815 printk(KERN_WARNING
816 "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
817 old_dentry->d_parent->d_name.name,
818 old_dentry->d_name.name, error);
819 goto rename_done;
821 error = -EIO;
822 dotdot_inode = iget(sb, dotdot_ino);
823 if (!dotdot_inode)
824 goto out_dotdot;
827 /* get an inode for the new name */
828 memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
829 memcpy(free_de->name, new_name, MSDOS_NAME);
830 free_de->attr = is_hid
831 ? (free_de->attr|ATTR_HIDDEN)
832 : (free_de->attr&~ATTR_HIDDEN);
834 error = -EIO;
835 free_inode = iget(sb, free_ino);
836 if (!free_inode)
837 goto out_iput;
838 /* make sure it's not busy! */
839 if (MSDOS_I(free_inode)->i_busy)
840 printk(KERN_ERR "msdos_rename_diff: new inode %ld busy!\n",
841 (ino_t) free_ino);
842 if (!list_empty(&free_inode->i_dentry))
843 printk("msdos_rename_diff: free inode has aliases??\n");
844 msdos_read_inode(free_inode);
847 * Make sure the old dentry isn't busy,
848 * as we need to change inodes ...
850 error = -EBUSY;
851 if (old_dentry->d_count > 1) {
852 shrink_dcache_parent(old_dentry);
853 if (old_dentry->d_count > 1) {
854 printk("msdos_rename_diff: source %s/%s busy, count=%d\n",
855 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
856 old_dentry->d_count);
857 goto out_iput;
861 /* keep the inode for a bit ... */
862 old_inode->i_count++;
863 d_delete(old_dentry);
865 free_inode->i_mode = old_inode->i_mode;
866 free_inode->i_nlink = old_inode->i_nlink;
867 free_inode->i_size = old_inode->i_size;
868 free_inode->i_blocks = old_inode->i_blocks;
869 free_inode->i_mtime = old_inode->i_mtime;
870 free_inode->i_atime = old_inode->i_atime;
871 free_inode->i_ctime = old_inode->i_ctime;
872 MSDOS_I(free_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms;
874 MSDOS_I(free_inode)->i_start = MSDOS_I(old_inode)->i_start;
875 MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart;
876 MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs;
878 /* release the old inode's resources */
879 MSDOS_I(old_inode)->i_start = 0;
880 MSDOS_I(old_inode)->i_logstart = 0;
881 old_inode->i_nlink = 0;
884 * Install the new inode ...
886 d_instantiate(old_dentry, free_inode);
888 fat_mark_buffer_dirty(sb, free_bh, 1);
889 fat_cache_inval_inode(old_inode);
890 mark_inode_dirty(old_inode);
891 old_de->name[0] = DELETED_FLAG;
892 fat_mark_buffer_dirty(sb, old_bh, 1);
893 iput(old_inode);
895 /* a directory? */
896 if (dotdot_bh) {
897 MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
898 MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
899 dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
900 dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
901 old_dir->i_nlink--;
902 new_dir->i_nlink++;
903 /* no need to mark them dirty */
904 dotdot_inode->i_nlink = new_dir->i_nlink;
905 mark_inode_dirty(dotdot_inode);
906 iput(dotdot_inode);
907 fat_mark_buffer_dirty(sb, dotdot_bh, 1);
908 fat_brelse(sb, dotdot_bh);
911 /* Update the dcache */
912 d_move(old_dentry, new_dentry);
913 error = 0;
915 rename_done:
916 fat_brelse(sb, free_bh);
917 out:
918 return error;
920 out_iput:
921 free_de->name[0] = DELETED_FLAG;
923 * Don't mark free_bh as dirty. Both states
924 * are supposed to be equivalent.
926 iput(free_inode); /* may be NULL */
927 iput(dotdot_inode);
928 out_dotdot:
929 fat_brelse(sb, dotdot_bh);
930 goto rename_done;
931 out_new:
932 fat_brelse(sb, new_bh);
933 goto rename_done;
936 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
937 int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
938 struct inode *new_dir,struct dentry *new_dentry)
940 struct super_block *sb = old_dir->i_sb;
941 struct buffer_head *old_bh;
942 struct msdos_dir_entry *old_de;
943 int old_ino, error;
944 int is_hid,old_hid; /* if new file and old file are hidden */
945 char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
947 error = -EINVAL;
948 if (sb != new_dir->i_sb)
949 goto rename_done;
950 error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
951 old_dentry->d_name.name, old_dentry->d_name.len,
952 old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
953 if (error < 0)
954 goto rename_done;
955 error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
956 new_dentry->d_name.name, new_dentry->d_name.len,
957 new_msdos_name, 0,MSDOS_SB(sb)->options.dotsOK);
958 if (error < 0)
959 goto rename_done;
961 is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
962 old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
963 error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de,
964 &old_ino, old_hid?SCAN_HID:SCAN_NOTHID);
965 if (error < 0)
966 goto rename_done;
968 fat_lock_creation();
969 if (old_dir == new_dir)
970 error = msdos_rename_same(old_dir, old_msdos_name, old_dentry,
971 new_dir, new_msdos_name, new_dentry,
972 old_bh, old_de, (ino_t)old_ino, is_hid);
973 else
974 error = msdos_rename_diff(old_dir, old_msdos_name, old_dentry,
975 new_dir, new_msdos_name, new_dentry,
976 old_bh, old_de, (ino_t)old_ino, is_hid);
977 fat_unlock_creation();
978 fat_brelse(sb, old_bh);
980 rename_done:
981 return error;
985 /* The public inode operations for the msdos fs */
986 struct inode_operations msdos_dir_inode_operations = {
987 &fat_dir_operations, /* default directory file-ops */
988 msdos_create, /* create */
989 msdos_lookup, /* lookup */
990 NULL, /* link */
991 msdos_unlink, /* unlink */
992 NULL, /* symlink */
993 msdos_mkdir, /* mkdir */
994 msdos_rmdir, /* rmdir */
995 NULL, /* mknod */
996 msdos_rename, /* rename */
997 NULL, /* readlink */
998 NULL, /* follow_link */
999 NULL, /* readpage */
1000 NULL, /* writepage */
1001 NULL, /* bmap */
1002 NULL, /* truncate */
1003 NULL, /* permission */
1004 NULL, /* smap */
1005 NULL, /* updatepage */
1006 NULL, /* revalidate */
1010 void msdos_read_inode(struct inode *inode)
1012 fat_read_inode(inode, &msdos_dir_inode_operations);
1017 #ifdef MODULE
1018 int init_module(void)
1020 return init_msdos_fs();
1024 void cleanup_module(void)
1026 unregister_filesystem(&msdos_fs_type);
1029 #endif