Import 2.2.7
[davej-history.git] / fs / msdos / namei.c
blobdc9faa9a15a9ed69a401c9f2cc6863d361a97337
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 struct dentry *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 ERR_PTR(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);
331 if ((*result = iget(dir->i_sb,ino)) != NULL)
332 msdos_read_inode(*result);
333 fat_brelse(sb, bh);
334 if (!*result) return -EIO;
335 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
336 CURRENT_TIME;
337 mark_inode_dirty(*result);
338 return 0;
341 /***** Create a file or directory */
342 int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
344 struct super_block *sb = dir->i_sb;
345 struct buffer_head *bh;
346 struct msdos_dir_entry *de;
347 struct inode *inode;
348 int ino,res,is_hid;
349 char msdos_name[MSDOS_NAME];
351 res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
352 dentry->d_name.name,dentry->d_name.len,
353 msdos_name,0,
354 MSDOS_SB(sb)->options.dotsOK);
355 if (res < 0)
356 return res;
357 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
358 fat_lock_creation();
359 /* Scan for existing file twice, so that creating a file fails
360 * with -EINVAL if the other (dotfile/nondotfile) exists.
361 * Else SCAN_ANY would do. Maybe use EACCES, EBUSY, ENOSPC, ENFILE?
363 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
364 fat_unlock_creation();
365 fat_brelse(sb, bh);
366 return is_hid ? -EEXIST : -EINVAL;
368 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
369 fat_unlock_creation();
370 fat_brelse(sb, bh);
371 return is_hid ? -EINVAL : -EEXIST;
373 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),is_hid,
374 &inode);
375 fat_unlock_creation();
376 if (!res)
377 d_instantiate(dentry, inode);
378 return res;
382 #ifdef DEBUG
384 static void dump_fat(struct super_block *sb,int start)
386 printk("[");
387 while (start) {
388 printk("%d ",start);
389 start = fat_access(sb,start,-1);
390 if (!start) {
391 printk("ERROR");
392 break;
394 if (start == -1) break;
396 printk("]\n");
399 #endif
401 /***** See if directory is empty */
402 static int msdos_empty(struct inode *dir)
404 loff_t pos;
405 struct buffer_head *bh;
406 struct msdos_dir_entry *de;
407 int result = 0;
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 goto rmdir_done;
449 res = msdos_empty(inode);
450 if (res)
451 goto rmdir_done;
453 inode->i_nlink = 0;
454 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
455 dir->i_nlink--;
456 mark_inode_dirty(inode);
457 mark_inode_dirty(dir);
459 * Do the d_delete before any blocking operations.
460 * We must make a negative dentry, as the FAT code
461 * apparently relies on the inode being iput().
463 d_delete(dentry);
464 de->name[0] = DELETED_FLAG;
465 fat_mark_buffer_dirty(sb, bh, 1);
466 res = 0;
468 rmdir_done:
469 fat_brelse(sb, bh);
470 return res;
473 /***** Make a directory */
474 int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
476 struct super_block *sb = dir->i_sb;
477 struct buffer_head *bh;
478 struct msdos_dir_entry *de;
479 struct inode *inode,*dot;
480 int ino,res,is_hid;
481 char msdos_name[MSDOS_NAME];
483 res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
484 dentry->d_name.name,dentry->d_name.len,
485 msdos_name,0,
486 MSDOS_SB(sb)->options.dotsOK);
487 if (res < 0)
488 return res;
489 is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
490 fat_lock_creation();
491 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0)
492 goto out_exist;
494 res = msdos_create_entry(dir,msdos_name,1,is_hid, &inode);
495 if (res < 0)
496 goto out_unlock;
498 dir->i_nlink++;
499 inode->i_nlink = 2; /* no need to mark them dirty */
501 if ((res = fat_add_cluster(inode)) < 0)
502 goto mkdir_error;
503 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
504 goto mkdir_error;
505 dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
506 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
507 MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
508 dot->i_nlink = inode->i_nlink;
509 mark_inode_dirty(dot);
510 iput(dot);
512 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,0,&dot)) < 0)
513 goto mkdir_error;
514 dot->i_size = dir->i_size;
515 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
516 MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
517 dot->i_nlink = dir->i_nlink;
518 mark_inode_dirty(dot);
519 iput(dot);
520 d_instantiate(dentry, inode);
521 res = 0;
523 out_unlock:
524 fat_unlock_creation();
525 return res;
527 mkdir_error:
528 printk("msdos_mkdir: error=%d, attempting cleanup\n", res);
529 bh = NULL;
530 fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY);
531 inode->i_nlink = 0;
532 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
533 dir->i_nlink--;
534 mark_inode_dirty(inode);
535 mark_inode_dirty(dir);
536 iput(inode);
537 de->name[0] = DELETED_FLAG;
538 fat_mark_buffer_dirty(sb, bh, 1);
539 fat_brelse(sb, bh);
540 goto out_unlock;
542 out_exist:
543 fat_brelse(sb, bh);
544 res = -EEXIST;
545 goto out_unlock;
548 /***** Unlink a file */
549 static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc)
551 struct super_block *sb = dir->i_sb;
552 struct inode *inode = dentry->d_inode;
553 int res,ino;
554 struct buffer_head *bh;
555 struct msdos_dir_entry *de;
557 bh = NULL;
558 res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
559 &bh, &de, &ino);
560 if (res < 0)
561 goto unlink_done;
562 res = -EPERM;
563 if (!S_ISREG(inode->i_mode) && nospc)
564 goto unlink_done;
565 /* N.B. check for busy files? */
567 inode->i_nlink = 0;
568 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
569 MSDOS_I(inode)->i_busy = 1;
570 mark_inode_dirty(inode);
571 mark_inode_dirty(dir);
572 d_delete(dentry); /* This also frees the inode */
573 de->name[0] = DELETED_FLAG;
574 fat_mark_buffer_dirty(sb, bh, 1);
575 res = 0;
576 unlink_done:
577 fat_brelse(sb, bh);
578 return res;
581 /***** Unlink, as called for msdosfs */
582 int msdos_unlink(struct inode *dir,struct dentry *dentry)
584 return msdos_unlinkx (dir,dentry,1);
587 /***** Unlink, as called for umsdosfs */
588 int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry)
590 return msdos_unlinkx (dir,dentry,0);
593 /* Now we could merge it with msdos_rename_same. Later */
594 /***** Rename across directories - a nonphysical move */
595 static int do_msdos_rename(struct inode *old_dir, char *old_name,
596 struct dentry *old_dentry,
597 struct inode *new_dir,char *new_name, struct dentry *new_dentry,
598 struct buffer_head *old_bh,
599 struct msdos_dir_entry *old_de, int old_ino, int is_hid)
601 struct super_block *sb = old_dir->i_sb;
602 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
603 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
604 struct inode *old_inode,*new_inode,*dotdot_inode;
605 int new_ino,free_ino,dotdot_ino;
606 int error, exists;
608 old_inode = old_dentry->d_inode;
609 if (old_dir==new_dir && !strncmp(old_name, new_name, MSDOS_NAME))
610 goto set_hid;
611 error = -ENOENT;
612 if (*(unsigned char *) old_de->name == DELETED_FLAG)
613 goto out;
615 /* find free spot */
616 if (new_dir!=old_dir)
617 while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de,
618 &free_ino, SCAN_ANY)) < 0) {
619 if (error != -ENOENT)
620 goto out;
621 error = fat_add_cluster(new_dir);
622 if (error)
623 goto out;
626 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
627 if (exists) { /* Trash the old file! */
628 error = -EIO;
629 new_inode = new_dentry->d_inode;
630 /* Make sure it really exists ... */
631 if (!new_inode) {
632 printk(KERN_ERR
633 "msdos_rename: %s/%s inode NULL, ino=%d\n",
634 new_dentry->d_parent->d_name.name,
635 new_dentry->d_name.name, new_ino);
636 d_drop(new_dentry);
637 goto out_new;
639 error = -EPERM;
640 if ((old_de->attr & ATTR_SYS))
641 goto out_new;
643 if (S_ISDIR(new_inode->i_mode)) {
644 error = msdos_empty(new_inode);
645 if (error)
646 goto out_new;
647 new_dir->i_nlink--;
648 mark_inode_dirty(new_dir);
650 new_inode->i_nlink = 0;
651 MSDOS_I(new_inode)->i_busy = 1;
652 mark_inode_dirty(new_inode);
654 new_de->name[0] = DELETED_FLAG;
655 fat_mark_buffer_dirty(sb, new_bh, 1);
656 fat_brelse(sb, new_bh);
659 if (old_dir==new_dir) {
660 memcpy(old_de->name, new_name, MSDOS_NAME);
661 set_hid:
662 old_de->attr = is_hid
663 ? (old_de->attr | ATTR_HIDDEN)
664 : (old_de->attr &~ ATTR_HIDDEN);
665 fat_mark_buffer_dirty(sb, old_bh, 1);
666 MSDOS_I(old_inode)->i_attrs = is_hid
667 ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
668 : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
669 error = 0;
670 goto out;
673 /* Get the dotdot inode if we'll need it ... */
674 dotdot_bh = NULL;
675 dotdot_inode = NULL;
676 if (S_ISDIR(old_inode->i_mode)) {
677 error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
678 &dotdot_de, &dotdot_ino, SCAN_ANY);
679 if (error < 0) {
680 printk(KERN_WARNING
681 "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
682 old_dentry->d_parent->d_name.name,
683 old_dentry->d_name.name, error);
684 goto rename_done;
686 error = -EIO;
687 dotdot_inode = iget(sb, dotdot_ino);
688 if (!dotdot_inode)
689 goto out_dotdot;
693 * Potential race here. It will go away when we'll switch to
694 * sane inumbers (along with a frigging lot of other races).
697 /* set new entry */
698 memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
699 memcpy(free_de->name, new_name, MSDOS_NAME);
700 free_de->attr = is_hid
701 ? (free_de->attr|ATTR_HIDDEN)
702 : (free_de->attr&~ATTR_HIDDEN);
705 * Now the tricky part. We need to change i_ino. icache ignores
706 * i_ino for unhashed inodes, so we'll remove inode from hash,
707 * change what we want to change and reinsert it back. NB: we
708 * don't have to invalidate FAT cache here - all we need is to
709 * flip i_ino in relevant cache entries. Later.
711 remove_inode_hash(old_inode);
713 fat_cache_inval_inode(old_inode);
714 old_inode->i_version = ++event;
715 MSDOS_I(old_inode)->i_binary =
716 fat_is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
717 old_inode->i_ino = free_ino;
718 fat_mark_buffer_dirty(sb, free_bh, 1);
719 old_de->name[0] = DELETED_FLAG;
720 fat_mark_buffer_dirty(sb, old_bh, 1);
722 insert_inode_hash(old_inode);
724 /* a directory? */
725 if (dotdot_bh) {
726 MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
727 MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
728 dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
729 dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
730 old_dir->i_nlink--;
731 new_dir->i_nlink++;
732 /* no need to mark them dirty */
733 dotdot_inode->i_nlink = new_dir->i_nlink;
734 mark_inode_dirty(dotdot_inode);
735 iput(dotdot_inode);
736 fat_mark_buffer_dirty(sb, dotdot_bh, 1);
737 fat_brelse(sb, dotdot_bh);
740 error = 0;
742 rename_done:
743 fat_brelse(sb, free_bh);
744 out:
745 return error;
747 out_dotdot:
748 fat_brelse(sb, dotdot_bh);
749 goto rename_done;
750 out_new:
751 fat_brelse(sb, new_bh);
752 goto rename_done;
755 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
756 int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
757 struct inode *new_dir,struct dentry *new_dentry)
759 struct super_block *sb = old_dir->i_sb;
760 struct buffer_head *old_bh;
761 struct msdos_dir_entry *old_de;
762 int old_ino, error;
763 int is_hid,old_hid; /* if new file and old file are hidden */
764 char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
766 error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
767 old_dentry->d_name.name, old_dentry->d_name.len,
768 old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
769 if (error < 0)
770 goto rename_done;
771 error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
772 new_dentry->d_name.name, new_dentry->d_name.len,
773 new_msdos_name, 0,MSDOS_SB(sb)->options.dotsOK);
774 if (error < 0)
775 goto rename_done;
777 is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
778 old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
779 error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de,
780 &old_ino, old_hid?SCAN_HID:SCAN_NOTHID);
781 if (error < 0)
782 goto rename_done;
784 fat_lock_creation();
785 error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
786 new_dir, new_msdos_name, new_dentry,
787 old_bh, old_de, (ino_t)old_ino, is_hid);
788 fat_unlock_creation();
789 fat_brelse(sb, old_bh);
791 rename_done:
792 return error;
796 /* The public inode operations for the msdos fs */
797 struct inode_operations msdos_dir_inode_operations = {
798 &fat_dir_operations, /* default directory file-ops */
799 msdos_create, /* create */
800 msdos_lookup, /* lookup */
801 NULL, /* link */
802 msdos_unlink, /* unlink */
803 NULL, /* symlink */
804 msdos_mkdir, /* mkdir */
805 msdos_rmdir, /* rmdir */
806 NULL, /* mknod */
807 msdos_rename, /* rename */
808 NULL, /* readlink */
809 NULL, /* follow_link */
810 NULL, /* readpage */
811 NULL, /* writepage */
812 NULL, /* bmap */
813 NULL, /* truncate */
814 NULL, /* permission */
815 NULL, /* smap */
816 NULL, /* updatepage */
817 NULL, /* revalidate */
821 void msdos_read_inode(struct inode *inode)
823 fat_read_inode(inode, &msdos_dir_inode_operations);
828 #ifdef MODULE
829 int init_module(void)
831 return init_msdos_fs();
835 void cleanup_module(void)
837 unregister_filesystem(&msdos_fs_type);
840 #endif