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