1/* Copyright 1995 David C. Niemi 2 * Copyright 1996-2003,2005,2007-2009 Alain Knaff. 3 * This file is part of mtools. 4 * 5 * Mtools is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * Mtools is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with Mtools. If not, see <http://www.gnu.org/licenses/>. 17 * 18 * vfat.c 19 * 20 * Miscellaneous VFAT-related functions 21 */ 22 23#include "sysincludes.h" 24#include "msdos.h" 25#include "mtools.h" 26#include "vfat.h" 27#include "file.h" 28#include "dirCache.h" 29#include "file_name.h" 30 31/* #define DEBUG */ 32 33const char *short_illegals=";+=[]',\"*\\<>/?:|"; 34const char *long_illegals = "\"*\\<>/?:|\005"; 35 36/* Automatically derive a new name */ 37static void autorename(char *name, 38 char tilda, char dot, const char *illegals, 39 int limit, int bump) 40{ 41 int tildapos, dotpos; 42 unsigned int seqnum=0, maxseq=0; 43 char tmp; 44 char *p; 45 46#ifdef DEBUG 47 printf("In autorename for name=%s.\n", name); 48#endif 49 tildapos = -1; 50 51 for(p=name; *p ; p++) 52 if (strchr(illegals, *p)) { 53 *p = '_'; 54 bump = 0; 55 } 56 57 for(dotpos=0; 58 name[dotpos] && dotpos < limit && name[dotpos] != dot ; 59 dotpos++) { 60 if(name[dotpos] == tilda) { 61 tildapos = dotpos; 62 seqnum = 0; 63 maxseq = 1; 64 } else if (name[dotpos] >= '0' && name[dotpos] <= '9') { 65 seqnum = seqnum * 10 + name[dotpos] - '0'; 66 maxseq = maxseq * 10; 67 } else 68 tildapos = -1; /* sequence number interrupted */ 69 } 70 if(tildapos == -1) { 71 /* no sequence number yet */ 72 if(dotpos > limit - 2) { 73 tildapos = limit - 2; 74 dotpos = limit; 75 } else { 76 tildapos = dotpos; 77 dotpos += 2; 78 } 79 seqnum = 1; 80 } else { 81 if(bump) 82 seqnum++; 83 if(seqnum > 999999) { 84 seqnum = 1; 85 tildapos = dotpos - 2; 86 /* this matches Win95's behavior, and also guarantees 87 * us that the sequence numbers never get shorter */ 88 } 89 if (seqnum == maxseq) { 90 if(dotpos >= limit) 91 tildapos--; 92 else 93 dotpos++; 94 } 95 } 96 97 tmp = name[dotpos]; 98 if((bump && seqnum == 1) || seqnum > 1 || mtools_numeric_tail) 99 sprintf(name+tildapos,"%c%d",tilda, seqnum); 100 if(dot) 101 name[dotpos]=tmp; 102 /* replace the character if it wasn't a space */ 103#ifdef DEBUG 104 printf("Out autorename for name=%s.\n", name); 105#endif 106} 107 108 109void autorename_short(dos_name_t *name, int bump) 110{ 111 autorename(name->base, '~', ' ', short_illegals, 8, bump); 112} 113 114void autorename_long(char *name, int bump) 115{ 116 autorename(name, '-', '\0', long_illegals, 255, bump); 117} 118 119 120static __inline__ int unicode_read(struct unicode_char *in, 121 wchar_t *out, int num) 122{ 123 wchar_t *end_out = out+num; 124 125 while(out < end_out) { 126#ifdef HAVE_WCHAR_H 127 *out = in->lchar | ((in->uchar) << 8); 128#else 129 if (in->uchar) 130 *out = '_'; 131 else 132 *out = in->lchar; 133#endif 134 ++out; 135 ++in; 136 } 137 return num; 138} 139 140 141void clear_vfat(struct vfat_state *v) 142{ 143 v->subentries = 0; 144 v->status = 0; 145 v->present = 0; 146} 147 148 149/* sum_shortname 150 * 151 * Calculate the checksum that results from the short name in *dir. 152 * 153 * The sum is formed by circularly right-shifting the previous sum 154 * and adding in each character, from left to right, padding both 155 * the name and extension to maximum length with spaces and skipping 156 * the "." (hence always summing exactly 11 characters). 157 * 158 * This exact algorithm is required in order to remain compatible 159 * with Microsoft Windows-95 and Microsoft Windows NT 3.5. 160 * Thanks to Jeffrey Richter of Microsoft Systems Journal for 161 * pointing me to the correct algorithm. 162 * 163 * David C. Niemi (niemi@tuxers.net) 95.01.19 164 */ 165static __inline__ unsigned char sum_shortname(const dos_name_t *dn) 166{ 167 unsigned char sum; 168 const char *name=dn->base; 169 const char *end = name+11; 170 171 for (sum=0; name<end; ++name) 172 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) 173 + (*name ? *name : ' '); 174 return(sum); 175} 176 177/* check_vfat 178 * 179 * Inspect a directory and any associated VSEs. 180 * Return 1 if the VSEs comprise a valid long file name, 181 * 0 if not. 182 */ 183static __inline__ void check_vfat(struct vfat_state *v, struct directory *dir) 184{ 185 dos_name_t dn;; 186 187 if (! v->subentries) { 188#ifdef DEBUG 189 fprintf(stderr, "check_vfat: no VSEs.\n"); 190#endif 191 return; 192 } 193 194 strncpy(dn.base, (char *)dir->name, 8); 195 strncpy(dn.ext, (char *)dir->ext, 3); 196 197 if (v->sum != sum_shortname(&dn)) 198 return; 199 200 if( (v->status & ((1<<v->subentries) - 1)) != (1<<v->subentries) - 1) 201 return; /* missing entries */ 202 203 /* zero out byte following last entry, for good measure */ 204 v->name[VSE_NAMELEN * v->subentries] = 0; 205 v->present = 1; 206} 207 208 209int clear_vses(Stream_t *Dir, int entrySlot, size_t last) 210{ 211 direntry_t entry; 212 dirCache_t *cache; 213 int error; 214 215 entry.Dir = Dir; 216 entry.entry = entrySlot; 217 218 /*maximize(last, entry.entry + MAX_VFAT_SUBENTRIES);*/ 219 cache = allocDirCache(Dir, last); 220 if(!cache) { 221 fprintf(stderr, "Out of memory error in clear_vses\n"); 222 exit(1); 223 } 224 addFreeEntry(cache, entry.entry, last); 225 for (; entry.entry < (signed int) last; ++entry.entry) { 226#ifdef DEBUG 227 fprintf(stderr,"Clearing entry %d.\n", entry.entry); 228#endif 229 dir_read(&entry, &error); 230 if(error) 231 return error; 232 if(!entry.dir.name[0] || entry.dir.name[0] == DELMARK) 233 break; 234 entry.dir.name[0] = DELMARK; 235 if (entry.dir.attr == 0xf) 236 entry.dir.attr = '\0'; 237 low_level_dir_write(&entry); 238 } 239 return 0; 240} 241 242int write_vfat(Stream_t *Dir, dos_name_t *shortname, char *longname, int start, 243 direntry_t *mainEntry) 244{ 245 struct vfat_subentry *vse; 246 int vse_id, num_vses; 247 wchar_t *c; 248 direntry_t entry; 249 dirCache_t *cache; 250 wchar_t unixyName[13]; 251 doscp_t *cp = GET_DOSCONVERT(Dir); 252 253 wchar_t wlongname[MAX_VNAMELEN+1]; 254 int wlen; 255 256 if(longname) { 257#ifdef DEBUG 258 printf("Entering write_vfat with longname=\"%s\", start=%d.\n", 259 longname,start); 260#endif 261 entry.Dir = Dir; 262 vse = (struct vfat_subentry *) &entry.dir; 263 /* Fill in invariant part of vse */ 264 vse->attribute = 0x0f; 265 vse->hash1 = vse->sector_l = vse->sector_u = 0; 266 vse->sum = sum_shortname(shortname); 267#ifdef DEBUG 268 printf("Wrote checksum=%d for shortname %s.%s\n", 269 vse->sum,shortname->base,shortname->ext); 270#endif 271 272 wlen = native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 273 0, 0); 274 num_vses = (wlen + VSE_NAMELEN - 1)/VSE_NAMELEN; 275 for (vse_id = num_vses; vse_id; --vse_id) { 276 int end = 0; 277 278 c = wlongname + (vse_id - 1) * VSE_NAMELEN; 279 280 c += unicode_write(c, vse->text1, VSE1SIZE, &end); 281 c += unicode_write(c, vse->text2, VSE2SIZE, &end); 282 c += unicode_write(c, vse->text3, VSE3SIZE, &end); 283 284 vse->id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id; 285#ifdef DEBUG 286 printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n", 287 longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN, 288 start + num_vses - vse_id, start + num_vses); 289#endif 290 291 entry.entry = start + num_vses - vse_id; 292 low_level_dir_write(&entry); 293 } 294 } else { 295 num_vses = 0; 296 wlongname[0]='\0'; 297 } 298 cache = allocDirCache(Dir, start + num_vses + 1); 299 if(!cache) { 300 fprintf(stderr, "Out of memory error\n"); 301 exit(1); 302 } 303 unix_name(cp, shortname->base, shortname->ext, 0, unixyName); 304 addUsedEntry(cache, start, start + num_vses + 1, wlongname, unixyName, 305 &mainEntry->dir); 306 low_level_dir_write(mainEntry); 307 return start + num_vses; 308} 309 310void dir_write(direntry_t *entry) 311{ 312 dirCacheEntry_t *dce; 313 dirCache_t *cache; 314 315 if(entry->entry == -3) { 316 fprintf(stderr, "Attempt to write root directory pointer\n"); 317 exit(1); 318 } 319 320 cache = allocDirCache(entry->Dir, entry->entry + 1); 321 if(!cache) { 322 fprintf(stderr, "Out of memory error in dir_write\n"); 323 exit(1); 324 } 325 dce = cache->entries[entry->entry]; 326 if(dce) { 327 if(entry->dir.name[0] == DELMARK) { 328 addFreeEntry(cache, dce->beginSlot, dce->endSlot); 329 } else { 330 dce->dir = entry->dir; 331 } 332 } 333 low_level_dir_write(entry); 334} 335 336 337/* 338 * The following function translates a series of vfat_subentries into 339 * data suitable for a dircache entry 340 */ 341static __inline__ void parse_vses(direntry_t *entry, 342 struct vfat_state *v) 343{ 344 struct vfat_subentry *vse; 345 unsigned char id, last_flag; 346 wchar_t *c; 347 348 vse = (struct vfat_subentry *) &entry->dir; 349 350 id = vse->id & VSE_MASK; 351 last_flag = (vse->id & VSE_LAST); 352 if (id > MAX_VFAT_SUBENTRIES) { 353 fprintf(stderr, "parse_vses: invalid VSE ID %d at %d.\n", 354 id, entry->entry); 355 return; 356 } 357 358/* 950819: This code enforced finding the VSEs in order. Well, Win95 359 * likes to write them in *reverse* order for some bizarre reason! So 360 * we pretty much have to tolerate them coming in any possible order. 361 * So skip this check, we'll do without it (What does this do, Alain?). 362 * 363 * 950820: Totally rearranged code to tolerate any order but to warn if 364 * they are not in reverse order like Win95 uses. 365 * 366 * 950909: Tolerate any order. We recognize new chains by mismatching 367 * checksums. In the event that the checksums match, new entries silently 368 * overwrite old entries of the same id. This should accept all valid 369 * entries, but may fail to reject invalid entries in some rare cases. 370 */ 371 372 /* bad checksum, begin new chain */ 373 if(v->sum != vse->sum) { 374 clear_vfat(v); 375 v->sum = vse->sum; 376 } 377 378#ifdef DEBUG 379 if(v->status & (1 << (id-1))) 380 fprintf(stderr, 381 "parse_vses: duplicate VSE %d\n", vse->id); 382#endif 383 384 v->status |= 1 << (id-1); 385 if(last_flag) 386 v->subentries = id; 387 388#ifdef DEBUG 389 if (id > v->subentries) 390 /* simple test to detect entries preceding 391 * the "last" entry (really the first) */ 392 fprintf(stderr, 393 "parse_vses: new VSE %d sans LAST flag\n", 394 vse->id); 395#endif 396 397 c = &(v->name[VSE_NAMELEN * (id-1)]); 398 c += unicode_read(vse->text1, c, VSE1SIZE); 399 c += unicode_read(vse->text2, c, VSE2SIZE); 400 c += unicode_read(vse->text3, c, VSE3SIZE); 401#ifdef DEBUG 402 printf("Read VSE %d at %d, subentries=%d, = (%13ls).\n", 403 id,entry->entry,v->subentries,&(v->name[VSE_NAMELEN * (id-1)])); 404#endif 405 if (last_flag) 406 *c = '\0'; /* Null terminate long name */ 407} 408 409 410static dirCacheEntry_t *vfat_lookup_loop_common(doscp_t *cp, 411 direntry_t *direntry, 412 dirCache_t *cache, 413 int lookForFreeSpace, 414 int *io_error) 415{ 416 wchar_t newfile[13]; 417 int initpos = direntry->entry + 1; 418 struct vfat_state vfat; 419 wchar_t *longname; 420 int error; 421 422 /* not yet cached */ 423 *io_error = 0; 424 clear_vfat(&vfat); 425 while(1) { 426 ++direntry->entry; 427 if(!dir_read(direntry, &error)){ 428 if(error) { 429 *io_error = error; 430 return NULL; 431 } 432 addFreeEntry(cache, initpos, direntry->entry); 433 return addEndEntry(cache, direntry->entry); 434 } 435 436 if (direntry->dir.name[0] == '\0'){ 437 /* the end of the directory */ 438 if(lookForFreeSpace) 439 continue; 440 return addEndEntry(cache, direntry->entry); 441 } 442 if(direntry->dir.name[0] != DELMARK && 443 direntry->dir.attr == 0x0f) 444 parse_vses(direntry, &vfat); 445 else 446 /* the main entry */ 447 break; 448 } 449 450 /* If we get here, it's a short name FAT entry, maybe erased. 451 * thus we should make sure that the vfat structure will be 452 * cleared before the next loop run */ 453 454 /* deleted file */ 455 if (direntry->dir.name[0] == DELMARK) { 456 return addFreeEntry(cache, initpos, 457 direntry->entry + 1); 458 } 459 460 check_vfat(&vfat, &direntry->dir); 461 if(!vfat.present) 462 vfat.subentries = 0; 463 464 /* mark space between last entry and this one as free */ 465 addFreeEntry(cache, initpos, 466 direntry->entry - vfat.subentries); 467 468 if (direntry->dir.attr & 0x8){ 469 /* Read entry as a label */ 470 wchar_t *ptr = newfile; 471 ptr += dos_to_wchar(cp, direntry->dir.name, ptr, 8); 472 ptr += dos_to_wchar(cp, direntry->dir.ext, ptr, 3); 473 *ptr = '\0'; 474 } else 475 unix_name(cp, 476 direntry->dir.name, 477 direntry->dir.ext, 478 direntry->dir.Case, 479 newfile); 480 481 if(vfat.present) 482 longname = vfat.name; 483 else 484 longname = 0; 485 486 return addUsedEntry(cache, direntry->entry - vfat.subentries, 487 direntry->entry + 1, longname, 488 newfile, &direntry->dir); 489} 490 491static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_read(doscp_t *cp, 492 direntry_t *direntry, 493 dirCache_t *cache, 494 int *io_error) 495{ 496 int initpos = direntry->entry + 1; 497 dirCacheEntry_t *dce; 498 499 *io_error = 0; 500 dce = cache->entries[initpos]; 501 if(dce) { 502 direntry->entry = dce->endSlot - 1; 503 return dce; 504 } else { 505 return vfat_lookup_loop_common(cp, 506 direntry, cache, 0, io_error); 507 } 508} 509 510 511typedef enum result_t { 512 RES_NOMATCH, 513 RES_MATCH, 514 RES_END, 515 RES_ERROR 516} result_t; 517 518 519/* 520 * 0 does not match 521 * 1 matches 522 * 2 end 523 */ 524static result_t checkNameForMatch(struct direntry_t *direntry, 525 dirCacheEntry_t *dce, 526 const wchar_t *filename, 527 int length, 528 int flags) 529{ 530 switch(dce->type) { 531 case DCET_FREE: 532 return RES_NOMATCH; 533 case DCET_END: 534 return RES_END; 535 case DCET_USED: 536 break; 537 default: 538 fprintf(stderr, "Unexpected entry type %d\n", 539 dce->type); 540 return RES_ERROR; 541 } 542 543 direntry->dir = dce->dir; 544 545 /* make sure the entry is of an accepted type */ 546 if((direntry->dir.attr & 0x8) && !(flags & ACCEPT_LABEL)) 547 return RES_NOMATCH; 548 549 550 /*---------- multiple files ----------*/ 551 if(!((flags & MATCH_ANY) || 552 (dce->longName && 553 match(dce->longName, filename, direntry->name, 0, length)) || 554 match(dce->shortName, filename, direntry->name, 1, length))) { 555 556 return RES_NOMATCH; 557 } 558 559 /* entry of non-requested type, has to come after name 560 * checking because of clash handling */ 561 if(IS_DIR(direntry) && !(flags & ACCEPT_DIR)) { 562 if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) { 563 char tmp[4*13+1]; 564 wchar_to_native(dce->shortName,tmp,13); 565 fprintf(stderr, "Skipping \"%s\", is a directory\n", 566 tmp); 567 } 568 return RES_NOMATCH; 569 } 570 571 if(!(direntry->dir.attr & (ATTR_LABEL | ATTR_DIR)) && 572 !(flags & ACCEPT_PLAIN)) { 573 if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) { 574 char tmp[4*13+1]; 575 wchar_to_native(dce->shortName,tmp,13); 576 fprintf(stderr, 577 "Skipping \"%s\", is not a directory\n", 578 tmp); 579 } 580 return RES_NOMATCH; 581 } 582 583 return RES_MATCH; 584} 585 586 587/* 588 * vfat_lookup looks for filenames in directory dir. 589 * if a name if found, it is returned in outname 590 * if applicable, the file is opened and its stream is returned in File 591 */ 592 593int vfat_lookup(direntry_t *direntry, const char *filename, int length, 594 int flags, char *shortname, char *longname) 595{ 596 dirCacheEntry_t *dce; 597 result_t result; 598 dirCache_t *cache; 599 int io_error; 600 wchar_t wfilename[MAX_VNAMELEN+1]; 601 wchar_t *wfilenamep = wfilename; 602 doscp_t *cp = GET_DOSCONVERT(direntry->Dir); 603 604 if(length == -1 && filename) 605 length = strlen(filename); 606 607 if(filename != NULL) 608 length = native_to_wchar(filename, wfilename, MAX_VNAMELEN, 609 filename+length, 0); 610 else { 611 wfilenamep = NULL; 612 length = 0; 613 } 614 615 if (direntry->entry == -2) 616 return -1; 617 618 cache = allocDirCache(direntry->Dir, direntry->entry+1); 619 if(!cache) { 620 fprintf(stderr, "Out of memory error in vfat_lookup [0]\n"); 621 exit(1); 622 } 623 624 do { 625 dce = vfat_lookup_loop_for_read(cp, direntry, cache, &io_error); 626 if(!dce) { 627 if (io_error) 628 return -2; 629 fprintf(stderr, "Out of memory error in vfat_lookup\n"); 630 exit(1); 631 } 632 result = checkNameForMatch(direntry, dce, 633 wfilename, 634 length, flags); 635 } while(result == RES_NOMATCH); 636 637 if(result == RES_MATCH){ 638 if(longname){ 639 if(dce->longName) 640 wchar_to_native(dce->longName, 641 longname, MAX_VNAMELEN); 642 else 643 *longname ='\0'; 644 } 645 if(shortname) 646 wchar_to_native(dce->shortName, shortname, 12); 647 direntry->beginSlot = dce->beginSlot; 648 direntry->endSlot = dce->endSlot-1; 649 return 0; /* file found */ 650 } else { 651 direntry->entry = -2; 652 return -1; /* no file found */ 653 } 654} 655 656static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_insert(doscp_t *cp, 657 direntry_t *direntry, 658 int initpos, 659 dirCache_t *cache) 660{ 661 dirCacheEntry_t *dce; 662 int io_error; 663 664 dce = cache->entries[initpos]; 665 if(dce && dce->type != DCET_END) { 666 return dce; 667 } else { 668 direntry->entry = initpos - 1; 669 dce = vfat_lookup_loop_common(cp, 670 direntry, cache, 1, &io_error); 671 if(!dce) { 672 if (io_error) { 673 return NULL; 674 } 675 fprintf(stderr, 676 "Out of memory error in vfat_lookup_loop\n"); 677 exit(1); 678 } 679 return cache->entries[initpos]; 680 } 681} 682 683static void accountFreeSlots(struct scan_state *ssp, dirCacheEntry_t *dce) 684{ 685 if(ssp->got_slots) 686 return; 687 688 if(ssp->free_end != dce->beginSlot) { 689 ssp->free_start = dce->beginSlot; 690 } 691 ssp->free_end = dce->endSlot; 692 693 if(ssp->free_end - ssp->free_start >= ssp->size_needed) { 694 ssp->got_slots = 1; 695 ssp->slot = ssp->free_start + ssp->size_needed - 1; 696 } 697} 698 699static void clear_scan(wchar_t *longname, int use_longname, 700 struct scan_state *s) 701{ 702 s->shortmatch = s->longmatch = s->slot = -1; 703 s->free_end = s->got_slots = s->free_start = 0; 704 705 if (use_longname) 706 s->size_needed = 1 + 707 (wcslen(longname) + VSE_NAMELEN - 1)/VSE_NAMELEN; 708 else 709 s->size_needed = 1; 710} 711 712/* lookup_for_insert replaces the old scandir function. It directly 713 * calls into vfat_lookup_loop, thus eliminating the overhead of the 714 * normal vfat_lookup 715 */ 716int lookupForInsert(Stream_t *Dir, 717 struct direntry_t *direntry, 718 dos_name_t *dosname, 719 char *longname, 720 struct scan_state *ssp, 721 int ignore_entry, 722 int source_entry, 723 int pessimisticShortRename, 724 int use_longname) 725{ 726 direntry_t entry; 727 int ignore_match; 728 dirCacheEntry_t *dce; 729 dirCache_t *cache; 730 int pos; /* position _before_ the next answered entry */ 731 wchar_t shortName[13]; 732 wchar_t wlongname[MAX_VNAMELEN+1]; 733 doscp_t *cp = GET_DOSCONVERT(Dir); 734 735 native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 0, 0); 736 clear_scan(wlongname, use_longname, ssp); 737 738 ignore_match = (ignore_entry == -2 ); 739 740 initializeDirentry(&entry, Dir); 741 ssp->match_free = 0; 742 743 /* hash bitmap of already encountered names. Speeds up batch appends 744 * to huge directories, because in the best case, we only need to scan 745 * the new entries rather than the whole directory */ 746 cache = allocDirCache(Dir, 1); 747 if(!cache) { 748 fprintf(stderr, "Out of memory error in lookupForInsert\n"); 749 exit(1); 750 } 751 752 if(!ignore_match) 753 unix_name(cp, dosname->base, dosname->ext, 0, shortName); 754 755 pos = cache->nrHashed; 756 if(source_entry >= 0 || 757 (pos && isHashed(cache, wlongname))) { 758 pos = 0; 759 } else if(pos && !ignore_match && isHashed(cache, shortName)) { 760 if(pessimisticShortRename) { 761 ssp->shortmatch = -2; 762 return 1; 763 } 764 pos = 0; 765 } else if(growDirCache(cache, pos) < 0) { 766 fprintf(stderr, "Out of memory error in vfat_looup [0]\n"); 767 exit(1); 768 } 769 do { 770 dce = vfat_lookup_loop_for_insert(cp, &entry, pos, cache); 771 switch(dce->type) { 772 case DCET_FREE: 773 accountFreeSlots(ssp, dce); 774 break; 775 case DCET_USED: 776 if(!(dce->dir.attr & 0x8) && 777 (signed int)dce->endSlot-1 == source_entry) 778 accountFreeSlots(ssp, dce); 779 780 /* labels never match, neither does the 781 * ignored entry */ 782 if( (dce->dir.attr & 0x8) || 783 ((signed int)dce->endSlot-1==ignore_entry)) 784 break; 785 786 /* check long name */ 787 if((dce->longName && 788 !wcscasecmp(dce->longName, wlongname)) || 789 (dce->shortName && 790 !wcscasecmp(dce->shortName, wlongname))) { 791 ssp->longmatch = dce->endSlot - 1; 792 /* long match is a reason for 793 * immediate stop */ 794 direntry->beginSlot = dce->beginSlot; 795 direntry->endSlot = dce->endSlot-1; 796 return 1; 797 } 798 799 /* Long name or not, always check for 800 * short name match */ 801 if (!ignore_match && 802 !wcscasecmp(shortName, dce->shortName)) 803 ssp->shortmatch = dce->endSlot - 1; 804 break; 805 case DCET_END: 806 break; 807 } 808 pos = dce->endSlot; 809 } while(dce->type != DCET_END); 810 if (ssp->shortmatch > -1) 811 return 1; 812 ssp->max_entry = dce->beginSlot; 813 if (ssp->got_slots) 814 return 6; /* Success */ 815 816 /* Need more room. Can we grow the directory? */ 817 if(!isRootDir(Dir)) 818 return 5; /* OK, try to grow the directory */ 819 820 fprintf(stderr, "No directory slots\n"); 821 return -1; 822} 823 824 825 826/* End vfat.c */ 827