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