00001 /* 00002 * Copyright 2004 Martin Fuchs 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 00020 // 00021 // Explorer clone 00022 // 00023 // fatfs.cpp 00024 // 00025 // Martin Fuchs, 01.02.2004 00026 // 00027 00028 00029 #include <precomp.h> 00030 00031 #include "fatfs.h" 00032 00033 00034 static union DEntry* link_dir_entries(struct dirent* dir, struct Kette* K, int cnt) 00035 { 00036 union DEntry* Ent = (union DEntry*) dir; 00037 struct Kette* L = NULL; 00038 00039 for(; cnt; cnt--) { 00040 K->Rueck = L; 00041 (L=K)->Ent = Ent; 00042 AddP(K, sizeof(struct Kette)); 00043 L->Vorw = K; 00044 AddP(Ent, sizeof(union DEntry)); 00045 } 00046 00047 L->Vorw = NULL; 00048 00049 return Ent; 00050 } 00051 00052 void FATDirectory::read_directory(int scan_flags) 00053 { 00054 CONTEXT("FATDirectory::read_directory()"); 00055 00056 read_dir(); 00057 00058 union DEntry* p = (union DEntry*) _dir; 00059 int i = 0; 00060 00061 do { 00062 /* if (!IS_LNAME(p->E.attr) && p->E.name[0]!=FAT_DEL_CHAR) 00063 gesBytes += p->E.size; 00064 */ 00065 00066 AddP(p, sizeof(union DEntry)); 00067 } while(++i<_ents && p->E.name[0]); 00068 00069 _alloc = (struct Kette*) malloc((size_t)((_ents=i)+8)*sizeof(struct Kette)); 00070 if (!_alloc) 00071 return; 00072 00073 link_dir_entries(_dir, _alloc, i); 00074 00075 Entry* first_entry = NULL; 00076 int level = _level + 1; 00077 00078 Entry* last = NULL; 00079 00080 WIN32_FIND_DATA w32fd; 00081 FAT_attribute attr; 00082 String long_name; 00083 00084 TCHAR buffer[MAX_PATH]; 00085 00086 _tcscpy(buffer, (LPCTSTR)_path); 00087 LPTSTR pname = buffer + _tcslen(buffer); 00088 int plen = COUNTOF(buffer) - _tcslen(buffer); 00089 00090 *pname++ = '\\'; 00091 --plen; 00092 00093 for(Kette*p=_alloc; p; p=p->Vorw) { 00094 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA)); 00095 00096 DEntry_E& e = p->Ent->E; 00097 00098 // get file/directory attributes 00099 attr.b = e.attr; 00100 00101 if (attr.b & (_A_DELETED | _A_ILLEGAL)) 00102 attr.b |= _A_ILLEGAL; 00103 00104 const char* s = e.name; 00105 LPTSTR d = w32fd.cFileName; 00106 00107 if (!IS_LNAME(attr.b) || e.name[0]==FAT_DEL_CHAR) { 00108 if (e.name[0] == FAT_DEL_CHAR) 00109 w32fd.dwFileAttributes |= ATTRIBUTE_ERASED; 00110 else if (IS_LNAME(attr.b)) 00111 w32fd.dwFileAttributes |= ATTRIBUTE_LONGNAME; 00112 else if (attr.a.directory) 00113 w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 00114 else if (attr.a.volume) 00115 w32fd.dwFileAttributes |= ATTRIBUTE_VOLNAME; //@@ -> in Volume-Name der Root kopieren 00116 00117 // get file name 00118 *d++ = *s==FAT_DEL_CHAR? '?': *s; 00119 ++s; 00120 00121 for(i=0; i<7; ++i) 00122 *d++ = *s++; 00123 00124 while(d>w32fd.cFileName && d[-1]==' ') 00125 --d; 00126 00127 *d++ = '.'; 00128 00129 for(; i<10; ++i) 00130 *d++ = *s++; 00131 00132 while(d>w32fd.cFileName && d[-1]==' ') 00133 --d; 00134 00135 if (d>w32fd.cFileName && d[-1]=='.') 00136 --d; 00137 00138 *d = '\0'; 00139 } else { 00140 s = (const char*)p->Ent->B; // no change of the pointer, just to avoid overung warnings in code checkers 00141 00142 // read long file name 00143 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]}; 00144 00145 long_name = String(lname, 13) + long_name; 00146 } 00147 00148 if (!IS_LNAME(attr.b) && !attr.a.volume) { 00149 // get file size 00150 w32fd.nFileSizeLow = e.size; 00151 00152 // convert date/time attribute into FILETIME 00153 const fdate& date = e.date; 00154 const ftime& time = e.time; 00155 SYSTEMTIME stime; 00156 FILETIME ftime; 00157 00158 stime.wYear = date.year + 1980; 00159 stime.wMonth = date.month; 00160 stime.wDayOfWeek = (WORD)-1; 00161 stime.wDay = date.day; 00162 stime.wHour = time.hour; 00163 stime.wMinute = time.min; 00164 stime.wSecond = time.sec2 * 2; 00165 stime.wMilliseconds = 0; 00166 00167 if (SystemTimeToFileTime(&stime, &ftime)) 00168 LocalFileTimeToFileTime(&ftime, &w32fd.ftLastWriteTime); 00169 00170 if (!(w32fd.dwFileAttributes & ATTRIBUTE_ERASED)) { //@@ 00171 Entry* entry; 00172 00173 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 00174 _tcscpy_s(pname, plen, w32fd.cFileName); 00175 entry = new FATDirectory(_drive, this, buffer, e.fclus); 00176 } else 00177 entry = new FATEntry(this, e.fclus); 00178 00179 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 00180 00181 if (!long_name.empty()) { 00182 entry->_content = _tcsdup(long_name); 00183 long_name.erase(); 00184 } 00185 00186 if (!first_entry) 00187 first_entry = entry; 00188 00189 if (last) 00190 last->_next = entry; 00191 00192 entry->_level = level; 00193 00194 last = entry; 00195 } 00196 } 00197 } 00198 00199 if (last) 00200 last->_next = NULL; 00201 00202 _down = first_entry; 00203 _scanned = true; 00204 } 00205 00206 00207 const void* FATDirectory::get_next_path_component(const void* p) const 00208 { 00209 LPCTSTR s = (LPCTSTR) p; 00210 00211 while(*s && *s!=TEXT('\\') && *s!=TEXT('/')) 00212 ++s; 00213 00214 while(*s==TEXT('\\') || *s==TEXT('/')) 00215 ++s; 00216 00217 if (!*s) 00218 return NULL; 00219 00220 return s; 00221 } 00222 00223 00224 Entry* FATDirectory::find_entry(const void* p) 00225 { 00226 LPCTSTR name = (LPCTSTR)p; 00227 00228 for(Entry*entry=_down; entry; entry=entry->_next) { 00229 LPCTSTR p = name; 00230 LPCTSTR q = entry->_data.cFileName; 00231 00232 do { 00233 if (!*p || *p==TEXT('\\') || *p==TEXT('/')) 00234 return entry; 00235 } while(tolower(*p++) == tolower(*q++)); 00236 00237 p = name; 00238 q = entry->_data.cAlternateFileName; 00239 00240 do { 00241 if (!*p || *p==TEXT('\\') || *p==TEXT('/')) 00242 return entry; 00243 } while(tolower(*p++) == tolower(*q++)); 00244 } 00245 00246 return NULL; 00247 } 00248 00249 00250 // get full path of specified directory entry 00251 bool FATEntry::get_path(PTSTR path, size_t path_count) const 00252 { 00253 return get_path_base ( path, path_count, ET_FAT ); 00254 } 00255 00256 ShellPath FATEntry::create_absolute_pidl() const 00257 { 00258 CONTEXT("WinEntry::create_absolute_pidl()"); 00259 00260 return (LPCITEMIDLIST)NULL; 00261 /* prepend root path if the drive is currently actually mounted in the file system -> return working PIDL 00262 TCHAR path[MAX_PATH]; 00263 00264 if (get_path(path, COUNTOF(path))) 00265 return ShellPath(path); 00266 00267 return ShellPath(); 00268 */ 00269 } 00270 00271 00272 FATDirectory::FATDirectory(FATDrive& drive, LPCTSTR root_path) 00273 : FATEntry(), 00274 _drive(drive) 00275 { 00276 _path = _tcsdup(root_path); 00277 00278 _secarr = NULL; 00279 _cur_bufs = 0; 00280 _ents = 0; 00281 _dir = NULL; 00282 _cluster = 0; 00283 } 00284 00285 FATDirectory::FATDirectory(FATDrive& drive, Entry* parent, LPCTSTR path, unsigned cluster) 00286 : FATEntry(parent, cluster), 00287 _drive(drive) 00288 { 00289 _path = _tcsdup(path); 00290 00291 _secarr = NULL; 00292 _cur_bufs = 0; 00293 _ents = 0; 00294 _dir = NULL; 00295 } 00296 00297 FATDirectory::~FATDirectory() 00298 { 00299 free(_path); 00300 _path = NULL; 00301 } 00302 00303 bool FATDirectory::read_dir() 00304 { 00305 int i; 00306 00307 if (_cluster == 0) { 00308 if (!_drive._boot_sector.SectorsPerFAT) { // FAT32? [boot_sector32->reserved0==0] 00309 BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; 00310 DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32; // lese Root-Directory ein 00311 int RootEntries = boot_sector32->RootSectors * 32; //@@ 00312 00313 _secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=RootEntries)/_drive._bufents))); 00314 00315 for(i=0; i<_cur_bufs; i++) 00316 _secarr->s[i] = sect+i; 00317 00318 _dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); 00319 if (!_dir) 00320 return false; 00321 00322 if (!(_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs))) 00323 return false; 00324 } else { 00325 DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT; // read in root directory 00326 00327 _secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=_drive._boot_sector.RootEntries)/_drive._bufents))); 00328 00329 for(i=0; i<_cur_bufs; i++) 00330 _secarr->s[i] = sect+i; 00331 00332 _dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); 00333 if (!_dir) 00334 return false; 00335 00336 if (!_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs)) 00337 return false; 00338 } 00339 } else { 00340 Buffer* buf; 00341 bool ok; 00342 00343 DWORD h = _cluster; 00344 00345 _cur_bufs = 0; 00346 00347 do { 00348 h = _drive.read_FAT(h, ok); 00349 00350 if (!ok) 00351 return false; 00352 00353 _cur_bufs++; 00354 } while (h<0x0ffffff0 && h); 00355 00356 _secarr = (struct dirsecz*) malloc(sizeof(DWORD) * _cur_bufs); 00357 00358 if (!_secarr) 00359 return false; 00360 00361 _ents = _drive._bufents * (size_t)_cur_bufs * _drive._SClus; 00362 00363 if ((buf=(Buffer*)(_dir=(struct dirent*)malloc((size_t) (_ents+16)*sizeof(union DEntry)))) == NULL) 00364 return false; 00365 00366 h = _cluster; 00367 00368 DWORD fdatsec; 00369 00370 if (!_drive._boot_sector.SectorsPerFAT) { // FAT32 ? 00371 BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; 00372 //int RootEntries = boot_sector32->RootSectors * 32; //@@ 00373 //fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec 00374 fdatsec = _drive._boot_sector.ReservedSectors + 00375 _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + boot_sector32->RootSectors; 00376 } else 00377 fdatsec = _drive._boot_sector.ReservedSectors + 00378 _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT + 00379 _drive._boot_sector.RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec 00380 00381 for(i=0; i<_cur_bufs; i++) { 00382 _secarr->s[i] = fdatsec + (DWORD)_drive._SClus*(h-2); 00383 00384 h = _drive.read_FAT(h, ok); 00385 00386 if (!ok) 00387 return false; 00388 } 00389 00390 for(i=0; i<_cur_bufs; i++) { 00391 if ((ok = (_drive.read_sector(_secarr->s[i], buf, _drive._SClus))) == true) 00392 AddP(buf, _drive._bufl*_drive._SClus) 00393 else { 00394 //@@FPara = _secarr->s[i]; 00395 return false; 00396 } 00397 } 00398 00399 buf->dat[0] = 0; // Endekennzeichen für Rekurs setzen 00400 } 00401 00402 return true; 00403 } 00404 00405 00406 #ifdef _MSC_VER 00407 #pragma warning(disable: 4355) 00408 #endif 00409 00410 FATDrive::FATDrive(LPCTSTR path) 00411 : FATDirectory(*this, TEXT("\\")) 00412 { 00413 _bufl = 0; 00414 _bufents = 0; 00415 _SClus = 0; 00416 _FATCache = NULL; 00417 _CacheCount = 0; 00418 _CacheSec = NULL; 00419 _CacheCnt = NULL; 00420 _CacheDty = NULL; 00421 _Caches = 0; 00422 00423 _hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); 00424 00425 if (_hDrive != INVALID_HANDLE_VALUE) { 00426 _boot_sector.BytesPerSector = 512; 00427 00428 if (read_sector(0, (Buffer*)&_boot_sector, 1)) { 00429 _bufl = _boot_sector.BytesPerSector; 00430 _SClus = _boot_sector.SectorsPerCluster; 00431 _bufents = _bufl / sizeof(union DEntry); 00432 } 00433 00434 small_cache(); 00435 } 00436 } 00437 00438 FATDrive::~FATDrive() 00439 { 00440 if (_hDrive != INVALID_HANDLE_VALUE) 00441 CloseHandle(_hDrive); 00442 00443 free(_path); 00444 _path = NULL; 00445 } 00446 00447 void FATDrive::small_cache() 00448 { 00449 if (_FATCache) 00450 free(_FATCache); 00451 00452 if (_CacheSec) { 00453 free(_CacheSec), _CacheSec = NULL; 00454 free(_CacheCnt); 00455 free(_CacheDty); 00456 } 00457 00458 _Caches = CACHE_SIZE_LOW; 00459 _FATCache = (struct Cache *) malloc((_Caches+1) * _drive._bufl); 00460 00461 reset_cache(); 00462 } 00463 00464 void FATDrive::reset_cache() // mark cache as empty 00465 { 00466 int i; 00467 00468 if (!_CacheSec) { 00469 _CacheSec = (DWORD*) malloc(_Caches * sizeof(DWORD)); 00470 _CacheCnt = (int*) malloc(_Caches * sizeof(int)); 00471 _CacheDty = (bool*) malloc(_Caches * sizeof(bool)); 00472 } else { 00473 _CacheSec = (DWORD*) realloc(_CacheSec, _Caches * sizeof(DWORD)); 00474 _CacheCnt = (int*) realloc(_CacheCnt, _Caches * sizeof(int)); 00475 _CacheDty = (bool*) realloc(_CacheDty, _Caches * sizeof(bool)); 00476 } 00477 00478 for(i=0; i<_Caches; i++) 00479 _CacheSec[i] = 0; 00480 00481 _read_ahead = (_Caches+1) / 2; 00482 } 00483 00484 bool FATDrive::read_sector(DWORD sec, Buffer* buf, int len) 00485 { 00486 sec += 63; //@@ jump to first partition 00487 00488 if (SetFilePointer(_hDrive, sec*_drive._boot_sector.BytesPerSector, 0, 0) == INVALID_SET_FILE_POINTER) 00489 return false; 00490 00491 DWORD read; 00492 00493 if (!ReadFile(_hDrive, buf, len*_drive._boot_sector.BytesPerSector, &read, 0)) 00494 return false; 00495 00496 return true; 00497 } 00498 00499 DWORD FATDrive::read_FAT(DWORD cluster, bool& ok) //@@ use exception handling 00500 { 00501 DWORD nClus; 00502 Buffer* FATBuf; 00503 00504 DWORD nclus = (_boot_sector.Sectors32? _boot_sector.Sectors32: _boot_sector.Sectors16) / _boot_sector.SectorsPerCluster; ///@todo cache result 00505 00506 if (cluster > nclus) { 00507 ok = false; 00508 return (DWORD)-1; 00509 } 00510 00511 if (nclus >= 65536) { // FAT32 00512 DWORD FATsec = cluster / (_boot_sector.BytesPerSector/4); 00513 DWORD z = (cluster - _boot_sector.BytesPerSector/4 * FATsec)*4; 00514 FATsec += _boot_sector.ReservedSectors; 00515 if (!read_cache(FATsec, &FATBuf)) 00516 ok = false; 00517 nClus = dpeek(&FATBuf->dat[z]); 00518 } else if (nclus >= 4096) { // 16 Bit-FAT 00519 DWORD FATsec = cluster / (_boot_sector.BytesPerSector/2); 00520 DWORD z = (cluster - _boot_sector.BytesPerSector/2 * FATsec)*2; 00521 FATsec += _boot_sector.ReservedSectors; 00522 if (!read_cache(FATsec, &FATBuf)) 00523 ok = false; 00524 nClus = wpeek(&FATBuf->dat[z]); 00525 00526 if (nClus >= 0xfff0) 00527 nClus |= 0x0fff0000; 00528 } else { // 12 Bit-FAT 00529 DWORD FATsec = cluster*3 / (_boot_sector.BytesPerSector*2); 00530 DWORD z = (cluster*3 - _boot_sector.BytesPerSector*2*FATsec)/2; 00531 FATsec += _boot_sector.ReservedSectors; 00532 if (!read_cache(FATsec,&FATBuf)) 00533 ok = false; 00534 BYTE a = FATBuf->dat[z++]; 00535 00536 if (z >= _boot_sector.BytesPerSector) 00537 if (!read_cache(FATsec+1,&FATBuf)) 00538 ok = false; 00539 z = 0; 00540 00541 BYTE b = FATBuf->dat[z]; 00542 00543 if (cluster & 1) 00544 nClus = (a>>4) | (b<<4); 00545 else 00546 nClus = a | ((b & 0xf)<<8); 00547 00548 if (nClus >= 0xff0) 00549 nClus |= 0x0ffff000; 00550 } 00551 00552 return nClus; 00553 } 00554 00555 bool FATDrive::read_cache(DWORD sec, Buffer** bufptr) 00556 { 00557 int i, C, anz; 00558 00559 if (_boot_sector.BytesPerSector != BufLen) // no standard sector size? 00560 return read_sector(sec, *bufptr=(Buffer*)&_FATCache[0], 1); 00561 00562 _CacheCount++; 00563 00564 for(i=0; _CacheSec[i]!=sec && i<_Caches; ) 00565 ++i; 00566 00567 if (i < _Caches) 00568 { 00569 *bufptr = (Buffer*) &_FATCache[i]; // FAT-Sektor schon gepuffert 00570 _CacheCnt[i]++; 00571 return true; 00572 } 00573 00574 i = get_cache_buffer(); 00575 00576 if (_cache_empty) // von get_cache_buffer() gesetzt 00577 { 00578 C = _CacheCount-1; 00579 anz = _boot_sector.SectorsPerFAT*_boot_sector.NumberFATs - sec; 00580 00581 if (anz > _read_ahead) 00582 anz = _read_ahead; 00583 00584 for(i=0; i<anz; i++) { 00585 _CacheSec[i] = sec++; 00586 _CacheCnt[i] = C; 00587 _CacheDty[i] = 0; 00588 } 00589 00590 _CacheCnt[0] = _CacheCount; 00591 00592 return read_sector(_CacheSec[0], *bufptr=(Buffer*) &_FATCache[0], anz); 00593 } 00594 else 00595 { 00596 _CacheDty[i] = 0; 00597 _CacheCnt[i] = _CacheCount; 00598 00599 return read_sector(_CacheSec[i]=sec, *bufptr=(Buffer*) &_FATCache[i], 1); 00600 } 00601 } 00602 00603 int FATDrive::get_cache_buffer() // search for free cache buffer 00604 { 00605 int i, j, minCnt; 00606 00607 for(i=0; i<_Caches; i++) 00608 if (_CacheSec[i]) 00609 break; 00610 00611 _cache_empty = i==_Caches? true: false; 00612 00613 for(i=0; _CacheSec[i] && i<_Caches; ) 00614 ++i; 00615 00616 if (i < _Caches) 00617 j = i; 00618 else 00619 { 00620 minCnt = 0; // search for least used buffer 00621 00622 for(j=i=0; i<_Caches; i++) 00623 if (minCnt < _CacheCnt[i]) { 00624 minCnt = _CacheCnt[i]; 00625 j = i; 00626 } 00627 00628 /**@todo enable write back 00629 if (CacheDty[j]) // Dirty-Flag gesetzt? 00630 if (writesec(_CacheSec[j], (Buffer*) &_FATCache[j], 1)) 00631 FPara = _CacheSec[j], Frag(SecWriteErr); 00632 */ 00633 } 00634 00635 return j; 00636 }
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |