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