1 /* 2 * Copyright 2004 Martin Fuchs 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 20 // 21 // Explorer clone 22 // 23 // fatfs.cpp 24 // 25 // Martin Fuchs, 01.02.2004 26 // 27 28 29 #include <precomp.h> 30 31 #include "fatfs.h" 32 33 #ifdef _DEBUG 34 35 static union DEntry* link_dir_entries(struct dirent* dir, struct Kette* K, int cnt) 36 { 37 union DEntry* Ent = (union DEntry*) dir; 38 struct Kette* L = NULL; 39 40 for(; cnt; cnt--) { 41 K->Rueck = L; 42 (L=K)->Ent = Ent; 43 AddP(K, sizeof(struct Kette)); 44 L->Vorw = K; 45 AddP(Ent, sizeof(union DEntry)); 46 } 47 48 L->Vorw = NULL; 49 50 return Ent; 51 } 52 53 void FATDirectory::read_directory(int scan_flags) 54 { 55 CONTEXT("FATDirectory::read_directory()"); 56 57 read_dir(); 58 59 union DEntry* p = (union DEntry*) _dir; 60 int i = 0; 61 62 do { 63 /* if (!IS_LNAME(p->E.attr) && p->E.name[0]!=FAT_DEL_CHAR) 64 gesBytes += p->E.size; 65 */ 66 67 AddP(p, sizeof(union DEntry)); 68 } while(++i<_ents && p->E.name[0]); 69 70 _alloc = (struct Kette*) malloc((size_t)((_ents=i)+8)*sizeof(struct Kette)); 71 if (!_alloc) 72 return; 73 74 link_dir_entries(_dir, _alloc, i); 75 76 Entry* first_entry = NULL; 77 int level = _level + 1; 78 79 Entry* last = NULL; 80 81 WIN32_FIND_DATA w32fd; 82 FAT_attribute attr; 83 String long_name; 84 85 TCHAR buffer[MAX_PATH]; 86 87 _tcscpy(buffer, (LPCTSTR)_path); 88 LPTSTR pname = buffer + _tcslen(buffer); 89 int plen = COUNTOF(buffer) - _tcslen(buffer); 90 91 *pname++ = '\\'; 92 --plen; 93 94 for(Kette*p=_alloc; p; p=p->Vorw) { 95 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA)); 96 97 DEntry_E& e = p->Ent->E; 98 99 // get file/directory attributes 100 attr.b = e.attr; 101 102 if (attr.b & (_A_DELETED | _A_ILLEGAL)) 103 attr.b |= _A_ILLEGAL; 104 105 const char* s = e.name; 106 LPTSTR d = w32fd.cFileName; 107 108 if (!IS_LNAME(attr.b) || e.name[0]==FAT_DEL_CHAR) { 109 if (e.name[0] == FAT_DEL_CHAR) 110 w32fd.dwFileAttributes |= ATTRIBUTE_ERASED; 111 else if (IS_LNAME(attr.b)) 112 w32fd.dwFileAttributes |= ATTRIBUTE_LONGNAME; 113 else if (attr.a.directory) 114 w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 115 else if (attr.a.volume) 116 w32fd.dwFileAttributes |= ATTRIBUTE_VOLNAME; //@@ -> in Volume-Name der Root kopieren 117 118 // get file name 119 *d++ = *s==FAT_DEL_CHAR? '?': *s; 120 ++s; 121 122 for(i=0; i<7; ++i) 123 *d++ = *s++; 124 125 while(d>w32fd.cFileName && d[-1]==' ') 126 --d; 127 128 *d++ = '.'; 129 130 for(; i<10; ++i) 131 *d++ = *s++; 132 133 while(d>w32fd.cFileName && d[-1]==' ') 134 --d; 135 136 if (d>w32fd.cFileName && d[-1]=='.') 137 --d; 138 139 *d = '\0'; 140 } else { 141 s = (const char*)p->Ent->B; // no change of the pointer, just to avoid overung warnings in code checkers 142 143 // read long file name 144 TCHAR lname[] = {s[1], s[3], s[5], s[7], s[9], s[14], s[16], s[18], s[20], s[22], s[24], s[28], s[30]}; 145 146 long_name = String(lname, 13) + long_name; 147 } 148 149 if (!IS_LNAME(attr.b) && !attr.a.volume) { 150 // get file size 151 w32fd.nFileSizeLow = e.size; 152 153 // convert date/time attribute into FILETIME 154 const filedate& date = e.date; 155 const filetime& time = e.time; 156 SYSTEMTIME stime; 157 FILETIME ftime; 158 159 stime.wYear = date.year + 1980; 160 stime.wMonth = date.month; 161 stime.wDayOfWeek = (WORD)-1; 162 stime.wDay = date.day; 163 stime.wHour = time.hour; 164 stime.wMinute = time.min; 165 stime.wSecond = time.sec2 * 2; 166 stime.wMilliseconds = 0; 167 168 if (SystemTimeToFileTime(&stime, &ftime)) 169 LocalFileTimeToFileTime(&ftime, &w32fd.ftLastWriteTime); 170 171 if (!(w32fd.dwFileAttributes & ATTRIBUTE_ERASED)) { //@@ 172 Entry* entry; 173 174 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 175 _tcscpy_s(pname, plen, w32fd.cFileName); 176 entry = new FATDirectory(_drive, this, buffer, e.fclus); 177 } else 178 entry = new FATEntry(this, e.fclus); 179 180 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 181 182 if (!long_name.empty()) { 183 entry->_content = _tcsdup(long_name); 184 long_name.erase(); 185 } 186 187 if (!first_entry) 188 first_entry = entry; 189 190 if (last) 191 last->_next = entry; 192 193 entry->_level = level; 194 195 last = entry; 196 } 197 } 198 } 199 200 if (last) 201 last->_next = NULL; 202 203 _down = first_entry; 204 _scanned = true; 205 } 206 207 208 const void* FATDirectory::get_next_path_component(const void* p) const 209 { 210 LPCTSTR s = (LPCTSTR) p; 211 212 while(*s && *s!=TEXT('\\') && *s!=TEXT('/')) 213 ++s; 214 215 while(*s==TEXT('\\') || *s==TEXT('/')) 216 ++s; 217 218 if (!*s) 219 return NULL; 220 221 return s; 222 } 223 224 225 Entry* FATDirectory::find_entry(const void* p) 226 { 227 LPCTSTR name = (LPCTSTR)p; 228 229 for(Entry*entry=_down; entry; entry=entry->_next) { 230 LPCTSTR p = name; 231 LPCTSTR q = entry->_data.cFileName; 232 233 do { 234 if (!*p || *p==TEXT('\\') || *p==TEXT('/')) 235 return entry; 236 } while(tolower(*p++) == tolower(*q++)); 237 238 p = name; 239 q = entry->_data.cAlternateFileName; 240 241 do { 242 if (!*p || *p==TEXT('\\') || *p==TEXT('/')) 243 return entry; 244 } while(tolower(*p++) == tolower(*q++)); 245 } 246 247 return NULL; 248 } 249 250 251 // get full path of specified directory entry 252 bool FATEntry::get_path(PTSTR path, size_t path_count) const 253 { 254 return get_path_base ( path, path_count, ET_FAT ); 255 } 256 257 ShellPath FATEntry::create_absolute_pidl() const 258 { 259 CONTEXT("WinEntry::create_absolute_pidl()"); 260 261 return (LPCITEMIDLIST)NULL; 262 /* prepend root path if the drive is currently actually mounted in the file system -> return working PIDL 263 TCHAR path[MAX_PATH]; 264 265 if (get_path(path, COUNTOF(path))) 266 return ShellPath(path); 267 268 return ShellPath(); 269 */ 270 } 271 272 273 FATDirectory::FATDirectory(FATDrive& drive, LPCTSTR root_path) 274 : FATEntry(), 275 _drive(drive) 276 { 277 _path = _tcsdup(root_path); 278 279 _secarr = NULL; 280 _cur_bufs = 0; 281 _ents = 0; 282 _dir = NULL; 283 _cluster = 0; 284 } 285 286 FATDirectory::FATDirectory(FATDrive& drive, Entry* parent, LPCTSTR path, unsigned cluster) 287 : FATEntry(parent, cluster), 288 _drive(drive) 289 { 290 _path = _tcsdup(path); 291 292 _secarr = NULL; 293 _cur_bufs = 0; 294 _ents = 0; 295 _dir = NULL; 296 } 297 298 FATDirectory::~FATDirectory() 299 { 300 free(_path); 301 _path = NULL; 302 } 303 304 bool FATDirectory::read_dir() 305 { 306 int i; 307 308 if (_cluster == 0) { 309 if (!_drive._boot_sector.SectorsPerFAT) { // FAT32? [boot_sector32->reserved0==0] 310 BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; 311 DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32; // lese Root-Directory ein 312 int RootEntries = boot_sector32->RootSectors * 32; //@@ 313 314 _secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=RootEntries)/_drive._bufents))); 315 316 for(i=0; i<_cur_bufs; i++) 317 _secarr->s[i] = sect+i; 318 319 _dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); 320 if (!_dir) 321 return false; 322 323 if (!(_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs))) 324 return false; 325 } else { 326 DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT; // read in root directory 327 328 _secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=_drive._boot_sector.RootEntries)/_drive._bufents))); 329 330 for(i=0; i<_cur_bufs; i++) 331 _secarr->s[i] = sect+i; 332 333 _dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); 334 if (!_dir) 335 return false; 336 337 if (!_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs)) 338 return false; 339 } 340 } else { 341 Buffer* buf; 342 bool ok; 343 344 DWORD h = _cluster; 345 346 _cur_bufs = 0; 347 348 do { 349 h = _drive.read_FAT(h, ok); 350 351 if (!ok) 352 return false; 353 354 _cur_bufs++; 355 } while (h<0x0ffffff0 && h); 356 357 _secarr = (struct dirsecz*) malloc(sizeof(DWORD) * _cur_bufs); 358 359 if (!_secarr) 360 return false; 361 362 _ents = _drive._bufents * (size_t)_cur_bufs * _drive._SClus; 363 364 if ((buf=(Buffer*)(_dir=(struct dirent*)malloc((size_t) (_ents+16)*sizeof(union DEntry)))) == NULL) 365 return false; 366 367 h = _cluster; 368 369 DWORD fdatsec; 370 371 if (!_drive._boot_sector.SectorsPerFAT) { // FAT32 ? 372 BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; 373 //int RootEntries = boot_sector32->RootSectors * 32; //@@ 374 //fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec 375 fdatsec = _drive._boot_sector.ReservedSectors + 376 _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + boot_sector32->RootSectors; 377 } else 378 fdatsec = _drive._boot_sector.ReservedSectors + 379 _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT + 380 _drive._boot_sector.RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec 381 382 for(i=0; i<_cur_bufs; i++) { 383 _secarr->s[i] = fdatsec + (DWORD)_drive._SClus*(h-2); 384 385 h = _drive.read_FAT(h, ok); 386 387 if (!ok) 388 return false; 389 } 390 391 for(i=0; i<_cur_bufs; i++) { 392 if ((ok = (_drive.read_sector(_secarr->s[i], buf, _drive._SClus))) == true) 393 AddP(buf, _drive._bufl*_drive._SClus) 394 else { 395 //@@FPara = _secarr->s[i]; 396 return false; 397 } 398 } 399 400 buf->dat[0] = 0; // Endekennzeichen f�r Rekurs setzen 401 } 402 403 return true; 404 } 405 406 407 #ifdef _MSC_VER 408 #pragma warning(disable: 4355) 409 #endif 410 411 FATDrive::FATDrive(LPCTSTR path) 412 : FATDirectory(*this, TEXT("\\")) 413 { 414 _bufl = 0; 415 _bufents = 0; 416 _SClus = 0; 417 _FATCache = NULL; 418 _CacheCount = 0; 419 _CacheSec = NULL; 420 _CacheCnt = NULL; 421 _CacheDty = NULL; 422 _Caches = 0; 423 424 _hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); 425 426 if (_hDrive != INVALID_HANDLE_VALUE) { 427 _boot_sector.BytesPerSector = 512; 428 429 if (read_sector(0, (Buffer*)&_boot_sector, 1)) { 430 _bufl = _boot_sector.BytesPerSector; 431 _SClus = _boot_sector.SectorsPerCluster; 432 _bufents = _bufl / sizeof(union DEntry); 433 } 434 435 small_cache(); 436 } 437 } 438 439 FATDrive::~FATDrive() 440 { 441 if (_hDrive != INVALID_HANDLE_VALUE) 442 CloseHandle(_hDrive); 443 444 free(_path); 445 _path = NULL; 446 } 447 448 void FATDrive::small_cache() 449 { 450 if (_FATCache) 451 free(_FATCache); 452 453 if (_CacheSec) { 454 free(_CacheSec), _CacheSec = NULL; 455 free(_CacheCnt); 456 free(_CacheDty); 457 } 458 459 _Caches = CACHE_SIZE_LOW; 460 _FATCache = (struct Cache *) malloc((_Caches+1) * _drive._bufl); 461 462 reset_cache(); 463 } 464 465 void FATDrive::reset_cache() // mark cache as empty 466 { 467 int i; 468 469 if (!_CacheSec) { 470 _CacheSec = (DWORD*) malloc(_Caches * sizeof(DWORD)); 471 _CacheCnt = (int*) malloc(_Caches * sizeof(int)); 472 _CacheDty = (bool*) malloc(_Caches * sizeof(bool)); 473 } else { 474 _CacheSec = (DWORD*) realloc(_CacheSec, _Caches * sizeof(DWORD)); 475 _CacheCnt = (int*) realloc(_CacheCnt, _Caches * sizeof(int)); 476 _CacheDty = (bool*) realloc(_CacheDty, _Caches * sizeof(bool)); 477 } 478 479 for(i=0; i<_Caches; i++) 480 _CacheSec[i] = 0; 481 482 _read_ahead = (_Caches+1) / 2; 483 } 484 485 bool FATDrive::read_sector(DWORD sec, Buffer* buf, int len) 486 { 487 sec += 63; //@@ jump to first partition 488 489 if (SetFilePointer(_hDrive, sec*_drive._boot_sector.BytesPerSector, 0, 0) == INVALID_SET_FILE_POINTER) 490 return false; 491 492 DWORD read; 493 494 if (!ReadFile(_hDrive, buf, len*_drive._boot_sector.BytesPerSector, &read, 0)) 495 return false; 496 497 return true; 498 } 499 500 DWORD FATDrive::read_FAT(DWORD cluster, bool& ok) //@@ use exception handling 501 { 502 DWORD nClus; 503 Buffer* FATBuf; 504 505 DWORD nclus = (_boot_sector.Sectors32? _boot_sector.Sectors32: _boot_sector.Sectors16) / _boot_sector.SectorsPerCluster; ///@todo cache result 506 507 if (cluster > nclus) { 508 ok = false; 509 return (DWORD)-1; 510 } 511 512 if (nclus >= 65536) { // FAT32 513 DWORD FATsec = cluster / (_boot_sector.BytesPerSector/4); 514 DWORD z = (cluster - _boot_sector.BytesPerSector/4 * FATsec)*4; 515 FATsec += _boot_sector.ReservedSectors; 516 if (!read_cache(FATsec, &FATBuf)) 517 ok = false; 518 nClus = dpeek(&FATBuf->dat[z]); 519 } else if (nclus >= 4096) { // 16 Bit-FAT 520 DWORD FATsec = cluster / (_boot_sector.BytesPerSector/2); 521 DWORD z = (cluster - _boot_sector.BytesPerSector/2 * FATsec)*2; 522 FATsec += _boot_sector.ReservedSectors; 523 if (!read_cache(FATsec, &FATBuf)) 524 ok = false; 525 nClus = wpeek(&FATBuf->dat[z]); 526 527 if (nClus >= 0xfff0) 528 nClus |= 0x0fff0000; 529 } else { // 12 Bit-FAT 530 DWORD FATsec = cluster*3 / (_boot_sector.BytesPerSector*2); 531 DWORD z = (cluster*3 - _boot_sector.BytesPerSector*2*FATsec)/2; 532 FATsec += _boot_sector.ReservedSectors; 533 if (!read_cache(FATsec,&FATBuf)) 534 ok = false; 535 BYTE a = FATBuf->dat[z++]; 536 537 if (z >= _boot_sector.BytesPerSector) 538 if (!read_cache(FATsec+1,&FATBuf)) 539 ok = false; 540 z = 0; 541 542 BYTE b = FATBuf->dat[z]; 543 544 if (cluster & 1) 545 nClus = (a>>4) | (b<<4); 546 else 547 nClus = a | ((b & 0xf)<<8); 548 549 if (nClus >= 0xff0) 550 nClus |= 0x0ffff000; 551 } 552 553 return nClus; 554 } 555 556 bool FATDrive::read_cache(DWORD sec, Buffer** bufptr) 557 { 558 int i, C, anz; 559 560 if (_boot_sector.BytesPerSector != BufLen) // no standard sector size? 561 return read_sector(sec, *bufptr=(Buffer*)&_FATCache[0], 1); 562 563 _CacheCount++; 564 565 for(i=0; _CacheSec[i]!=sec && i<_Caches; ) 566 ++i; 567 568 if (i < _Caches) 569 { 570 *bufptr = (Buffer*) &_FATCache[i]; // FAT-Sektor schon gepuffert 571 _CacheCnt[i]++; 572 return true; 573 } 574 575 i = get_cache_buffer(); 576 577 if (_cache_empty) // von get_cache_buffer() gesetzt 578 { 579 C = _CacheCount-1; 580 anz = _boot_sector.SectorsPerFAT*_boot_sector.NumberFATs - sec; 581 582 if (anz > _read_ahead) 583 anz = _read_ahead; 584 585 for(i=0; i<anz; i++) { 586 _CacheSec[i] = sec++; 587 _CacheCnt[i] = C; 588 _CacheDty[i] = 0; 589 } 590 591 _CacheCnt[0] = _CacheCount; 592 593 return read_sector(_CacheSec[0], *bufptr=(Buffer*) &_FATCache[0], anz); 594 } 595 else 596 { 597 _CacheDty[i] = 0; 598 _CacheCnt[i] = _CacheCount; 599 600 return read_sector(_CacheSec[i]=sec, *bufptr=(Buffer*) &_FATCache[i], 1); 601 } 602 } 603 604 int FATDrive::get_cache_buffer() // search for free cache buffer 605 { 606 int i, j, minCnt; 607 608 for(i=0; i<_Caches; i++) 609 if (_CacheSec[i]) 610 break; 611 612 _cache_empty = i==_Caches? true: false; 613 614 for(i=0; _CacheSec[i] && i<_Caches; ) 615 ++i; 616 617 if (i < _Caches) 618 j = i; 619 else 620 { 621 minCnt = 0; // search for least used buffer 622 623 for(j=i=0; i<_Caches; i++) 624 if (minCnt < _CacheCnt[i]) { 625 minCnt = _CacheCnt[i]; 626 j = i; 627 } 628 629 /**@todo enable write back 630 if (CacheDty[j]) // Dirty-Flag gesetzt? 631 if (writesec(_CacheSec[j], (Buffer*) &_FATCache[j], 1)) 632 FPara = _CacheSec[j], Frag(SecWriteErr); 633 */ 634 } 635 636 return j; 637 } 638 639 #endif // _DEBUG 640