File: /usr/src/linux/fs/fat/dir.c
1 /*
2 * linux/fs/fat/dir.c
3 *
4 * directory handling functions for fat-based filesystems
5 *
6 * Written 1992,1993 by Werner Almesberger
7 *
8 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
9 *
10 * VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
11 * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
12 * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
13 * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
14 */
15
16 #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
17
18 #include <linux/version.h>
19 #include <linux/fs.h>
20 #include <linux/msdos_fs.h>
21 #include <linux/nls.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/stat.h>
25 #include <linux/string.h>
26 #include <linux/ioctl.h>
27 #include <linux/dirent.h>
28 #include <linux/mm.h>
29 #include <linux/ctype.h>
30
31 #include <asm/uaccess.h>
32
33 #include "msbuffer.h"
34
35 #define PRINTK(X)
36
37 struct file_operations fat_dir_operations = {
38 read: generic_read_dir,
39 readdir: fat_readdir,
40 ioctl: fat_dir_ioctl,
41 fsync: file_fsync,
42 };
43
44 /*
45 * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
46 * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
47 * colon as an escape character since it is normally invalid on the vfat
48 * filesystem. The following four characters are the hexadecimal digits
49 * of Unicode value. This lets us do a full dump and restore of Unicode
50 * filenames. We could get into some trouble with long Unicode names,
51 * but ignore that right now.
52 * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
53 */
54 static int
55 uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
56 struct nls_table *nls)
57 {
58 wchar_t *ip, ec;
59 unsigned char *op, nc;
60 int charlen;
61 int k;
62
63 ip = uni;
64 op = ascii;
65
66 while (*ip) {
67 ec = *ip++;
68 if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
69 op += charlen;
70 } else {
71 if (uni_xlate == 1) {
72 *op = ':';
73 for (k = 4; k > 0; k--) {
74 nc = ec & 0xF;
75 op[k] = nc > 9 ? nc + ('a' - 10)
76 : nc + '0';
77 ec >>= 4;
78 }
79 op += 5;
80 } else {
81 *op++ = '?';
82 }
83 }
84 /* We have some slack there, so it's OK */
85 if (op>ascii+256) {
86 op = ascii + 256;
87 break;
88 }
89 }
90 *op = 0;
91 return (op - ascii);
92 }
93
94 #if 0
95 static void dump_de(struct msdos_dir_entry *de)
96 {
97 int i;
98 unsigned char *p = (unsigned char *) de;
99 printk("[");
100
101 for (i = 0; i < 32; i++, p++) {
102 printk("%02x ", *p);
103 }
104 printk("]\n");
105 }
106 #endif
107
108 static inline unsigned char
109 fat_tolower(struct nls_table *t, unsigned char c)
110 {
111 unsigned char nc = t->charset2lower[c];
112
113 return nc ? nc : c;
114 }
115
116 static inline int
117 fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
118 {
119 int charlen;
120
121 charlen = t->char2uni(c, clen, uni);
122 if (charlen < 0) {
123 *uni = 0x003f; /* a question mark */
124 charlen = 1;
125 }
126 return charlen;
127 }
128
129 static inline int
130 fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
131 {
132 int charlen;
133 wchar_t wc;
134
135 charlen = t->char2uni(c, clen, &wc);
136 if (charlen < 0) {
137 *uni = 0x003f; /* a question mark */
138 charlen = 1;
139 } else if (charlen <= 1) {
140 unsigned char nc = t->charset2lower[*c];
141
142 if (!nc)
143 nc = *c;
144
145 if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) {
146 *uni = 0x003f; /* a question mark */
147 charlen = 1;
148 }
149 } else
150 *uni = wc;
151
152 return charlen;
153 }
154
155 static int
156 fat_strnicmp(struct nls_table *t, const unsigned char *s1,
157 const unsigned char *s2, int len)
158 {
159 while(len--)
160 if (fat_tolower(t, *s1++) != fat_tolower(t, *s2++))
161 return 1;
162
163 return 0;
164 }
165
166 /*
167 * Return values: negative -> error, 0 -> not found, positive -> found,
168 * value is the total amount of slots, including the shortname entry.
169 */
170 int fat_search_long(struct inode *inode, const char *name, int name_len,
171 int anycase, loff_t *spos, loff_t *lpos)
172 {
173 struct super_block *sb = inode->i_sb;
174 struct buffer_head *bh = NULL;
175 struct msdos_dir_entry *de;
176 struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
177 struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
178 wchar_t bufuname[14];
179 unsigned char xlate_len, long_slots, *unicode = NULL;
180 char work[8], bufname[260]; /* 256 + 4 */
181 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
182 int utf8 = MSDOS_SB(sb)->options.utf8;
183 int nocase = MSDOS_SB(sb)->options.nocase;
184 int ino, chl, i, j, last_u, res = 0;
185 loff_t cpos = 0;
186
187 while(1) {
188 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
189 goto EODir;
190 parse_record:
191 long_slots = 0;
192 if (de->name[0] == (__s8) DELETED_FLAG)
193 continue;
194 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
195 continue;
196 if (de->attr != ATTR_EXT && IS_FREE(de->name))
197 continue;
198 if (de->attr == ATTR_EXT) {
199 struct msdos_dir_slot *ds;
200 int offset;
201 unsigned char id;
202 unsigned char slot;
203 unsigned char slots;
204 unsigned char sum;
205 unsigned char alias_checksum;
206
207 if (!unicode) {
208 unicode = (unsigned char *)
209 __get_free_page(GFP_KERNEL);
210 if (!unicode) {
211 fat_brelse(sb, bh);
212 return -ENOMEM;
213 }
214 }
215 parse_long:
216 slots = 0;
217 offset = 0;
218 ds = (struct msdos_dir_slot *) de;
219 id = ds->id;
220 if (!(id & 0x40))
221 continue;
222 slots = id & ~0x40;
223 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
224 continue;
225 long_slots = slots;
226 alias_checksum = ds->alias_checksum;
227
228 slot = slots;
229 while (1) {
230 slot--;
231 offset = slot * 26;
232 memcpy(&unicode[offset], ds->name0_4, 10);
233 memcpy(&unicode[offset+10], ds->name5_10, 12);
234 memcpy(&unicode[offset+22], ds->name11_12, 4);
235 offset += 26;
236
237 if (ds->id & 0x40) {
238 unicode[offset] = 0;
239 unicode[offset+1] = 0;
240 }
241 if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
242 goto EODir;
243 if (slot == 0)
244 break;
245 ds = (struct msdos_dir_slot *) de;
246 if (ds->attr != ATTR_EXT)
247 goto parse_record;
248 if ((ds->id & ~0x40) != slot)
249 goto parse_long;
250 if (ds->alias_checksum != alias_checksum)
251 goto parse_long;
252 }
253 if (de->name[0] == (__s8) DELETED_FLAG)
254 continue;
255 if (de->attr == ATTR_EXT)
256 goto parse_long;
257 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
258 continue;
259 for (sum = 0, i = 0; i < 11; i++)
260 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
261 if (sum != alias_checksum)
262 long_slots = 0;
263 }
264
265 for (i = 0; i < 8; i++) {
266 /* see namei.c, msdos_format_name */
267 if (de->name[i] == 0x05)
268 work[i] = 0xE5;
269 else
270 work[i] = de->name[i];
271 }
272 for (i = 0, j = 0, last_u = 0; i < 8;) {
273 if (!work[i]) break;
274 if (nocase)
275 chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
276 else
277 chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
278 if (chl <= 1) {
279 if (work[i] != ' ')
280 last_u = j;
281 } else {
282 last_u = j;
283 }
284 i += chl;
285 }
286 j = last_u;
287 fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
288 for (i = 0; i < 3;) {
289 if (!de->ext[i]) break;
290 if (nocase)
291 chl = fat_short2uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
292 else
293 chl = fat_short2lower_uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
294 if (chl <= 1) {
295 if (de->ext[i] != ' ')
296 last_u = j;
297 } else {
298 last_u = j;
299 }
300 i += chl;
301 }
302 if (!last_u)
303 continue;
304
305 bufuname[last_u] = 0x0000;
306 xlate_len = utf8
307 ?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
308 :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
309 if (xlate_len == name_len)
310 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
311 (anycase && !fat_strnicmp(nls_io, name, bufname,
312 xlate_len)))
313 goto Found;
314
315 if (long_slots) {
316 xlate_len = utf8
317 ?utf8_wcstombs(bufname, (wchar_t *) unicode, sizeof(bufname))
318 :uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io);
319 if (xlate_len != name_len)
320 continue;
321 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
322 (anycase && !fat_strnicmp(nls_io, name, bufname,
323 xlate_len)))
324 goto Found;
325 }
326 }
327
328 Found:
329 res = long_slots + 1;
330 *spos = cpos - sizeof(struct msdos_dir_entry);
331 *lpos = cpos - res*sizeof(struct msdos_dir_entry);
332 EODir:
333 fat_brelse(sb, bh);
334 if (unicode) {
335 free_page((unsigned long) unicode);
336 }
337 return res;
338 }
339
340 static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
341 filldir_t filldir, int shortnames, int both)
342 {
343 struct super_block *sb = inode->i_sb;
344 struct buffer_head *bh;
345 struct msdos_dir_entry *de;
346 struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
347 struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
348 wchar_t bufuname[14];
349 unsigned char long_slots, *unicode = NULL;
350 char c, work[8], bufname[56], *ptname = bufname;
351 unsigned long lpos, dummy, *furrfu = &lpos;
352 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
353 int isvfat = MSDOS_SB(sb)->options.isvfat;
354 int utf8 = MSDOS_SB(sb)->options.utf8;
355 int nocase = MSDOS_SB(sb)->options.nocase;
356 int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
357 loff_t cpos;
358
359 cpos = filp->f_pos;
360 /* Fake . and .. for the root directory. */
361 if (inode->i_ino == MSDOS_ROOT_INO) {
362 while (cpos < 2) {
363 if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
364 return 0;
365 cpos++;
366 filp->f_pos++;
367 }
368 if (cpos == 2) {
369 dummy = 2;
370 furrfu = &dummy;
371 cpos = 0;
372 }
373 }
374 if (cpos & (sizeof(struct msdos_dir_entry)-1))
375 return -ENOENT;
376
377 bh = NULL;
378 GetNew:
379 long_slots = 0;
380 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
381 goto EODir;
382 /* Check for long filename entry */
383 if (isvfat) {
384 if (de->name[0] == (__s8) DELETED_FLAG)
385 goto RecEnd;
386 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
387 goto RecEnd;
388 if (de->attr != ATTR_EXT && IS_FREE(de->name))
389 goto RecEnd;
390 } else {
391 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
392 goto RecEnd;
393 }
394
395 if (isvfat && de->attr == ATTR_EXT) {
396 struct msdos_dir_slot *ds;
397 int offset;
398 unsigned char id;
399 unsigned char slot;
400 unsigned char slots;
401 unsigned char sum;
402 unsigned char alias_checksum;
403
404 if (!unicode) {
405 unicode = (unsigned char *)
406 __get_free_page(GFP_KERNEL);
407 if (!unicode) {
408 filp->f_pos = cpos;
409 fat_brelse(sb, bh);
410 return -ENOMEM;
411 }
412 }
413 ParseLong:
414 slots = 0;
415 offset = 0;
416 ds = (struct msdos_dir_slot *) de;
417 id = ds->id;
418 if (!(id & 0x40))
419 goto RecEnd;
420 slots = id & ~0x40;
421 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
422 goto RecEnd;
423 long_slots = slots;
424 alias_checksum = ds->alias_checksum;
425
426 slot = slots;
427 while (1) {
428 slot--;
429 offset = slot * 26;
430 memcpy(&unicode[offset], ds->name0_4, 10);
431 memcpy(&unicode[offset+10], ds->name5_10, 12);
432 memcpy(&unicode[offset+22], ds->name11_12, 4);
433 offset += 26;
434
435 if (ds->id & 0x40) {
436 unicode[offset] = 0;
437 unicode[offset+1] = 0;
438 }
439 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
440 goto EODir;
441 if (slot == 0)
442 break;
443 ds = (struct msdos_dir_slot *) de;
444 if (ds->attr != ATTR_EXT)
445 goto RecEnd; /* XXX */
446 if ((ds->id & ~0x40) != slot)
447 goto ParseLong;
448 if (ds->alias_checksum != alias_checksum)
449 goto ParseLong;
450 }
451 if (de->name[0] == (__s8) DELETED_FLAG)
452 goto RecEnd;
453 if (de->attr == ATTR_EXT)
454 goto ParseLong;
455 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
456 goto RecEnd;
457 for (sum = 0, i = 0; i < 11; i++)
458 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
459 if (sum != alias_checksum)
460 long_slots = 0;
461 }
462
463 if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
464 *ptname++ = '.';
465 dotoffset = 1;
466 }
467
468 for (i = 0; i < 8; i++) {
469 /* see namei.c, msdos_format_name */
470 if (de->name[i] == 0x05)
471 work[i] = 0xE5;
472 else
473 work[i] = de->name[i];
474 }
475 for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
476 if (!(c = work[i])) break;
477 if (nocase)
478 chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
479 else
480 chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
481 if (chl <= 1) {
482 ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
483 if (c != ' ') {
484 last = i;
485 last_u = j;
486 }
487 } else {
488 last_u = j;
489 for (chi = 0; chi < chl && i < 8; chi++) {
490 ptname[i] = work[i];
491 i++; last = i;
492 }
493 }
494 }
495 i = last;
496 j = last_u;
497 fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
498 ptname[i++] = '.';
499 for (i2 = 0; i2 < 3;) {
500 if (!(c = de->ext[i2])) break;
501 if (nocase)
502 chl = fat_short2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
503 else
504 chl = fat_short2lower_uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
505 if (chl <= 1) {
506 i2++;
507 ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
508 if (c != ' ') {
509 last = i;
510 last_u = j;
511 }
512 } else {
513 last_u = j;
514 for (chi = 0; chi < chl && i2 < 3; chi++) {
515 ptname[i++] = de->ext[i2++];
516 last = i;
517 }
518 }
519 }
520 if (!last)
521 goto RecEnd;
522
523 i = last + dotoffset;
524 j = last_u;
525
526 lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
527 if (!memcmp(de->name,MSDOS_DOT,11))
528 inum = inode->i_ino;
529 else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
530 /* inum = fat_parent_ino(inode,0); */
531 inum = filp->f_dentry->d_parent->d_inode->i_ino;
532 } else {
533 struct inode *tmp = fat_iget(sb, ino);
534 if (tmp) {
535 inum = tmp->i_ino;
536 iput(tmp);
537 } else
538 inum = iunique(sb, MSDOS_ROOT_INO);
539 }
540
541 if (isvfat) {
542 bufuname[j] = 0x0000;
543 i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
544 : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
545 }
546
547 if (!long_slots||shortnames) {
548 if (both)
549 bufname[i] = '\0';
550 if (filldir(dirent, bufname, i, *furrfu, inum,
551 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
552 goto FillFailed;
553 } else {
554 char longname[275];
555 int long_len = utf8
556 ? utf8_wcstombs(longname, (wchar_t *) unicode, sizeof(longname))
557 : uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate,
558 nls_io);
559 if (both) {
560 memcpy(&longname[long_len+1], bufname, i);
561 long_len += i;
562 }
563 if (filldir(dirent, longname, long_len, *furrfu, inum,
564 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
565 goto FillFailed;
566 }
567
568 RecEnd:
569 furrfu = &lpos;
570 filp->f_pos = cpos;
571 goto GetNew;
572 EODir:
573 filp->f_pos = cpos;
574 FillFailed:
575 if (bh)
576 fat_brelse(sb, bh);
577 if (unicode) {
578 free_page((unsigned long) unicode);
579 }
580 return 0;
581 }
582
583 int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
584 {
585 struct inode *inode = filp->f_dentry->d_inode;
586 return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
587 }
588
589 static int vfat_ioctl_fill(
590 void * buf,
591 const char * name,
592 int name_len,
593 loff_t offset,
594 ino_t ino,
595 unsigned int d_type)
596 {
597 struct dirent *d1 = (struct dirent *)buf;
598 struct dirent *d2 = d1 + 1;
599 int len, slen;
600 int dotdir;
601
602 get_user(len, &d1->d_reclen);
603 if (len != 0) {
604 return -1;
605 }
606
607 if ((name_len == 1 && name[0] == '.') ||
608 (name_len == 2 && name[0] == '.' && name[1] == '.')) {
609 dotdir = 1;
610 len = name_len;
611 } else {
612 dotdir = 0;
613 len = strlen(name);
614 }
615 if (len != name_len) {
616 copy_to_user(d2->d_name, name, len);
617 put_user(0, d2->d_name + len);
618 put_user(len, &d2->d_reclen);
619 put_user(ino, &d2->d_ino);
620 put_user(offset, &d2->d_off);
621 slen = name_len - len;
622 copy_to_user(d1->d_name, name+len+1, slen);
623 put_user(0, d1->d_name+slen);
624 put_user(slen, &d1->d_reclen);
625 } else {
626 put_user(0, d2->d_name);
627 put_user(0, &d2->d_reclen);
628 copy_to_user(d1->d_name, name, len);
629 put_user(0, d1->d_name+len);
630 put_user(len, &d1->d_reclen);
631 }
632 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
633 d1, d2, len, name_len));
634
635 return 0;
636 }
637
638 int fat_dir_ioctl(struct inode * inode, struct file * filp,
639 unsigned int cmd, unsigned long arg)
640 {
641 int err;
642 /*
643 * We want to provide an interface for Samba to be able
644 * to get the short filename for a given long filename.
645 * Samba should use this ioctl instead of readdir() to
646 * get the information it needs.
647 */
648 switch (cmd) {
649 case VFAT_IOCTL_READDIR_BOTH: {
650 struct dirent *d1 = (struct dirent *)arg;
651 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
652 if (err)
653 return err;
654 put_user(0, &d1->d_reclen);
655 return fat_readdirx(inode,filp,(void *)arg,
656 vfat_ioctl_fill, 0, 1);
657 }
658 case VFAT_IOCTL_READDIR_SHORT: {
659 struct dirent *d1 = (struct dirent *)arg;
660 put_user(0, &d1->d_reclen);
661 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
662 if (err)
663 return err;
664 return fat_readdirx(inode,filp,(void *)arg,
665 vfat_ioctl_fill, 1, 1);
666 }
667 default:
668 /* forward ioctl to CVF extension */
669 if (MSDOS_SB(inode->i_sb)->cvf_format &&
670 MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
671 return MSDOS_SB(inode->i_sb)->cvf_format
672 ->cvf_dir_ioctl(inode,filp,cmd,arg);
673 return -EINVAL;
674 }
675
676 return 0;
677 }
678
679 /***** See if directory is empty */
680 int fat_dir_empty(struct inode *dir)
681 {
682 loff_t pos;
683 struct buffer_head *bh;
684 struct msdos_dir_entry *de;
685 int ino,result = 0;
686
687 pos = 0;
688 bh = NULL;
689 while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
690 /* Ignore vfat longname entries */
691 if (de->attr == ATTR_EXT)
692 continue;
693 if (!IS_FREE(de->name) &&
694 strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
695 strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
696 result = -ENOTEMPTY;
697 break;
698 }
699 }
700 if (bh)
701 fat_brelse(dir->i_sb, bh);
702
703 return result;
704 }
705
706 /* This assumes that size of cluster is above the 32*slots */
707
708 int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
709 struct msdos_dir_entry **de, int *ino)
710 {
711 struct super_block *sb = dir->i_sb;
712 loff_t offset, curr;
713 int row;
714 struct buffer_head *new_bh;
715
716 offset = curr = 0;
717 *bh = NULL;
718 row = 0;
719 while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
720 if (IS_FREE((*de)->name)) {
721 if (++row == slots)
722 return offset;
723 } else {
724 row = 0;
725 offset = curr;
726 }
727 }
728 if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
729 return -ENOSPC;
730 new_bh = fat_extend_dir(dir);
731 if (!new_bh)
732 return -ENOSPC;
733 fat_brelse(sb, new_bh);
734 do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
735 return offset;
736 }
737
738 int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
739 {
740 struct super_block *sb = dir->i_sb;
741 struct buffer_head *bh;
742 struct msdos_dir_entry *de;
743 __u16 date, time;
744
745 if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
746 /* zeroed out, so... */
747 fat_date_unix2dos(dir->i_mtime,&time,&date);
748 de = (struct msdos_dir_entry*)&bh->b_data[0];
749 memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
750 memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
751 de[0].attr = de[1].attr = ATTR_DIR;
752 de[0].time = de[1].time = CT_LE_W(time);
753 de[0].date = de[1].date = CT_LE_W(date);
754 if (is_vfat) { /* extra timestamps */
755 de[0].ctime = de[1].ctime = CT_LE_W(time);
756 de[0].adate = de[0].cdate =
757 de[1].adate = de[1].cdate = CT_LE_W(date);
758 }
759 de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
760 de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
761 de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
762 de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
763 fat_mark_buffer_dirty(sb, bh);
764 fat_brelse(sb, bh);
765 dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
766 mark_inode_dirty(dir);
767
768 return 0;
769 }
770
771 /*
772 * Overrides for Emacs so that we follow Linus's tabbing style.
773 * Emacs will notice this stuff at the end of the file and automatically
774 * adjust the settings for this buffer only. This must remain at the end
775 * of the file.
776 * ---------------------------------------------------------------------------
777 * Local variables:
778 * c-indent-level: 8
779 * c-brace-imaginary-offset: 0
780 * c-brace-offset: -8
781 * c-argdecl-indent: 8
782 * c-label-offset: -8
783 * c-continued-statement-offset: 8
784 * c-continued-brace-offset: 0
785 * End:
786 */
787