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)->options.dotsOK;
158 res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.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)->options.name_check,
306 name,len,msdos_name,0,
307 MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
308 iput(dir);
309 return res;
310 }
311 is_hid = (name[0]=='.') && (msdos_name[0]!='.');
312 fat_lock_creation();
313
314
315
316
317 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
318 fat_unlock_creation();
319 brelse(bh);
320 iput(dir);
321 return is_hid ? -EEXIST : -EINVAL;
322 }
323 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
324 fat_unlock_creation();
325 brelse(bh);
326 iput(dir);
327 return is_hid ? -EINVAL : -EEXIST;
328 }
329 res = msdos_create_entry(dir,msdos_name,len,S_ISDIR(mode),is_hid,
330 result);
331 fat_unlock_creation();
332 iput(dir);
333 return res;
334 }
335
336
337 #ifdef DEBUG
338
339 static void dump_fat(struct super_block *sb,int start)
340 {
341 printk("[");
342 while (start) {
343 printk("%d ",start);
344 start = fat_access(sb,start,-1);
345 if (!start) {
346 printk("ERROR");
347 break;
348 }
349 if (start == -1) break;
350 }
351 printk("]\n");
352 }
353
354 #endif
355
356
357 static int msdos_empty(struct inode *dir)
358 {
359 struct super_block *sb = dir->i_sb;
360 loff_t pos;
361 struct buffer_head *bh;
362 struct msdos_dir_entry *de;
363
364 if (dir->i_count > 1)
365 return -EBUSY;
366 if (MSDOS_I(dir)->i_start) {
367 pos = 0;
368 bh = NULL;
369 while (fat_get_entry(dir,&pos,&bh,&de) > -1)
370 if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
371 MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
372 MSDOS_NAME)) {
373 brelse(bh);
374 return -ENOTEMPTY;
375 }
376 if (bh)
377 brelse(bh);
378 }
379 return 0;
380 }
381
382
383 int msdos_rmdir(struct inode *dir,const char *name,int len)
384 {
385 struct super_block *sb = dir->i_sb;
386 int res,ino;
387 struct buffer_head *bh;
388 struct msdos_dir_entry *de;
389 struct inode *inode;
390
391 bh = NULL;
392 inode = NULL;
393 res = -EPERM;
394 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
395 goto rmdir_done;
396 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
397 res = -ENOENT;
398 if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
399 res = -ENOTDIR;
400 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
401 res = -EBUSY;
402 if (dir->i_dev != inode->i_dev || dir == inode)
403 goto rmdir_done;
404 res = msdos_empty(inode);
405 if (res)
406 goto rmdir_done;
407 inode->i_nlink = 0;
408 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
409 dir->i_nlink--;
410 inode->i_dirt = dir->i_dirt = 1;
411 de->name[0] = DELETED_FLAG;
412 mark_buffer_dirty(bh, 1);
413 res = 0;
414 rmdir_done:
415 brelse(bh);
416 iput(dir);
417 iput(inode);
418 return res;
419 }
420
421
422 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
423 {
424 struct super_block *sb = dir->i_sb;
425 struct buffer_head *bh;
426 struct msdos_dir_entry *de;
427 struct inode *inode,*dot;
428 char msdos_name[MSDOS_NAME];
429 int ino,res,is_hid;
430
431 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
432 name,len,msdos_name,0,
433 MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
434 iput(dir);
435 return res;
436 }
437 is_hid = (name[0]=='.') && (msdos_name[0]!='.');
438 fat_lock_creation();
439 if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) {
440 fat_unlock_creation();
441 brelse(bh);
442 iput(dir);
443 return -EEXIST;
444 }
445 if ((res = msdos_create_entry(dir,msdos_name,len,1,is_hid,
446 &inode)) < 0) {
447 fat_unlock_creation();
448 iput(dir);
449 return res;
450 }
451 dir->i_nlink++;
452 inode->i_nlink = 2;
453 MSDOS_I(inode)->i_busy = 1;
454 if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error;
455 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,1,0,&dot)) < 0)
456 goto mkdir_error;
457 dot->i_size = inode->i_size;
458 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
459 dot->i_nlink = inode->i_nlink;
460 dot->i_dirt = 1;
461 iput(dot);
462 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
463 goto mkdir_error;
464 fat_unlock_creation();
465 dot->i_size = dir->i_size;
466 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
467 dot->i_nlink = dir->i_nlink;
468 dot->i_dirt = 1;
469 MSDOS_I(inode)->i_busy = 0;
470 iput(dot);
471 iput(inode);
472 iput(dir);
473 return 0;
474 mkdir_error:
475 iput(inode);
476 if (msdos_rmdir(dir,name,len) < 0)
477 fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
478 fat_unlock_creation();
479 return res;
480 }
481
482
483 static int msdos_unlinkx(
484 struct inode *dir,
485 const char *name,
486 int len,
487 int nospc)
488 {
489 struct super_block *sb = dir->i_sb;
490 int res,ino;
491 struct buffer_head *bh;
492 struct msdos_dir_entry *de;
493 struct inode *inode;
494
495 bh = NULL;
496 inode = NULL;
497 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
498 goto unlink_done;
499 if (!(inode = iget(dir->i_sb,ino))) {
500 res = -ENOENT;
501 goto unlink_done;
502 }
503 if (!S_ISREG(inode->i_mode) && nospc){
504 res = -EPERM;
505 goto unlink_done;
506 }
507 if (IS_IMMUTABLE(inode)){
508 res = -EPERM;
509 goto unlink_done;
510 }
511 inode->i_nlink = 0;
512 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
513 MSDOS_I(inode)->i_busy = 1;
514 inode->i_dirt = dir->i_dirt = 1;
515 de->name[0] = DELETED_FLAG;
516 mark_buffer_dirty(bh, 1);
517 unlink_done:
518 brelse(bh);
519 iput(inode);
520 iput(dir);
521 return res;
522 }
523
524
525 int msdos_unlink(struct inode *dir,const char *name,int len)
526 {
527 return msdos_unlinkx (dir,name,len,1);
528 }
529
530
531 int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
532 {
533 return msdos_unlinkx (dir,name,len,0);
534 }
535
536
537 static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
538 struct inode *new_dir,char *new_name,int new_len,
539 struct buffer_head *old_bh,
540 struct msdos_dir_entry *old_de,int old_ino,int is_hid)
541 {
542 struct super_block *sb = old_dir->i_sb;
543 struct buffer_head *new_bh;
544 struct msdos_dir_entry *new_de;
545 struct inode *new_inode,*old_inode;
546 int new_ino,exists,error;
547
548 if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid;
549 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
550 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
551 if (exists) brelse(new_bh);
552 return -ENOENT;
553 }
554 if (exists) {
555 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
556 brelse(new_bh);
557 return -EIO;
558 }
559 error = S_ISDIR(new_inode->i_mode)
560 ? (old_de->attr & ATTR_DIR)
561 ? msdos_empty(new_inode)
562 : -EPERM
563 : (old_de->attr & ATTR_DIR)
564 ? -EPERM
565 : 0;
566 if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
567 if (error) {
568 iput(new_inode);
569 brelse(new_bh);
570 return error;
571 }
572 if (S_ISDIR(new_inode->i_mode)) {
573 new_dir->i_nlink--;
574 new_dir->i_dirt = 1;
575 }
576 new_inode->i_nlink = 0;
577 MSDOS_I(new_inode)->i_busy = 1;
578 new_inode->i_dirt = 1;
579 new_de->name[0] = DELETED_FLAG;
580 mark_buffer_dirty(new_bh, 1);
581 dcache_add(new_dir, new_name, new_len, new_ino);
582 iput(new_inode);
583 brelse(new_bh);
584 }
585 memcpy(old_de->name,new_name,MSDOS_NAME);
586 set_hid:
587 old_de->attr = is_hid
588 ? (old_de->attr | ATTR_HIDDEN)
589 : (old_de->attr &~ ATTR_HIDDEN);
590 mark_buffer_dirty(old_bh, 1);
591
592 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
593 MSDOS_I(old_inode)->i_attrs = is_hid
594 ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
595 : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
596 iput(old_inode);
597 }
598 return 0;
599 }
600
601
602 static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
603 struct inode *new_dir,char *new_name,int new_len,
604 struct buffer_head *old_bh,
605 struct msdos_dir_entry *old_de,int old_ino,int is_hid)
606 {
607 struct super_block *sb = old_dir->i_sb;
608 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
609 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
610 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
611 int new_ino,free_ino,dotdot_ino;
612 int error,exists,ino;
613
614 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
615 if (old_ino == new_dir->i_ino) return -EINVAL;
616 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
617
618 while (walk->i_ino != MSDOS_ROOT_INO) {
619 ino = fat_parent_ino(walk,1);
620 iput(walk);
621 if (ino < 0) return ino;
622 if (ino == old_ino) return -EINVAL;
623 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
624 }
625 iput(walk);
626
627 while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino,
628 SCAN_ANY)) < 0) {
629 if (error != -ENOENT) return error;
630 error = fat_add_cluster(new_dir);
631 if (error) return error;
632 }
633 exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
634 if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
635 brelse(free_bh);
636 if (exists) brelse(new_bh);
637 return -EIO;
638 }
639 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
640 iput(old_inode);
641 brelse(free_bh);
642 if (exists) brelse(new_bh);
643 return -ENOENT;
644 }
645 new_inode = NULL;
646 if (exists) {
647 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
648 iput(old_inode);
649 brelse(new_bh);
650 return -EIO;
651 }
652 error = S_ISDIR(new_inode->i_mode)
653 ? (old_de->attr & ATTR_DIR)
654 ? msdos_empty(new_inode)
655 : -EPERM
656 : (old_de->attr & ATTR_DIR)
657 ? -EPERM
658 : 0;
659 if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
660 if (error) {
661 iput(new_inode);
662 iput(old_inode);
663 brelse(new_bh);
664 return error;
665 }
666 new_inode->i_nlink = 0;
667 MSDOS_I(new_inode)->i_busy = 1;
668 new_inode->i_dirt = 1;
669 new_de->name[0] = DELETED_FLAG;
670 mark_buffer_dirty(new_bh, 1);
671 }
672 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
673 memcpy(free_de->name,new_name,MSDOS_NAME);
674 free_de->attr = is_hid
675 ? (free_de->attr|ATTR_HIDDEN)
676 : (free_de->attr&~ATTR_HIDDEN);
677 if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
678 free_de->name[0] = DELETED_FLAG;
679
680 brelse(free_bh);
681 if (exists) {
682 iput(new_inode);
683 brelse(new_bh);
684 }
685 return -EIO;
686 }
687 if (exists && S_ISDIR(new_inode->i_mode)) {
688 new_dir->i_nlink--;
689 new_dir->i_dirt = 1;
690 }
691 msdos_read_inode(free_inode);
692 MSDOS_I(old_inode)->i_busy = 1;
693 MSDOS_I(old_inode)->i_linked = free_inode;
694 MSDOS_I(free_inode)->i_oldlink = old_inode;
695 fat_cache_inval_inode(old_inode);
696 old_inode->i_dirt = 1;
697 old_de->name[0] = DELETED_FLAG;
698 mark_buffer_dirty(old_bh, 1);
699 mark_buffer_dirty(free_bh, 1);
700 if (exists) {
701 MSDOS_I(new_inode)->i_depend = free_inode;
702 MSDOS_I(free_inode)->i_old = new_inode;
703
704 free_inode->i_count++;
705
706 iput(new_inode);
707 dcache_add(new_dir, new_name, new_len, new_ino);
708 brelse(new_bh);
709 }
710 if (S_ISDIR(old_inode->i_mode)) {
711 if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
712 &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
713 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
714 brelse(dotdot_bh);
715 error = -EIO;
716 goto rename_done;
717 }
718 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
719 MSDOS_I(new_dir)->i_start;
720 dotdot_inode->i_dirt = 1;
721 mark_buffer_dirty(dotdot_bh, 1);
722 old_dir->i_nlink--;
723 new_dir->i_nlink++;
724
725 dotdot_inode->i_nlink = new_dir->i_nlink;
726 iput(dotdot_inode);
727 brelse(dotdot_bh);
728 }
729 error = 0;
730 rename_done:
731 brelse(free_bh);
732 iput(old_inode);
733 return error;
734 }
735
736
737 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
738 struct inode *new_dir,const char *new_name,int new_len)
739 {
740 struct super_block *sb = old_dir->i_sb;
741 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
742 struct buffer_head *old_bh;
743 struct msdos_dir_entry *old_de;
744 int old_ino,error;
745 int is_hid,old_hid;
746
747 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check,
748 old_name,old_len,old_msdos_name,1,
749 MSDOS_SB(old_dir->i_sb)->options.dotsOK))
750 < 0) goto rename_done;
751 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check,
752 new_name,new_len,new_msdos_name,0,
753 MSDOS_SB(new_dir->i_sb)->options.dotsOK))
754 < 0) goto rename_done;
755 is_hid = (new_name[0]=='.') && (new_msdos_name[0]!='.');
756 old_hid = (old_name[0]=='.') && (old_msdos_name[0]!='.');
757 if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de,
758 &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done;
759 fat_lock_creation();
760 if (old_dir == new_dir)
761 error = rename_same_dir(old_dir,old_msdos_name,old_len,new_dir,
762 new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
763 else error = rename_diff_dir(old_dir,old_msdos_name,old_len,new_dir,
764 new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
765 fat_unlock_creation();
766 brelse(old_bh);
767 rename_done:
768 iput(old_dir);
769 iput(new_dir);
770 return error;
771 }
772
773
774
775 struct inode_operations msdos_dir_inode_operations = {
776 &fat_dir_operations,
777 msdos_create,
778 msdos_lookup,
779 NULL,
780 msdos_unlink,
781 NULL,
782 msdos_mkdir,
783 msdos_rmdir,
784 NULL,
785 msdos_rename,
786 NULL,
787 NULL,
788 NULL,
789 NULL,
790 fat_bmap,
791 NULL,
792 NULL
793 };
794
795
796 void msdos_read_inode(struct inode *inode)
797 {
798 fat_read_inode(inode, &msdos_dir_inode_operations);
799 }
800
801
802
803 #ifdef MODULE
804 int init_module(void)
805 {
806 return init_msdos_fs();
807 }
808
809
810 void cleanup_module(void)
811 {
812 unregister_filesystem(&msdos_fs_type);
813 }
814
815 #endif
816