This source file includes following definitions.
- msdos_put_super
- msdos_read_super
- msdos_format_name
- msdos_find
- msdos_lookup
- msdos_create_entry
- msdos_create
- dump_fat
- msdos_empty
- msdos_rmdir
- msdos_mkdir
- msdos_unlinkx
- msdos_unlink
- msdos_unlink_umsdos
- rename_same_dir
- rename_diff_dir
- msdos_rename
- msdos_read_inode
- init_module
- cleanup_module
1
2
3
4
5
6
7
8 #define __NO_VERSION__
9 #include <linux/module.h>
10
11 #include <linux/sched.h>
12 #include <linux/msdos_fs.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/stat.h>
17
18 #include <asm/segment.h>
19
20 #include "../fat/msbuffer.h"
21
22 #define PRINTK(x)
23
24
25
26
27 static const char *reserved_names[] = {
28 "CON ","PRN ","NUL ","AUX ",
29 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
30 "COM1 ","COM2 ","COM3 ","COM4 ",
31 NULL };
32
33
34
35
36 static char bad_chars[] = "*?<>|\"";
37 static char bad_if_strict[] = "+=,; ";
38
39
40 void msdos_put_super(struct super_block *sb)
41 {
42 fat_put_super(sb);
43 MOD_DEC_USE_COUNT;
44 }
45
46 struct super_operations msdos_sops = {
47 msdos_read_inode,
48 fat_notify_change,
49 fat_write_inode,
50 fat_put_inode,
51 msdos_put_super,
52 NULL,
53 fat_statfs,
54 NULL
55 };
56
57 struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
58 {
59 struct super_block *res;
60
61 MOD_INC_USE_COUNT;
62
63 sb->s_op = &msdos_sops;
64 res = fat_read_super(sb, data, silent);
65 if (res == NULL)
66 MOD_DEC_USE_COUNT;
67
68 return res;
69 }
70
71
72
73
74
75
76 static int msdos_format_name(char conv,const char *name,int len,
77 char *res,int dot_dirs,char dotsOK)
78
79
80
81
82 {
83 char *walk;
84 const char **reserved;
85 unsigned char c;
86 int space;
87
88 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
89 if (!dot_dirs) return -EEXIST;
90 memset(res+1,' ',10);
91 while (len--) *res++ = '.';
92 return 0;
93 }
94 if (name[0] == '.') {
95 if (!dotsOK) return -EINVAL;
96
97 name++; len--;
98 }
99 space = 1;
100 c = 0;
101 for (walk = res; len && walk-res < 8; walk++) {
102 c = *name++;
103 len--;
104 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
105 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
106 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
107 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
108
109
110
111
112 if((res==walk) && (c==0xE5)) c=0x05;
113 if (c == '.') break;
114 space = (c == ' ');
115 *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
116 }
117 if (space) return -EINVAL;
118 if (conv == 's' && len && c != '.') {
119 c = *name++;
120 len--;
121 if (c != '.') return -EINVAL;
122 }
123 while (c != '.' && len--) c = *name++;
124 if (c == '.') {
125 while (walk-res < 8) *walk++ = ' ';
126 while (len > 0 && walk-res < MSDOS_NAME) {
127 c = *name++;
128 len--;
129 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
130 if (conv == 's' && strchr(bad_if_strict,c))
131 return -EINVAL;
132 if (c < ' ' || c == ':' || c == '\\' || c == '.')
133 return -EINVAL;
134 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
135 space = c == ' ';
136 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
137 }
138 if (space) return -EINVAL;
139 if (conv == 's' && len) return -EINVAL;
140 }
141 while (walk-res < MSDOS_NAME) *walk++ = ' ';
142 for (reserved = reserved_names; *reserved; reserved++)
143 if (!strncmp(res,*reserved,8)) return -EINVAL;
144 return 0;
145 }
146
147
148
149 static int msdos_find(struct inode *dir,const char *name,int len,
150 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
151 {
152 char msdos_name[MSDOS_NAME];
153 int res;
154 char dotsOK;
155 char scantype;
156
157 dotsOK = MSDOS_SB(dir->i_sb)->dotsOK;
158 res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,
159 name,len, msdos_name,1,dotsOK);
160 if (res < 0)
161 return -ENOENT;
162 if((name[0]=='.') && dotsOK){
163 switch(len){
164 case 0: panic("Empty name in msdos_find!");
165 case 1: scantype = SCAN_ANY; break;
166 case 2: scantype = ((name[1]=='.')?SCAN_ANY:SCAN_HID); break;
167 default: scantype = SCAN_HID;
168 }
169 } else {
170 scantype = (dotsOK ? SCAN_NOTHID : SCAN_ANY);
171 }
172 return fat_scan(dir,msdos_name,bh,de,ino,scantype);
173 }
174
175
176 int msdos_lookup(struct inode *dir,const char *name,int len,
177 struct inode **result)
178 {
179 struct super_block *sb = dir->i_sb;
180 int ino,res;
181 struct msdos_dir_entry *de;
182 struct buffer_head *bh;
183 struct inode *next;
184
185 PRINTK (("msdos_lookup\n"));
186
187 *result = NULL;
188 if (!dir) return -ENOENT;
189 if (!S_ISDIR(dir->i_mode)) {
190 iput(dir);
191 return -ENOENT;
192 }
193 PRINTK (("msdos_lookup 2\n"));
194 if (len == 1 && name[0] == '.') {
195 *result = dir;
196 return 0;
197 }
198 if (len == 2 && name[0] == '.' && name[1] == '.') {
199 ino = fat_parent_ino(dir,0);
200 iput(dir);
201 if (ino < 0) return ino;
202 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
203 return 0;
204 }
205 #if 0
206 if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) {
207 iput(dir);
208 if (!(*result = iget(dir->i_sb, ino)))
209 return -EACCES;
210 return 0;
211 }
212 #endif
213 PRINTK (("msdos_lookup 3\n"));
214 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
215 iput(dir);
216 return res;
217 }
218 PRINTK (("msdos_lookup 4\n"));
219 if (bh) brelse(bh);
220 PRINTK (("msdos_lookup 4.5\n"));
221
222 if (!(*result = iget(dir->i_sb,ino))) {
223 iput(dir);
224 return -EACCES;
225 }
226 PRINTK (("msdos_lookup 5\n"));
227 if (!(*result)->i_sb ||
228 ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
229
230 iput(dir);
231 return 0;
232 }
233 if (MSDOS_I(*result)->i_busy) {
234 iput(*result);
235 iput(dir);
236 return -ENOENT;
237 }
238 PRINTK (("msdos_lookup 6\n"));
239 while (MSDOS_I(*result)->i_old) {
240 next = MSDOS_I(*result)->i_old;
241 iput(*result);
242 if (!(*result = iget(next->i_sb,next->i_ino))) {
243 fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
244 iput(dir);
245 return -ENOENT;
246 }
247 }
248 PRINTK (("msdos_lookup 7\n"));
249 iput(dir);
250 PRINTK (("msdos_lookup 8\n"));
251 return 0;
252 }
253
254
255
256 static int msdos_create_entry(struct inode *dir, const char *name,int len,
257 int is_dir, int is_hid, struct inode **result)
258 {
259 struct super_block *sb = dir->i_sb;
260 struct buffer_head *bh;
261 struct msdos_dir_entry *de;
262 int res,ino;
263
264 if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
265 if (res != -ENOENT) return res;
266 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
267 if ((res = fat_add_cluster(dir)) < 0) return res;
268 if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
269 }
270
271
272
273 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
274 dir->i_dirt = 1;
275 memcpy(de->name,name,MSDOS_NAME);
276 memset(de->unused, 0, sizeof(de->unused));
277 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
278 de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
279 de->start = 0;
280 fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
281 de->size = 0;
282 mark_buffer_dirty(bh, 1);
283 if ((*result = iget(dir->i_sb,ino)) != NULL)
284 msdos_read_inode(*result);
285 brelse(bh);
286 if (!*result) return -EIO;
287 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
288 CURRENT_TIME;
289 (*result)->i_dirt = 1;
290 dcache_add(dir, name, len, ino);
291 return 0;
292 }
293
294
295 int msdos_create(struct inode *dir,const char *name,int len,int mode,
296 struct inode **result)
297 {
298 struct super_block *sb = dir->i_sb;
299 struct buffer_head *bh;
300 struct msdos_dir_entry *de;
301 char msdos_name[MSDOS_NAME];
302 int ino,res,is_hid;
303
304 if (!dir) return -ENOENT;
305 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
306 msdos_name,0,MSDOS_SB(dir->i_sb)->dotsOK)) < 0) {
307 iput(dir);
308 return res;
309 }
310 is_hid = (name[0]=='.') && (msdos_name[0]!='.');
311 fat_lock_creation();
312
313
314
315
316 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
317 fat_unlock_creation();
318 brelse(bh);
319 iput(dir);
320 return is_hid ? -EEXIST : -EINVAL;
321 }
322 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
323 fat_unlock_creation();
324 brelse(bh);
325 iput(dir);
326 return is_hid ? -EINVAL : -EEXIST;
327 }
328 res = msdos_create_entry(dir,msdos_name,len,S_ISDIR(mode),is_hid,
329 result);
330 fat_unlock_creation();
331 iput(dir);
332 return res;
333 }
334
335
336 #ifdef DEBUG
337
338 static void dump_fat(struct super_block *sb,int start)
339 {
340 printk("[");
341 while (start) {
342 printk("%d ",start);
343 start = fat_access(sb,start,-1);
344 if (!start) {
345 printk("ERROR");
346 break;
347 }
348 if (start == -1) break;
349 }
350 printk("]\n");
351 }
352
353 #endif
354
355
356 static int msdos_empty(struct inode *dir)
357 {
358 struct super_block *sb = dir->i_sb;
359 loff_t pos;
360 struct buffer_head *bh;
361 struct msdos_dir_entry *de;
362
363 if (dir->i_count > 1)
364 return -EBUSY;
365 if (MSDOS_I(dir)->i_start) {
366 pos = 0;
367 bh = NULL;
368 while (fat_get_entry(dir,&pos,&bh,&de) > -1)
369 if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
370 MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
371 MSDOS_NAME)) {
372 brelse(bh);
373 return -ENOTEMPTY;
374 }
375 if (bh)
376 brelse(bh);
377 }
378 return 0;
379 }
380
381
382 int msdos_rmdir(struct inode *dir,const char *name,int len)
383 {
384 struct super_block *sb = dir->i_sb;
385 int res,ino;
386 struct buffer_head *bh;
387 struct msdos_dir_entry *de;
388 struct inode *inode;
389
390 bh = NULL;
391 inode = NULL;
392 res = -EPERM;
393 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
394 goto rmdir_done;
395 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
396 res = -ENOENT;
397 if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
398 res = -ENOTDIR;
399 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
400 res = -EBUSY;
401 if (dir->i_dev != inode->i_dev || dir == inode)
402 goto rmdir_done;
403 res = msdos_empty(inode);
404 if (res)
405 goto rmdir_done;
406 inode->i_nlink = 0;
407 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
408 dir->i_nlink--;
409 inode->i_dirt = dir->i_dirt = 1;
410 de->name[0] = DELETED_FLAG;
411 mark_buffer_dirty(bh, 1);
412 res = 0;
413 rmdir_done:
414 brelse(bh);
415 iput(dir);
416 iput(inode);
417 return res;
418 }
419
420
421 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
422 {
423 struct super_block *sb = dir->i_sb;
424 struct buffer_head *bh;
425 struct msdos_dir_entry *de;
426 struct inode *inode,*dot;
427 char msdos_name[MSDOS_NAME];
428 int ino,res,is_hid;
429
430 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
431 msdos_name,0,MSDOS_SB(dir->i_sb)->dotsOK)) < 0) {
432 iput(dir);
433 return res;
434 }
435 is_hid = (name[0]=='.') && (msdos_name[0]!='.');
436 fat_lock_creation();
437 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) {
438 fat_unlock_creation();
439 brelse(bh);
440 iput(dir);
441 return -EEXIST;
442 }
443 if ((res = msdos_create_entry(dir,msdos_name,len,1,is_hid,
444 &inode)) < 0) {
445 fat_unlock_creation();
446 iput(dir);
447 return res;
448 }
449 dir->i_nlink++;
450 inode->i_nlink = 2;
451 MSDOS_I(inode)->i_busy = 1;
452 if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error;
453 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,1,0,&dot)) < 0)
454 goto mkdir_error;
455 dot->i_size = inode->i_size;
456 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
457 dot->i_nlink = inode->i_nlink;
458 dot->i_dirt = 1;
459 iput(dot);
460 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
461 goto mkdir_error;
462 fat_unlock_creation();
463 dot->i_size = dir->i_size;
464 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
465 dot->i_nlink = dir->i_nlink;
466 dot->i_dirt = 1;
467 MSDOS_I(inode)->i_busy = 0;
468 iput(dot);
469 iput(inode);
470 iput(dir);
471 return 0;
472 mkdir_error:
473 iput(inode);
474 if (msdos_rmdir(dir,name,len) < 0)
475 fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
476 fat_unlock_creation();
477 return res;
478 }
479
480
481 static int msdos_unlinkx(
482 struct inode *dir,
483 const char *name,
484 int len,
485 int nospc)
486 {
487 struct super_block *sb = dir->i_sb;
488 int res,ino;
489 struct buffer_head *bh;
490 struct msdos_dir_entry *de;
491 struct inode *inode;
492
493 bh = NULL;
494 inode = NULL;
495 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
496 goto unlink_done;
497 if (!(inode = iget(dir->i_sb,ino))) {
498 res = -ENOENT;
499 goto unlink_done;
500 }
501 if (!S_ISREG(inode->i_mode) && nospc){
502 res = -EPERM;
503 goto unlink_done;
504 }
505 if (IS_IMMUTABLE(inode)){
506 res = -EPERM;
507 goto unlink_done;
508 }
509 inode->i_nlink = 0;
510 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
511 MSDOS_I(inode)->i_busy = 1;
512 inode->i_dirt = dir->i_dirt = 1;
513 de->name[0] = DELETED_FLAG;
514 mark_buffer_dirty(bh, 1);
515 unlink_done:
516 brelse(bh);
517 iput(inode);
518 iput(dir);
519 return res;
520 }
521
522
523 int msdos_unlink(struct inode *dir,const char *name,int len)
524 {
525 return msdos_unlinkx (dir,name,len,1);
526 }
527
528
529 int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
530 {
531 return msdos_unlinkx (dir,name,len,0);
532 }
533
534
535 static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
536 struct inode *new_dir,char *new_name,int new_len,
537 struct buffer_head *old_bh,
538 struct msdos_dir_entry *old_de,int old_ino,int is_hid)
539 {
540 struct super_block *sb = old_dir->i_sb;
541 struct buffer_head *new_bh;
542 struct msdos_dir_entry *new_de;
543 struct inode *new_inode,*old_inode;
544 int new_ino,exists,error;
545
546 if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid;
547 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
548 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
549 if (exists) brelse(new_bh);
550 return -ENOENT;
551 }
552 if (exists) {
553 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
554 brelse(new_bh);
555 return -EIO;
556 }
557 error = S_ISDIR(new_inode->i_mode)
558 ? (old_de->attr & ATTR_DIR)
559 ? msdos_empty(new_inode)
560 : -EPERM
561 : (old_de->attr & ATTR_DIR)
562 ? -EPERM
563 : 0;
564 if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
565 if (error) {
566 iput(new_inode);
567 brelse(new_bh);
568 return error;
569 }
570 if (S_ISDIR(new_inode->i_mode)) {
571 new_dir->i_nlink--;
572 new_dir->i_dirt = 1;
573 }
574 new_inode->i_nlink = 0;
575 MSDOS_I(new_inode)->i_busy = 1;
576 new_inode->i_dirt = 1;
577 new_de->name[0] = DELETED_FLAG;
578 mark_buffer_dirty(new_bh, 1);
579 dcache_add(new_dir, new_name, new_len, new_ino);
580 iput(new_inode);
581 brelse(new_bh);
582 }
583 memcpy(old_de->name,new_name,MSDOS_NAME);
584 set_hid:
585 old_de->attr = is_hid
586 ? (old_de->attr | ATTR_HIDDEN)
587 : (old_de->attr &~ ATTR_HIDDEN);
588 mark_buffer_dirty(old_bh, 1);
589
590 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
591 msdos_read_inode(old_inode);
592 MSDOS_I(old_inode)->i_attrs = is_hid
593 ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
594 : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
595 iput(old_inode);
596 }
597 return 0;
598 }
599
600
601 static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
602 struct inode *new_dir,char *new_name,int new_len,
603 struct buffer_head *old_bh,
604 struct msdos_dir_entry *old_de,int old_ino,int is_hid)
605 {
606 struct super_block *sb = old_dir->i_sb;
607 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
608 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
609 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
610 int new_ino,free_ino,dotdot_ino;
611 int error,exists,ino;
612
613 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
614 if (old_ino == new_dir->i_ino) return -EINVAL;
615 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
616
617 while (walk->i_ino != MSDOS_ROOT_INO) {
618 ino = fat_parent_ino(walk,1);
619 iput(walk);
620 if (ino < 0) return ino;
621 if (ino == old_ino) return -EINVAL;
622 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
623 }
624 iput(walk);
625
626 while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino,
627 SCAN_ANY)) < 0) {
628 if (error != -ENOENT) return error;
629 error = fat_add_cluster(new_dir);
630 if (error) return error;
631 }
632 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
633 if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
634 brelse(free_bh);
635 if (exists) brelse(new_bh);
636 return -EIO;
637 }
638 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
639 iput(old_inode);
640 brelse(free_bh);
641 if (exists) brelse(new_bh);
642 return -ENOENT;
643 }
644 new_inode = NULL;
645 if (exists) {
646 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
647 iput(old_inode);
648 brelse(new_bh);
649 return -EIO;
650 }
651 error = S_ISDIR(new_inode->i_mode)
652 ? (old_de->attr & ATTR_DIR)
653 ? msdos_empty(new_inode)
654 : -EPERM
655 : (old_de->attr & ATTR_DIR)
656 ? -EPERM
657 : 0;
658 if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
659 if (error) {
660 iput(new_inode);
661 iput(old_inode);
662 brelse(new_bh);
663 return error;
664 }
665 new_inode->i_nlink = 0;
666 MSDOS_I(new_inode)->i_busy = 1;
667 new_inode->i_dirt = 1;
668 new_de->name[0] = DELETED_FLAG;
669 mark_buffer_dirty(new_bh, 1);
670 }
671 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
672 memcpy(free_de->name,new_name,MSDOS_NAME);
673 free_de->attr = is_hid
674 ? (free_de->attr|ATTR_HIDDEN)
675 : (free_de->attr&~ATTR_HIDDEN);
676 if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
677 free_de->name[0] = DELETED_FLAG;
678
679 brelse(free_bh);
680 if (exists) {
681 iput(new_inode);
682 brelse(new_bh);
683 }
684 return -EIO;
685 }
686 if (exists && S_ISDIR(new_inode->i_mode)) {
687 new_dir->i_nlink--;
688 new_dir->i_dirt = 1;
689 }
690 msdos_read_inode(free_inode);
691 MSDOS_I(old_inode)->i_busy = 1;
692 fat_cache_inval_inode(old_inode);
693 old_inode->i_dirt = 1;
694 old_de->name[0] = DELETED_FLAG;
695 mark_buffer_dirty(old_bh, 1);
696 mark_buffer_dirty(free_bh, 1);
697 if (!exists) iput(free_inode);
698 else {
699 MSDOS_I(new_inode)->i_depend = free_inode;
700 MSDOS_I(free_inode)->i_old = new_inode;
701
702 iput(new_inode);
703 dcache_add(new_dir, new_name, new_len, new_ino);
704 brelse(new_bh);
705 }
706 if (S_ISDIR(old_inode->i_mode)) {
707 if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
708 &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
709 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
710 brelse(dotdot_bh);
711 error = -EIO;
712 goto rename_done;
713 }
714 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
715 MSDOS_I(new_dir)->i_start;
716 dotdot_inode->i_dirt = 1;
717 mark_buffer_dirty(dotdot_bh, 1);
718 old_dir->i_nlink--;
719 new_dir->i_nlink++;
720
721 dotdot_inode->i_nlink = new_dir->i_nlink;
722 iput(dotdot_inode);
723 brelse(dotdot_bh);
724 }
725 error = 0;
726 rename_done:
727 brelse(free_bh);
728 iput(old_inode);
729 return error;
730 }
731
732
733 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
734 struct inode *new_dir,const char *new_name,int new_len)
735 {
736 struct super_block *sb = old_dir->i_sb;
737 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
738 struct buffer_head *old_bh;
739 struct msdos_dir_entry *old_de;
740 int old_ino,error;
741 int is_hid,old_hid;
742
743 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
744 old_name,old_len,old_msdos_name,1,MSDOS_SB(old_dir->i_sb)->dotsOK))
745 < 0) goto rename_done;
746 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
747 new_name,new_len,new_msdos_name,0,MSDOS_SB(new_dir->i_sb)->dotsOK))
748 < 0) goto rename_done;
749 is_hid = (new_name[0]=='.') && (new_msdos_name[0]!='.');
750 old_hid = (old_name[0]=='.') && (old_msdos_name[0]!='.');
751 if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de,
752 &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done;
753 fat_lock_creation();
754 if (old_dir == new_dir)
755 error = rename_same_dir(old_dir,old_msdos_name,old_len,new_dir,
756 new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
757 else error = rename_diff_dir(old_dir,old_msdos_name,old_len,new_dir,
758 new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
759 fat_unlock_creation();
760 brelse(old_bh);
761 rename_done:
762 iput(old_dir);
763 iput(new_dir);
764 return error;
765 }
766
767
768
769 struct inode_operations msdos_dir_inode_operations = {
770 &fat_dir_operations,
771 msdos_create,
772 msdos_lookup,
773 NULL,
774 msdos_unlink,
775 NULL,
776 msdos_mkdir,
777 msdos_rmdir,
778 NULL,
779 msdos_rename,
780 NULL,
781 NULL,
782 NULL,
783 NULL,
784 fat_bmap,
785 NULL,
786 NULL
787 };
788
789
790 void msdos_read_inode(struct inode *inode)
791 {
792 fat_read_inode(inode, &msdos_dir_inode_operations);
793 }
794
795
796
797 #ifdef MODULE
798 int init_module(void)
799 {
800 return init_msdos_fs();
801 }
802
803
804 void cleanup_module(void)
805 {
806 unregister_filesystem(&msdos_fs_type);
807 }
808
809 #endif
810