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