This source file includes following definitions.
- vfat_put_super
- parse_options
- vfat_read_super
- check_stack
- dump_fat
- dump_de
- vfat_valid_longname
- vfat_valid_shortname
- vfat_format_name
- vfat_create_shortname
- vfat_find_free_slots
- xlate_to_uni
- vfat_fill_long_slots
- vfat_build_slots
- vfat_readdir_cb
- vfat_find
- vfat_lookup
- vfat_create_entry
- vfat_create
- vfat_create_a_dotdir
- vfat_create_dotdirs
- vfat_empty
- vfat_rmdir_free_ino
- vfat_unlink_free_ino
- vfat_remove_entry
- vfat_rmdirx
- vfat_rmdir
- vfat_unlinkx
- vfat_mkdir
- vfat_unlink
- vfat_rename
- vfat_read_inode
- init_vfat_fs
- init_module
- cleanup_module
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/module.h>
14
15 #include <linux/sched.h>
16 #include <linux/msdos_fs.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
20 #include <linux/stat.h>
21 #include <linux/mm.h>
22
23 #include <asm/segment.h>
24
25 #include "../fat/msbuffer.h"
26 #include "../fat/tables.h"
27
28 #if 0
29 # define PRINTK(x) printk x
30 #else
31 # define PRINTK(x)
32 #endif
33
34 #ifndef DEBUG
35 # define CHECK_STACK
36 #else
37 # define CHECK_STACK check_stack(__FILE__, __LINE__)
38 #endif
39
40
41
42
43
44 #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
45
46 struct vfat_find_info {
47 const char *name;
48 int len;
49 int new_filename;
50 int found;
51 int is_long;
52 off_t offset;
53 off_t short_offset;
54 int long_slots;
55 ino_t ino;
56 int posix;
57 };
58
59 void vfat_read_inode(struct inode *inode);
60
61 void vfat_put_super(struct super_block *sb)
62 {
63 fat_put_super(sb);
64 MOD_DEC_USE_COUNT;
65 }
66
67
68 static struct super_operations vfat_sops = {
69 vfat_read_inode,
70 fat_notify_change,
71 fat_write_inode,
72 fat_put_inode,
73 vfat_put_super,
74 NULL,
75 fat_statfs,
76 NULL
77 };
78
79 static int parse_options(char *options, struct fat_mount_options *opts)
80 {
81 char *this_char,*value,save,*savep;
82 int ret;
83
84 opts->unicode_xlate = opts->posixfs = 0;
85 opts->numtail = 1;
86
87 if (!options) return 1;
88 save = 0;
89 savep = NULL;
90 ret = 1;
91 for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
92 if ((value = strchr(this_char,'=')) != NULL) {
93 save = *value;
94 savep = value;
95 *value++ = 0;
96 }
97 if (!strcmp(this_char,"uni_xlate")) {
98 if (value) {
99 ret = 0;
100 } else {
101 opts->unicode_xlate = 1;
102 }
103 }
104 else if (!strcmp(this_char,"posix")) {
105 if (value) {
106 ret = 0;
107 } else {
108 opts->posixfs = 1;
109 }
110 }
111 else if (!strcmp(this_char,"nonumtail")) {
112 if (value) {
113 ret = 0;
114 } else {
115 opts->numtail = 0;
116 }
117 }
118 if (this_char != options)
119 *(this_char-1) = ',';
120 if (value) {
121 *savep = save;
122 }
123 if (ret == 0) {
124 return 0;
125 }
126 }
127 return 1;
128 }
129
130 struct super_block *vfat_read_super(struct super_block *sb,void *data,
131 int silent)
132 {
133 struct super_block *res;
134
135 MOD_INC_USE_COUNT;
136
137 sb->s_op = &vfat_sops;
138 res = fat_read_super(sb, data, silent);
139 if (res == NULL) {
140 sb->s_dev = 0;
141 MOD_DEC_USE_COUNT;
142 return NULL;
143 }
144
145 if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
146 MOD_DEC_USE_COUNT;
147 } else {
148 MSDOS_SB(sb)->options.isvfat = 1;
149 MSDOS_SB(sb)->options.dotsOK = 0;
150 }
151
152 return res;
153 }
154
155 #ifdef DEBUG
156
157 static void
158 check_stack(const char *fname, int lineno)
159 {
160 int stack_level;
161 char *pg_dir;
162
163 stack_level = (long)(&pg_dir)-current->kernel_stack_page;
164 if (stack_level < 0)
165 printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
166 fname, lineno, stack_level);
167 else if (stack_level < 500)
168 printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
169 fname, lineno, stack_level);
170 #if 0
171 else
172 printk("------- vfat kstack ok in %s line %d: SL=%d\n",
173 fname, lineno, stack_level);
174 #endif
175 if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
176 printk("******* vfat stack corruption detected in %s at line %d\n",
177 fname, lineno);
178 }
179 }
180
181 static int debug = 0;
182 static void dump_fat(struct super_block *sb,int start)
183 {
184 printk("[");
185 while (start) {
186 printk("%d ",start);
187 start = fat_access(sb,start,-1);
188 if (!start) {
189 printk("ERROR");
190 break;
191 }
192 if (start == -1) break;
193 }
194 printk("]\n");
195 }
196
197 static void dump_de(struct msdos_dir_entry *de)
198 {
199 int i;
200 unsigned char *p = (unsigned char *) de;
201 printk("[");
202
203 for (i = 0; i < 32; i++, p++) {
204 printk("%02x ", *p);
205 }
206 printk("]\n");
207 }
208
209 #endif
210
211
212
213 static const char *reserved_names[] = {
214 "CON ","PRN ","NUL ","AUX ",
215 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
216 "COM1 ","COM2 ","COM3 ","COM4 ",
217 NULL };
218
219
220
221
222 static char bad_chars[] = "*?<>|\":/\\";
223 static char bad_if_strict[] = "+=,; []";
224 static char replace_chars[] = "[];,+=";
225
226 static int vfat_find(struct inode *dir,const char *name,int len,
227 int find_long,int new_filename,int is_dir,
228 struct slot_info *sinfo_out);
229
230
231
232
233
234 static int vfat_valid_longname(const char *name, int len, int dot_dirs,
235 int xlate)
236 {
237 const char **reserved;
238 unsigned char c;
239 int i;
240
241 if (IS_FREE(name)) return -EINVAL;
242 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
243 if (!dot_dirs) return -EEXIST;
244 return 1;
245 }
246
247 if (len && name[len-1] == ' ') return -EINVAL;
248 if (len >= 256) return -EINVAL;
249 for (i = 0; i < len; i++) {
250 c = name[i];
251 if (xlate && c == ':') continue;
252 if (strchr(bad_chars,c)) {
253 return -EINVAL;
254 }
255 }
256 if (len == 3 || len == 4) {
257 for (reserved = reserved_names; *reserved; reserved++)
258 if (!strncmp(name,*reserved,8)) return -EINVAL;
259 }
260 return 0;
261 }
262
263 static int vfat_valid_shortname(char conv,const char *name,int len,
264 int dot_dirs)
265 {
266 const char *walk, **reserved;
267 unsigned char c;
268 int space;
269
270 if (IS_FREE(name)) return -EINVAL;
271 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
272 if (!dot_dirs) return -EEXIST;
273 return 1;
274 }
275
276 space = 1;
277 c = 0;
278 for (walk = name; len && walk-name < 8;) {
279 c = *walk++;
280 len--;
281 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
282 if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
283 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
284 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
285 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
286 if ((walk == name) && (c == 0xE5)) c = 0x05;
287 if (c == '.') break;
288 space = c == ' ';
289 }
290 if (space) return -EINVAL;
291 if ((conv == 's' || conv == 'x') && len && c != '.') {
292 c = *walk++;
293 len--;
294 if (c != '.') return -EINVAL;
295 }
296 while (c != '.' && len--) c = *walk++;
297 if (c == '.') {
298 if (len >= 4) return -EINVAL;
299 while (len > 0 && walk-name < (MSDOS_NAME+1)) {
300 c = *walk++;
301 len--;
302 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
303 if (conv == 's' && strchr(bad_if_strict,c))
304 return -EINVAL;
305 if (conv == 'x' && strchr(replace_chars,c))
306 return -EINVAL;
307 if (c < ' ' || c == ':' || c == '\\' || c == '.')
308 return -EINVAL;
309 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
310 space = c == ' ';
311 }
312 if (space) return -EINVAL;
313 if ((conv == 's' || conv == 'x') && len) return -EINVAL;
314 }
315 for (reserved = reserved_names; *reserved; reserved++)
316 if (!strncmp(name,*reserved,8)) return -EINVAL;
317
318 return 0;
319 }
320
321
322
323
324
325
326 static int vfat_format_name(char conv,const char *name,int len,char *res,
327 int dot_dirs)
328 {
329 char *walk;
330 const char **reserved;
331 unsigned char c;
332 int space;
333
334 if (IS_FREE(name)) return -EINVAL;
335 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
336 if (!dot_dirs) return -EEXIST;
337 memset(res+1,' ',10);
338 while (len--) *res++ = '.';
339 return 0;
340 }
341
342 space = 1;
343 c = 0;
344 for (walk = res; len && walk-res < 8; walk++) {
345 c = *name++;
346 len--;
347 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
348 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
349 if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
350 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
351 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
352 if (c == '.') break;
353 space = c == ' ';
354 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
355 }
356 if (space) return -EINVAL;
357 if ((conv == 's' || conv == 'x') && len && c != '.') {
358 c = *name++;
359 len--;
360 if (c != '.') return -EINVAL;
361 }
362 while (c != '.' && len--) c = *name++;
363 if (c == '.') {
364 while (walk-res < 8) *walk++ = ' ';
365 while (len > 0 && walk-res < MSDOS_NAME) {
366 c = *name++;
367 len--;
368 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
369 if (conv == 's' && strchr(bad_if_strict,c))
370 return -EINVAL;
371 if (conv == 'x' && strchr(replace_chars,c))
372 return -EINVAL;
373 if (c < ' ' || c == ':' || c == '\\' || c == '.')
374 return -EINVAL;
375 if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
376 space = c == ' ';
377 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
378 }
379 if (space) return -EINVAL;
380 if ((conv == 's' || conv == 'x') && len) return -EINVAL;
381 }
382 while (walk-res < MSDOS_NAME) *walk++ = ' ';
383 for (reserved = reserved_names; *reserved; reserved++)
384 if (!strncmp(res,*reserved,8)) return -EINVAL;
385
386 return 0;
387 }
388
389 static char skip_chars[] = ".:\"?<>| ";
390
391
392
393
394 static int vfat_create_shortname(struct inode *dir, const char *name,
395 int len, char *name_res)
396 {
397 const char *ip, *ext_start, *end;
398 char *p;
399 int sz, extlen, baselen, totlen;
400 char msdos_name[13];
401 char base[9], ext[4];
402 int i;
403 int res;
404 int spaces;
405 char buf[8];
406 struct slot_info sinfo;
407 const char *name_start;
408
409 PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
410 sz = 0;
411 if (len && name[len-1]==' ') return -EINVAL;
412 if (len <= 12) {
413
414
415 for (i = 0, p = msdos_name, ip = name; i < len; i++, p++, ip++)
416 {
417 if (*ip >= 'A' && *ip <= 'Z') {
418 *p = *ip + 32;
419 } else {
420 *p = *ip;
421 }
422 }
423 res = vfat_format_name('x', msdos_name, len, name_res, 1);
424 if (res > -1) {
425 PRINTK(("vfat_create_shortname 1\n"));
426 res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
427 PRINTK(("vfat_create_shortname 2\n"));
428 if (res > -1) return -EEXIST;
429 return 0;
430 }
431 }
432
433 PRINTK(("vfat_create_shortname 3\n"));
434
435 ext_start = end = &name[len];
436 while (--ext_start >= name) {
437 if (*ext_start == '.') {
438 if (ext_start == end - 1) {
439 sz = len;
440 ext_start = NULL;
441 }
442 break;
443 }
444 }
445 if (ext_start == name - 1) {
446 sz = len;
447 ext_start = NULL;
448 } else if (ext_start) {
449
450
451
452
453
454 name_start = &name[0];
455 while (name_start < ext_start)
456 {
457 if (!strchr(skip_chars,*name_start)) break;
458 name_start++;
459 }
460 if (name_start != ext_start) {
461 sz = ext_start - name;
462 ext_start++;
463 } else {
464 sz = len;
465 ext_start=NULL;
466 }
467 }
468
469 for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
470 {
471 if (!strchr(skip_chars, *ip)) {
472 if (*ip >= 'A' && *ip <= 'Z') {
473 *p = *ip + 32;
474 } else {
475 *p = *ip;
476 }
477 if (strchr(replace_chars, *p)) *p='_';
478 p++; baselen++;
479 }
480 ip++;
481 }
482 if (baselen == 0) {
483 return -EINVAL;
484 }
485
486 spaces = 8 - baselen;
487
488 if (ext_start) {
489 extlen = 0;
490 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
491 if (!strchr(skip_chars, *ip)) {
492 if (*ip >= 'A' && *ip <= 'Z') {
493 *p = *ip + 32;
494 } else {
495 *p = *ip;
496 }
497 if (strchr(replace_chars, *p)) *p='_';
498 extlen++;
499 p++;
500 }
501 }
502 } else {
503 extlen = 0;
504 }
505 ext[extlen] = '\0';
506 base[baselen] = '\0';
507
508 strcpy(msdos_name, base);
509 msdos_name[baselen] = '.';
510 strcpy(&msdos_name[baselen+1], ext);
511
512 totlen = baselen + extlen + (extlen > 0);
513 res = 0;
514 if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
515 res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
516 }
517 i = 0;
518 while (res > -1) {
519
520 i++;
521 if (i == 10000000) return -EEXIST;
522 sprintf(buf, "%d", i);
523 sz = strlen(buf);
524 if (sz + 1 > spaces) {
525 baselen = baselen - (sz + 1 - spaces);
526 spaces = sz + 1;
527 }
528
529 strncpy(msdos_name, base, baselen);
530 msdos_name[baselen] = '~';
531 strcpy(&msdos_name[baselen+1], buf);
532 msdos_name[baselen+sz+1] = '.';
533 strcpy(&msdos_name[baselen+sz+2], ext);
534
535 totlen = baselen + sz + 1 + extlen + (extlen > 0);
536 res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
537 }
538 res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
539 return res;
540 }
541
542 static loff_t vfat_find_free_slots(struct inode *dir,int slots)
543 {
544 struct super_block *sb = dir->i_sb;
545 loff_t offset, curr;
546 struct msdos_dir_entry *de;
547 struct buffer_head *bh;
548 struct inode *inode;
549 int ino;
550 int row;
551 int done;
552 int res;
553 int added;
554
555 PRINTK(("vfat_find_free_slots: find %d free slots\n", slots));
556 offset = curr = 0;
557 bh = NULL;
558 row = 0;
559 ino = fat_get_entry(dir,&curr,&bh,&de);
560
561 for (added = 0; added < 2; added++) {
562 while (ino > -1) {
563 done = IS_FREE(de->name);
564 if (done) {
565 inode = iget(sb,ino);
566 if (inode) {
567
568 done = !MSDOS_I(inode)->i_busy;
569
570 }
571 iput(inode);
572 }
573 if (done) {
574 row++;
575 if (row == slots) {
576 brelse(bh);
577
578 return offset;
579 }
580 } else {
581 row = 0;
582 offset = curr;
583 }
584 ino = fat_get_entry(dir,&curr,&bh,&de);
585 }
586
587 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
588 if ((res = fat_add_cluster(dir)) < 0) return res;
589 ino = fat_get_entry(dir,&curr,&bh,&de);
590 }
591 return -ENOSPC;
592 }
593
594
595 static int
596 xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
597 {
598 int i;
599 const unsigned char *ip;
600 char *op;
601 int fill;
602 unsigned char c1, c2, c3;
603
604 op = outname;
605 for (i = 0, ip = name, op = outname, *outlen = 0;
606 i < len && *outlen <= 260; i++, *outlen += 1)
607 {
608 if (escape && (i < len - 4) &&
609 (*ip == ':') &&
610 ((c1 = fat_code2uni[ip[1]]) != 255) &&
611 ((c2 = fat_code2uni[ip[2]]) != 255) &&
612 ((c3 = fat_code2uni[ip[3]]) != 255)) {
613 *op++ = (c1 << 4) + (c2 >> 2);
614 *op++ = ((c2 & 0x3) << 6) + c3;
615 ip += 4;
616 } else {
617 *op++ = fat_a2uni[*ip].uni1;
618 *op++ = fat_a2uni[*ip].uni2;
619 ip++;
620 }
621 }
622 if (*outlen > 260)
623 return -ENAMETOOLONG;
624
625 if (*outlen % 13) {
626 *op++ = 0;
627 *op++ = 0;
628 *outlen += 1;
629 if (*outlen % 13) {
630 fill = 13 - (*outlen % 13);
631 for (i = 0; i < fill; i++) {
632 *op++ = 0xff;
633 *op++ = 0xff;
634 }
635 *outlen += fill;
636 }
637 }
638
639 return 0;
640 }
641
642 static int
643 vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
644 char *msdos_name, int *slots, int uni_xlate)
645 {
646 struct msdos_dir_slot *ps;
647 struct msdos_dir_entry *de;
648 int res;
649 int slot;
650 unsigned char cksum;
651 char *uniname;
652 const char *ip;
653 unsigned long page;
654 int unilen;
655 int i;
656 loff_t offset;
657
658 if(!(page = __get_free_page(GFP_KERNEL)))
659 return -ENOMEM;
660 uniname = (char *) page;
661 res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate);
662 if (res < 0) {
663 free_page(page);
664 return res;
665 }
666
667 *slots = unilen / 13;
668 for (cksum = i = 0; i < 11; i++) {
669 cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
670 }
671 PRINTK(("vfat_fill_long_slots 3: slots=%d\n",*slots));
672
673 for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
674 int end, j;
675
676 PRINTK(("vfat_fill_long_slots 4\n"));
677 ps->id = slot;
678 ps->attr = ATTR_EXT;
679 ps->reserved = 0;
680 ps->alias_checksum = cksum;
681 ps->start[0] = 0;
682 ps->start[1] = 0;
683 PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
684 offset = (slot - 1) * 26;
685 ip = &uniname[offset];
686 j = offset;
687 end = 0;
688 for (i = 0; i < 10; i += 2) {
689 ps->name0_4[i] = *ip++;
690 ps->name0_4[i+1] = *ip++;
691 }
692 PRINTK(("vfat_fill_long_slots 6\n"));
693 for (i = 0; i < 12; i += 2) {
694 ps->name5_10[i] = *ip++;
695 ps->name5_10[i+1] = *ip++;
696 }
697 PRINTK(("vfat_fill_long_slots 7\n"));
698 for (i = 0; i < 4; i += 2) {
699 ps->name11_12[i] = *ip++;
700 ps->name11_12[i+1] = *ip++;
701 }
702 }
703 PRINTK(("vfat_fill_long_slots 8\n"));
704 ds[0].id |= 0x40;
705
706 de = (struct msdos_dir_entry *) ps;
707 PRINTK(("vfat_fill_long_slots 9\n"));
708 strncpy(de->name, msdos_name, MSDOS_NAME);
709
710 free_page(page);
711 return 0;
712 }
713
714 static int vfat_build_slots(struct inode *dir,const char *name,int len,
715 struct msdos_dir_slot *ds, int *slots, int *is_long)
716 {
717 struct msdos_dir_entry *de;
718 char msdos_name[MSDOS_NAME];
719 int res, xlate;
720
721 PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
722 de = (struct msdos_dir_entry *) ds;
723 xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
724
725 *slots = 1;
726 *is_long = 0;
727 if (len == 1 && name[0] == '.') {
728 strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
729 } else if (len == 2 && name[0] == '.' && name[1] == '.') {
730 strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
731 } else {
732 PRINTK(("vfat_build_slots 4\n"));
733 res = vfat_valid_shortname('x', name, len, 1);
734 if (res > -1) {
735 PRINTK(("vfat_build_slots 5a\n"));
736 res = vfat_format_name('x', name, len, de->name, 1);
737 PRINTK(("vfat_build_slots 5b\n"));
738 } else {
739 res = vfat_create_shortname(dir, name, len, msdos_name);
740 if (res < 0) {
741 return res;
742 }
743
744 res = vfat_valid_longname(name, len, 1, xlate);
745 if (res < 0) {
746 return res;
747 }
748
749 *is_long = 1;
750
751 return vfat_fill_long_slots(ds, name, len, msdos_name,
752 slots, xlate);
753 }
754 }
755 return 0;
756 }
757
758 static int vfat_readdir_cb(
759 filldir_t filldir,
760 void * buf,
761 const char * name,
762 int name_len,
763 int is_long,
764 off_t offset,
765 off_t short_offset,
766 int long_slots,
767 ino_t ino)
768 {
769 struct vfat_find_info *vf = (struct vfat_find_info *) buf;
770 const char *s1, *s2;
771 int i;
772
773 #ifdef DEBUG
774 if (debug) printk("cb: vf.name=%s, len=%d, name=%s, name_len=%d\n",
775 vf->name, vf->len, name, name_len);
776 #endif
777
778 if (vf->len != name_len) {
779 return 0;
780 }
781
782 s1 = name; s2 = vf->name;
783 for (i = 0; i < name_len; i++) {
784 if (vf->new_filename && !vf->posix) {
785 if (tolower(*s1) != tolower(*s2))
786 return 0;
787 } else {
788 if (*s1 != *s2)
789 return 0;
790 }
791 s1++; s2++;
792 }
793 vf->found = 1;
794 vf->is_long = is_long;
795 vf->offset = (offset == 2) ? 0 : offset;
796 vf->short_offset = (short_offset == 2) ? 0 : short_offset;
797 vf->long_slots = long_slots;
798 vf->ino = ino;
799 return -1;
800 }
801
802 static int vfat_find(struct inode *dir,const char *name,int len,
803 int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
804 {
805 struct super_block *sb = dir->i_sb;
806 struct vfat_find_info vf;
807 struct file fil;
808 struct buffer_head *bh;
809 struct msdos_dir_entry *de;
810 struct msdos_dir_slot *ps;
811 loff_t offset;
812 struct msdos_dir_slot ds[MSDOS_SLOTS];
813 int is_long;
814 int slots, slot;
815 int res;
816
817 PRINTK(("Entering vfat_find\n"));
818 fil.f_pos = 0;
819 vf.name = name;
820 vf.len = len;
821 vf.new_filename = new_filename;
822 vf.found = 0;
823 vf.posix = MSDOS_SB(sb)->options.posixfs;
824 res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
825 PRINTK(("vfat_find: Debug 1\n"));
826 if (res < 0) return res;
827 if (vf.found) {
828 if (new_filename) {
829 return -EEXIST;
830 }
831 sinfo_out->longname_offset = vf.offset;
832 sinfo_out->shortname_offset = vf.short_offset;
833 sinfo_out->is_long = vf.is_long;
834 sinfo_out->long_slots = vf.long_slots;
835 sinfo_out->total_slots = vf.long_slots + 1;
836 sinfo_out->ino = vf.ino;
837
838 PRINTK(("vfat_find: Debug 2\n"));
839 return 0;
840 }
841
842 PRINTK(("vfat_find: Debug 3\n"));
843 if (!vf.found && !new_filename)
844 return -ENOENT;
845
846 res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
847 if (res < 0) return res;
848
849 de = (struct msdos_dir_entry *) ds;
850
851 bh = NULL;
852 if (new_filename) {
853 PRINTK(("vfat_find: create file 1\n"));
854 if (is_long) slots++;
855 offset = vfat_find_free_slots(dir, slots);
856 if (offset < 0) {
857 return offset;
858 }
859
860 PRINTK(("vfat_find: create file 2\n"));
861
862 bh = NULL;
863 for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
864 PRINTK(("vfat_find: create file 3, slot=%d\n",slot));
865 sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
866 if (sinfo_out->ino < 0) {
867 PRINTK(("vfat_find: problem\n"));
868 return sinfo_out->ino;
869 }
870 memcpy(de, ps, sizeof(struct msdos_dir_slot));
871 mark_buffer_dirty(bh, 1);
872 }
873
874 PRINTK(("vfat_find: create file 4\n"));
875 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
876 dir->i_dirt = 1;
877
878 PRINTK(("vfat_find: create file 5\n"));
879
880 memset(de->unused, 0, sizeof(de->unused));
881 fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
882 de->ctime_ms = 0;
883 de->ctime = de->time;
884 de->adate = de->cdate = de->date;
885 de->start = 0;
886 de->size = 0;
887 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
888 de->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
889
890
891 mark_buffer_dirty(bh, 1);
892 brelse(bh);
893
894 sinfo_out->is_long = (slots > 1) ? 1 : 0;
895 if (sinfo_out->is_long) {
896 sinfo_out->long_slots = slots - 1;
897 } else {
898 sinfo_out->long_slots = 0;
899 }
900 sinfo_out->total_slots = slots;
901 sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
902 sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
903 return 0;
904 }
905
906 return -ENOENT;
907 }
908
909 int vfat_lookup(struct inode *dir,const char *name,int len,
910 struct inode **result)
911 {
912 int res, ino;
913 struct inode *next;
914 struct slot_info sinfo;
915
916 PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len));
917
918 *result = NULL;
919 if (!dir) return -ENOENT;
920 if (!S_ISDIR(dir->i_mode)) {
921 iput(dir);
922 return -ENOENT;
923 }
924 PRINTK (("vfat_lookup 2\n"));
925 if (len == 1 && name[0] == '.') {
926 *result = dir;
927 return 0;
928 }
929 if (len == 2 && name[0] == '.' && name[1] == '.') {
930 ino = fat_parent_ino(dir,0);
931 iput(dir);
932 if (ino < 0) return ino;
933 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
934 return 0;
935 }
936 if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) {
937 iput(dir);
938 if (!(*result = iget(dir->i_sb, ino)))
939 return -EACCES;
940 return 0;
941 }
942 PRINTK (("vfat_lookup 3\n"));
943 if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
944 iput(dir);
945 return res;
946 }
947 PRINTK (("vfat_lookup 4.5\n"));
948 if (!(*result = iget(dir->i_sb,sinfo.ino))) {
949 iput(dir);
950 return -EACCES;
951 }
952 PRINTK (("vfat_lookup 5\n"));
953 if (!(*result)->i_sb ||
954 ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
955
956 iput(dir);
957 return 0;
958 }
959 if (MSDOS_I(*result)->i_busy) {
960 iput(*result);
961 iput(dir);
962 return -ENOENT;
963 }
964 PRINTK (("vfat_lookup 6\n"));
965 while (MSDOS_I(*result)->i_old) {
966 next = MSDOS_I(*result)->i_old;
967 iput(*result);
968 if (!(*result = iget(next->i_sb,next->i_ino))) {
969 fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
970 iput(dir);
971 return -ENOENT;
972 }
973 }
974 iput(dir);
975 return 0;
976 }
977
978
979 static int vfat_create_entry(struct inode *dir,const char *name,int len,
980 int is_dir, struct inode **result)
981 {
982 struct super_block *sb = dir->i_sb;
983 int res,ino;
984 loff_t offset;
985 struct buffer_head *bh;
986 struct msdos_dir_entry *de;
987 struct slot_info sinfo;
988
989 PRINTK(("vfat_create_entry 1\n"));
990 res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo);
991 if (res < 0) {
992 return res;
993 }
994
995 offset = sinfo.shortname_offset;
996
997 PRINTK(("vfat_create_entry 2\n"));
998 bh = NULL;
999 ino = fat_get_entry(dir, &offset, &bh, &de);
1000 if (ino < 0) {
1001 PRINTK(("vfat_mkdir problem\n"));
1002 if (bh) brelse(bh);
1003 return ino;
1004 }
1005 PRINTK(("vfat_create_entry 3\n"));
1006
1007 if ((*result = iget(dir->i_sb,ino)) != NULL)
1008 vfat_read_inode(*result);
1009 brelse(bh);
1010 if (!*result) return -EIO;
1011 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
1012 CURRENT_TIME;
1013 (*result)->i_dirt = 1;
1014 (*result)->i_version = ++event;
1015 dir->i_version = event;
1016 dcache_add(dir, name, len, ino);
1017
1018 return 0;
1019 }
1020
1021 int vfat_create(struct inode *dir,const char *name,int len,int mode,
1022 struct inode **result)
1023 {
1024 int res;
1025
1026 if (!dir) return -ENOENT;
1027
1028 fat_lock_creation();
1029 res = vfat_create_entry(dir,name,len,0,result);
1030 if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
1031
1032 fat_unlock_creation();
1033 iput(dir);
1034 return res;
1035 }
1036
1037 static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
1038 struct buffer_head *bh,
1039 struct msdos_dir_entry *de,int ino,const char *name, int isdot)
1040 {
1041 struct super_block *sb = dir->i_sb;
1042 struct inode *dot;
1043
1044 PRINTK(("vfat_create_a_dotdir 1\n"));
1045
1046
1047
1048
1049 dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1050 dir->i_dirt = 1;
1051 memcpy(de->name,name,MSDOS_NAME);
1052 memset(de->unused, 0, sizeof(de->unused));
1053 de->lcase = 0;
1054 de->attr = ATTR_DIR;
1055 de->start = 0;
1056 fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
1057 de->ctime_ms = 0;
1058 de->ctime = de->time;
1059 de->adate = de->cdate = de->date;
1060 de->size = 0;
1061 mark_buffer_dirty(bh, 1);
1062 if ((dot = iget(dir->i_sb,ino)) != NULL)
1063 vfat_read_inode(dot);
1064 if (!dot) return -EIO;
1065 dot->i_mtime = dot->i_atime = CURRENT_TIME;
1066 dot->i_dirt = 1;
1067 if (isdot) {
1068 dot->i_size = dir->i_size;
1069 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
1070 dot->i_nlink = dir->i_nlink;
1071 } else {
1072 dot->i_size = parent->i_size;
1073 MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start;
1074 dot->i_nlink = parent->i_nlink;
1075 }
1076
1077 iput(dot);
1078
1079 PRINTK(("vfat_create_a_dotdir 2\n"));
1080 return 0;
1081 }
1082
1083 static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
1084 {
1085 struct super_block *sb = dir->i_sb;
1086 int res;
1087 struct buffer_head *bh;
1088 struct msdos_dir_entry *de;
1089 loff_t offset;
1090
1091 PRINTK(("vfat_create_dotdirs 1\n"));
1092 if ((res = fat_add_cluster(dir)) < 0) return res;
1093
1094 PRINTK(("vfat_create_dotdirs 2\n"));
1095 offset = 0;
1096 bh = NULL;
1097 if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) return res;
1098
1099 PRINTK(("vfat_create_dotdirs 3\n"));
1100 res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOT, 1);
1101 PRINTK(("vfat_create_dotdirs 4\n"));
1102 if (res < 0) {
1103 brelse(bh);
1104 return res;
1105 }
1106 PRINTK(("vfat_create_dotdirs 5\n"));
1107
1108 if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) {
1109 brelse(bh);
1110 return res;
1111 }
1112 PRINTK(("vfat_create_dotdirs 6\n"));
1113
1114 res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOTDOT, 0);
1115 PRINTK(("vfat_create_dotdirs 7\n"));
1116 brelse(bh);
1117
1118 return res;
1119 }
1120
1121
1122 static int vfat_empty(struct inode *dir)
1123 {
1124 struct super_block *sb = dir->i_sb;
1125 loff_t pos;
1126 struct buffer_head *bh;
1127 struct msdos_dir_entry *de;
1128
1129 if (dir->i_count > 1)
1130 return -EBUSY;
1131 if (MSDOS_I(dir)->i_start) {
1132 pos = 0;
1133 bh = NULL;
1134 while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
1135
1136 if (de->attr == ATTR_EXT) continue;
1137
1138 if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
1139 MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
1140 MSDOS_NAME)) {
1141 brelse(bh);
1142 return -ENOTEMPTY;
1143 }
1144 }
1145 if (bh)
1146 brelse(bh);
1147 }
1148 return 0;
1149 }
1150
1151 static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
1152 struct msdos_dir_entry *de,int ino)
1153 {
1154 struct super_block *sb = dir->i_sb;
1155 struct inode *inode;
1156 int res;
1157
1158 if (ino < 0) return -EINVAL;
1159 if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
1160 if (!S_ISDIR(inode->i_mode)) {
1161 iput(inode);
1162 return -ENOTDIR;
1163 }
1164 if (dir->i_dev != inode->i_dev || dir == inode) {
1165 iput(inode);
1166 return -EBUSY;
1167 }
1168 res = vfat_empty(inode);
1169 if (res) {
1170 iput(inode);
1171 return res;
1172 }
1173 inode->i_nlink = 0;
1174 inode->i_mtime = dir->i_mtime = CURRENT_TIME;
1175 inode->i_atime = dir->i_atime = CURRENT_TIME;
1176 dir->i_nlink--;
1177 inode->i_dirt = dir->i_dirt = 1;
1178 de->name[0] = DELETED_FLAG;
1179 mark_buffer_dirty(bh, 1);
1180 iput(inode);
1181
1182 return 0;
1183 }
1184
1185 static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
1186 struct msdos_dir_entry *de,int ino,int nospc)
1187 {
1188 struct super_block *sb = dir->i_sb;
1189 struct inode *inode;
1190 if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
1191 if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) {
1192 iput(inode);
1193 return -EPERM;
1194 }
1195 inode->i_nlink = 0;
1196 inode->i_mtime = dir->i_mtime = CURRENT_TIME;
1197 inode->i_atime = dir->i_atime = CURRENT_TIME;
1198 dir->i_version = ++event;
1199 MSDOS_I(inode)->i_busy = 1;
1200 inode->i_dirt = dir->i_dirt = 1;
1201 de->name[0] = DELETED_FLAG;
1202 mark_buffer_dirty(bh, 1);
1203
1204 iput(inode);
1205 return 0;
1206 }
1207
1208 static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
1209 struct buffer_head **bh,struct msdos_dir_entry **de,
1210 int is_dir,int nospc)
1211 {
1212 struct super_block *sb = dir->i_sb;
1213 loff_t offset;
1214 int res, i;
1215
1216
1217 offset = sinfo->shortname_offset;
1218 res = fat_get_entry(dir, &offset, bh, de);
1219 if (res < 0) return res;
1220 if (is_dir) {
1221 res = vfat_rmdir_free_ino(dir,*bh,*de,res);
1222 } else {
1223 res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc);
1224 }
1225 if (res < 0) return res;
1226
1227
1228 offset = sinfo->longname_offset;
1229 for (i = sinfo->long_slots; i > 0; --i) {
1230 res = fat_get_entry(dir, &offset, bh, de);
1231 if (res < 0) {
1232 printk("vfat_remove_entry: problem 1\n");
1233 continue;
1234 }
1235 (*de)->name[0] = DELETED_FLAG;
1236 (*de)->attr = 0;
1237 mark_buffer_dirty(*bh, 1);
1238 }
1239 return 0;
1240 }
1241
1242
1243 static int vfat_rmdirx(struct inode *dir,const char *name,int len)
1244 {
1245 struct super_block *sb = dir->i_sb;
1246 int res;
1247 struct buffer_head *bh;
1248 struct msdos_dir_entry *de;
1249 struct slot_info sinfo;
1250
1251 bh = NULL;
1252 res = -EPERM;
1253 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
1254 goto rmdir_done;
1255 res = vfat_find(dir,name,len,1,0,0,&sinfo);
1256
1257 if (res >= 0 && sinfo.total_slots > 0) {
1258 res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0);
1259 if (res > 0) {
1260 res = 0;
1261 }
1262 } else {
1263 printk("Problem in vfat_rmdirx\n");
1264 }
1265 dir->i_version = ++event;
1266
1267 rmdir_done:
1268 brelse(bh);
1269 return res;
1270 }
1271
1272
1273 int vfat_rmdir(struct inode *dir,const char *name,int len)
1274 {
1275 int res;
1276
1277 res = vfat_rmdirx(dir, name, len);
1278 iput(dir);
1279 return res;
1280 }
1281
1282 static int vfat_unlinkx(
1283 struct inode *dir,
1284 const char *name,
1285 int len,
1286 int nospc)
1287 {
1288 struct super_block *sb = dir->i_sb;
1289 int res;
1290 struct buffer_head *bh;
1291 struct msdos_dir_entry *de;
1292 struct slot_info sinfo;
1293
1294 bh = NULL;
1295 if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0)
1296 goto unlink_done;
1297
1298 if (res >= 0 && sinfo.total_slots > 0) {
1299 res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
1300 if (res > 0) {
1301 res = 0;
1302 }
1303 } else {
1304 printk("Problem in vfat_unlinkx: res=%d, total_slots=%d\n",res, sinfo.total_slots);
1305 }
1306
1307 unlink_done:
1308 brelse(bh);
1309 return res;
1310 }
1311
1312
1313 int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
1314 {
1315 struct inode *inode;
1316 int res;
1317
1318 fat_lock_creation();
1319 if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) {
1320 fat_unlock_creation();
1321 iput(dir);
1322 return res;
1323 }
1324
1325 dir->i_nlink++;
1326 inode->i_nlink = 2;
1327 MSDOS_I(inode)->i_busy = 1;
1328
1329 res = vfat_create_dotdirs(inode, dir);
1330 fat_unlock_creation();
1331 MSDOS_I(inode)->i_busy = 0;
1332 iput(inode);
1333 iput(dir);
1334 if (res < 0) {
1335 if (vfat_rmdir(dir,name,len) < 0)
1336 fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
1337 }
1338 return res;
1339 }
1340
1341
1342 int vfat_unlink(struct inode *dir,const char *name,int len)
1343 {
1344 int res;
1345
1346 res = vfat_unlinkx (dir,name,len,1);
1347 iput(dir);
1348 return res;
1349 }
1350
1351
1352 int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
1353 struct inode *new_dir,const char *new_name,int new_len)
1354 {
1355 struct super_block *sb = old_dir->i_sb;
1356 struct buffer_head *old_bh,*new_bh,*dotdot_bh;
1357 struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
1358 loff_t old_offset,new_offset,old_longname_offset;
1359 int old_slots,old_ino,new_ino,dotdot_ino,ino;
1360 struct inode *old_inode, *new_inode, *dotdot_inode, *walk;
1361 int res, is_dir, i;
1362 int locked = 0;
1363 struct slot_info sinfo;
1364
1365 PRINTK(("vfat_rename 1\n"));
1366 if (old_dir == new_dir && old_len == new_len &&
1367 strncmp(old_name, new_name, old_len) == 0)
1368 return 0;
1369
1370 old_bh = new_bh = NULL;
1371 old_inode = new_inode = NULL;
1372 res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo);
1373 PRINTK(("vfat_rename 2\n"));
1374 if (res < 0) goto rename_done;
1375
1376 old_slots = sinfo.total_slots;
1377 old_longname_offset = sinfo.longname_offset;
1378 old_offset = sinfo.shortname_offset;
1379 old_ino = sinfo.ino;
1380 res = fat_get_entry(old_dir, &old_offset, &old_bh, &old_de);
1381 PRINTK(("vfat_rename 3\n"));
1382 if (res < 0) goto rename_done;
1383
1384 if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done;
1385 is_dir = S_ISDIR(old_inode->i_mode);
1386 if (is_dir) {
1387 if ((old_dir->i_dev != new_dir->i_dev) ||
1388 (old_ino == new_dir->i_ino)) {
1389 res = -EINVAL;
1390 goto rename_done;
1391 }
1392 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
1393
1394 while (walk->i_ino != MSDOS_ROOT_INO) {
1395 ino = fat_parent_ino(walk,1);
1396 iput(walk);
1397 if (ino < 0) {
1398 res = ino;
1399 goto rename_done;
1400 }
1401 if (ino == old_ino) {
1402 res = -EINVAL;
1403 goto rename_done;
1404 }
1405 if (!(walk = iget(new_dir->i_sb,ino))) {
1406 res = -EIO;
1407 goto rename_done;
1408 }
1409 }
1410 iput(walk);
1411 }
1412
1413 res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo);
1414
1415 PRINTK(("vfat_rename 4\n"));
1416 if (res > -1) {
1417 int new_is_dir;
1418
1419 PRINTK(("vfat_rename 5\n"));
1420
1421 new_offset = sinfo.shortname_offset;
1422 res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
1423 PRINTK(("vfat_rename 6\n"));
1424 if (res < 0) goto rename_done;
1425
1426 if (!(new_inode = iget(new_dir->i_sb,res)))
1427 goto rename_done;
1428 new_is_dir = S_ISDIR(new_inode->i_mode);
1429 iput(new_inode);
1430 if (new_is_dir) {
1431 PRINTK(("vfat_rename 7\n"));
1432 res = vfat_rmdirx(new_dir,new_name,new_len);
1433 PRINTK(("vfat_rename 8\n"));
1434 if (res < 0) goto rename_done;
1435 } else {
1436 PRINTK(("vfat_rename 9\n"));
1437 res = vfat_unlinkx(new_dir,new_name,new_len,1);
1438 PRINTK(("vfat_rename 10\n"));
1439 if (res < 0) goto rename_done;
1440 }
1441 }
1442
1443 PRINTK(("vfat_rename 11\n"));
1444 fat_lock_creation(); locked = 1;
1445 res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo);
1446
1447 PRINTK(("vfat_rename 12\n"));
1448 if (res < 0) goto rename_done;
1449
1450 new_offset = sinfo.shortname_offset;
1451 new_ino = sinfo.ino;
1452 res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
1453 PRINTK(("vfat_rename 13\n"));
1454 if (res < 0) goto rename_done;
1455
1456 new_de->attr = old_de->attr;
1457 new_de->time = old_de->time;
1458 new_de->date = old_de->date;
1459 new_de->ctime_ms = old_de->ctime_ms;
1460 new_de->cdate = old_de->cdate;
1461 new_de->adate = old_de->adate;
1462 new_de->start = old_de->start;
1463 new_de->size = old_de->size;
1464
1465 if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done;
1466 PRINTK(("vfat_rename 14\n"));
1467
1468
1469
1470
1471
1472
1473
1474 vfat_read_inode(new_inode);
1475 MSDOS_I(old_inode)->i_busy = 1;
1476 MSDOS_I(old_inode)->i_linked = new_inode;
1477 MSDOS_I(new_inode)->i_oldlink = old_inode;
1478 fat_cache_inval_inode(old_inode);
1479 PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
1480 old_inode->i_dirt = 1;
1481 old_dir->i_version = ++event;
1482
1483
1484 for (i = old_slots; i > 0; --i) {
1485 res = fat_get_entry(old_dir, &old_longname_offset, &old_bh, &old_de);
1486 if (res < 0) {
1487 printk("vfat_unlinkx: problem 1\n");
1488 continue;
1489 }
1490 old_de->name[0] = DELETED_FLAG;
1491 old_de->attr = 0;
1492 mark_buffer_dirty(old_bh, 1);
1493 }
1494 PRINTK(("vfat_rename 15b\n"));
1495
1496 mark_buffer_dirty(new_bh, 1);
1497 dcache_add(new_dir, new_name, new_len, new_ino);
1498
1499
1500
1501
1502
1503
1504 if (S_ISDIR(old_inode->i_mode)) {
1505 if ((res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
1506 &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
1507 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
1508 brelse(dotdot_bh);
1509 res = -EIO;
1510 goto rename_done;
1511 }
1512 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
1513 MSDOS_I(new_dir)->i_start;
1514 dotdot_inode->i_dirt = 1;
1515 mark_buffer_dirty(dotdot_bh, 1);
1516 old_dir->i_nlink--;
1517 new_dir->i_nlink++;
1518
1519 dotdot_inode->i_nlink = new_dir->i_nlink;
1520 iput(dotdot_inode);
1521 brelse(dotdot_bh);
1522 }
1523
1524 if (res > 0) res = 0;
1525
1526 rename_done:
1527 if (locked) fat_unlock_creation();
1528 if (old_bh) brelse(old_bh);
1529 if (new_bh) brelse(new_bh);
1530 if (old_inode) iput(old_inode);
1531 iput(old_dir);
1532 iput(new_dir);
1533 return res;
1534 }
1535
1536
1537
1538
1539 struct inode_operations vfat_dir_inode_operations = {
1540 &fat_dir_operations,
1541 vfat_create,
1542 vfat_lookup,
1543 NULL,
1544 vfat_unlink,
1545 NULL,
1546 vfat_mkdir,
1547 vfat_rmdir,
1548 NULL,
1549 vfat_rename,
1550 NULL,
1551 NULL,
1552 NULL,
1553 NULL,
1554 fat_bmap,
1555 NULL,
1556 NULL
1557 };
1558
1559
1560 void vfat_read_inode(struct inode *inode)
1561 {
1562 fat_read_inode(inode, &vfat_dir_inode_operations);
1563 }
1564
1565
1566
1567
1568 static struct file_system_type vfat_fs_type = {
1569 vfat_read_super, "vfat", 1, NULL
1570 };
1571
1572 static struct symbol_table vfat_syms = {
1573 #include <linux/symtab_begin.h>
1574 X(vfat_create),
1575 X(vfat_unlink),
1576 X(vfat_mkdir),
1577 X(vfat_rmdir),
1578 X(vfat_rename),
1579 X(vfat_put_super),
1580 X(vfat_read_super),
1581 X(vfat_read_inode),
1582 X(vfat_lookup),
1583 #include <linux/symtab_end.h>
1584 };
1585
1586 int init_vfat_fs(void)
1587 {
1588 int status;
1589
1590 if ((status = register_filesystem(&vfat_fs_type)) == 0)
1591 status = register_symtab(&vfat_syms);
1592 return status;
1593 }
1594
1595 #ifdef MODULE
1596 int init_module(void)
1597 {
1598 return init_vfat_fs();
1599 }
1600
1601
1602 void cleanup_module(void)
1603 {
1604 unregister_filesystem(&vfat_fs_type);
1605 }
1606
1607 #endif
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626