Something went wrong. Try again.
Reactos
Something went wrong. Try again.
15 kB · 639 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640/* * Copyright 2004 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// // Explorer clone // // fatfs.cpp // // Martin Fuchs, 01.02.2004 //
#include <precomp.h>
#include "fatfs.h"
#ifdef _DEBUG
static union DEntry* link_dir_entries(struct dirent* dir, struct Kette* K, int cnt){ union DEntry* Ent = (union DEntry*) dir; struct Kette* L = NULL;
for(; cnt; cnt--) { K->Rueck = L; (L=K)->Ent = Ent; AddP(K, sizeof(struct Kette)); L->Vorw = K; AddP(Ent, sizeof(union DEntry)); }
L->Vorw = NULL;
return Ent;}
void FATDirectory::read_directory(int scan_flags){ CONTEXT("FATDirectory::read_directory()");
read_dir();
union DEntry* p = (union DEntry*) _dir; int i = 0;
do {/* if (!IS_LNAME(p->E.attr) && p->E.name[0]!=FAT_DEL_CHAR) gesBytes += p->E.size;*/
AddP(p, sizeof(union DEntry)); } while(++i<_ents && p->E.name[0]);
_alloc = (struct Kette*) malloc((size_t)((_ents=i)+8)*sizeof(struct Kette)); if (!_alloc) return;
link_dir_entries(_dir, _alloc, i);
Entry* first_entry = NULL; int level = _level + 1;
Entry* last = NULL;
WIN32_FIND_DATA w32fd; FAT_attribute attr; String long_name;
TCHAR buffer[MAX_PATH];
_tcscpy(buffer, (LPCTSTR)_path); LPTSTR pname = buffer + _tcslen(buffer); int plen = COUNTOF(buffer) - _tcslen(buffer);
*pname++ = '\\'; --plen;
for(Kette*p=_alloc; p; p=p->Vorw) { memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
DEntry_E& e = p->Ent->E;
// get file/directory attributes attr.b = e.attr;
if (attr.b & (_A_DELETED | _A_ILLEGAL)) attr.b |= _A_ILLEGAL;
const char* s = e.name; LPTSTR d = w32fd.cFileName;
if (!IS_LNAME(attr.b) || e.name[0]==FAT_DEL_CHAR) { if (e.name[0] == FAT_DEL_CHAR) w32fd.dwFileAttributes |= ATTRIBUTE_ERASED; else if (IS_LNAME(attr.b)) w32fd.dwFileAttributes |= ATTRIBUTE_LONGNAME; else if (attr.a.directory) w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; else if (attr.a.volume) w32fd.dwFileAttributes |= ATTRIBUTE_VOLNAME; //@@ -> in Volume-Name der Root kopieren
// get file name *d++ = *s==FAT_DEL_CHAR? '?': *s; ++s;
for(i=0; i<7; ++i) *d++ = *s++;
while(d>w32fd.cFileName && d[-1]==' ') --d;
*d++ = '.';
for(; i<10; ++i) *d++ = *s++;
while(d>w32fd.cFileName && d[-1]==' ') --d;
if (d>w32fd.cFileName && d[-1]=='.') --d;
*d = '\0'; } else { s = (const char*)p->Ent->B; // no change of the pointer, just to avoid overung warnings in code checkers
// read long file name char 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]};
long_name = String(lname, 13) + long_name; }
if (!IS_LNAME(attr.b) && !attr.a.volume) { // get file size w32fd.nFileSizeLow = e.size;
// convert date/time attribute into FILETIME const filedate& date = e.date; const filetime& time = e.time; SYSTEMTIME stime; FILETIME ftime;
stime.wYear = date.year + 1980; stime.wMonth = date.month; stime.wDayOfWeek = (WORD)-1; stime.wDay = date.day; stime.wHour = time.hour; stime.wMinute = time.min; stime.wSecond = time.sec2 * 2; stime.wMilliseconds = 0;
if (SystemTimeToFileTime(&stime, &ftime)) LocalFileTimeToFileTime(&ftime, &w32fd.ftLastWriteTime);
if (!(w32fd.dwFileAttributes & ATTRIBUTE_ERASED)) { //@@ Entry* entry;
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { _tcscpy_s(pname, plen, w32fd.cFileName); entry = new FATDirectory(_drive, this, buffer, e.fclus); } else entry = new FATEntry(this, e.fclus);
memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
if (!long_name.empty()) { entry->_content = _tcsdup(long_name); long_name.erase(); }
if (!first_entry) first_entry = entry;
if (last) last->_next = entry;
entry->_level = level;
last = entry; } } }
if (last) last->_next = NULL;
_down = first_entry; _scanned = true;}
const void* FATDirectory::get_next_path_component(const void* p) const{ LPCTSTR s = (LPCTSTR) p;
while(*s && *s!=TEXT('\\') && *s!=TEXT('/')) ++s;
while(*s==TEXT('\\') || *s==TEXT('/')) ++s;
if (!*s) return NULL;
return s;}
Entry* FATDirectory::find_entry(const void* p){ LPCTSTR name = (LPCTSTR)p;
for(Entry*entry=_down; entry; entry=entry->_next) { LPCTSTR p = name; LPCTSTR q = entry->_data.cFileName;
do { if (!*p || *p==TEXT('\\') || *p==TEXT('/')) return entry; } while(tolower(*p++) == tolower(*q++));
p = name; q = entry->_data.cAlternateFileName;
do { if (!*p || *p==TEXT('\\') || *p==TEXT('/')) return entry; } while(tolower(*p++) == tolower(*q++)); }
return NULL;}
// get full path of specified directory entrybool FATEntry::get_path(PTSTR path, size_t path_count) const{ return get_path_base ( path, path_count, ET_FAT );}
ShellPath FATEntry::create_absolute_pidl() const{ CONTEXT("WinEntry::create_absolute_pidl()");
return (LPCITEMIDLIST)NULL;/* prepend root path if the drive is currently actually mounted in the file system -> return working PIDL TCHAR path[MAX_PATH];
if (get_path(path, COUNTOF(path))) return ShellPath(path);
return ShellPath();*/}
FATDirectory::FATDirectory(FATDrive& drive, LPCTSTR root_path) : FATEntry(), _drive(drive){ _path = _tcsdup(root_path);
_secarr = NULL; _cur_bufs = 0; _ents = 0; _dir = NULL; _cluster = 0;}
FATDirectory::FATDirectory(FATDrive& drive, Entry* parent, LPCTSTR path, unsigned cluster) : FATEntry(parent, cluster), _drive(drive){ _path = _tcsdup(path);
_secarr = NULL; _cur_bufs = 0; _ents = 0; _dir = NULL;}
FATDirectory::~FATDirectory(){ free(_path); _path = NULL;}
bool FATDirectory::read_dir(){ int i;
if (_cluster == 0) { if (!_drive._boot_sector.SectorsPerFAT) { // FAT32? [boot_sector32->reserved0==0] BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32; // lese Root-Directory ein int RootEntries = boot_sector32->RootSectors * 32; //@@
_secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=RootEntries)/_drive._bufents)));
for(i=0; i<_cur_bufs; i++) _secarr->s[i] = sect+i;
_dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); if (!_dir) return false;
if (!(_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs))) return false; } else { DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT; // read in root directory
_secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=_drive._boot_sector.RootEntries)/_drive._bufents)));
for(i=0; i<_cur_bufs; i++) _secarr->s[i] = sect+i;
_dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry)); if (!_dir) return false;
if (!_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs)) return false; } } else { Buffer* buf; bool ok;
DWORD h = _cluster;
_cur_bufs = 0;
do { h = _drive.read_FAT(h, ok);
if (!ok) return false;
_cur_bufs++; } while (h<0x0ffffff0 && h);
_secarr = (struct dirsecz*) malloc(sizeof(DWORD) * _cur_bufs);
if (!_secarr) return false;
_ents = _drive._bufents * (size_t)_cur_bufs * _drive._SClus;
if ((buf=(Buffer*)(_dir=(struct dirent*)malloc((size_t) (_ents+16)*sizeof(union DEntry)))) == NULL) return false;
h = _cluster;
DWORD fdatsec;
if (!_drive._boot_sector.SectorsPerFAT) { // FAT32 ? BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector; //int RootEntries = boot_sector32->RootSectors * 32; //@@ //fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + boot_sector32->RootSectors; } else fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT + _drive._boot_sector.RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector; // dpb.fdirsec
for(i=0; i<_cur_bufs; i++) { _secarr->s[i] = fdatsec + (DWORD)_drive._SClus*(h-2);
h = _drive.read_FAT(h, ok);
if (!ok) return false; }
for(i=0; i<_cur_bufs; i++) { if ((ok = (_drive.read_sector(_secarr->s[i], buf, _drive._SClus))) == true) AddP(buf, _drive._bufl*_drive._SClus) else { //@@FPara = _secarr->s[i]; return false; } }
buf->dat[0] = 0; // Endekennzeichen für Rekurs setzen }
return true;}
#ifdef _MSC_VER#pragma warning(disable: 4355)#endif
FATDrive::FATDrive(LPCTSTR path) : FATDirectory(*this, TEXT("\\")){ _bufl = 0; _bufents = 0; _SClus = 0; _FATCache = NULL; _CacheCount = 0; _CacheSec = NULL; _CacheCnt = NULL; _CacheDty = NULL; _Caches = 0;
_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (_hDrive != INVALID_HANDLE_VALUE) { _boot_sector.BytesPerSector = 512;
if (read_sector(0, (Buffer*)&_boot_sector, 1)) { _bufl = _boot_sector.BytesPerSector; _SClus = _boot_sector.SectorsPerCluster; _bufents = _bufl / sizeof(union DEntry); }
small_cache(); }}
FATDrive::~FATDrive(){ if (_hDrive != INVALID_HANDLE_VALUE) CloseHandle(_hDrive);
free(_path); _path = NULL;}
void FATDrive::small_cache(){ if (_FATCache) free(_FATCache);
if (_CacheSec) { free(_CacheSec), _CacheSec = NULL; free(_CacheCnt); free(_CacheDty); }
_Caches = CACHE_SIZE_LOW; _FATCache = (struct Cache *) malloc((_Caches+1) * _drive._bufl);
reset_cache();}
void FATDrive::reset_cache() // mark cache as empty{ int i;
if (!_CacheSec) { _CacheSec = (DWORD*) malloc(_Caches * sizeof(DWORD)); _CacheCnt = (int*) malloc(_Caches * sizeof(int)); _CacheDty = (bool*) malloc(_Caches * sizeof(bool)); } else { _CacheSec = (DWORD*) realloc(_CacheSec, _Caches * sizeof(DWORD)); _CacheCnt = (int*) realloc(_CacheCnt, _Caches * sizeof(int)); _CacheDty = (bool*) realloc(_CacheDty, _Caches * sizeof(bool)); }
for(i=0; i<_Caches; i++) _CacheSec[i] = 0;
_read_ahead = (_Caches+1) / 2;}
bool FATDrive::read_sector(DWORD sec, Buffer* buf, int len){ sec += 63; //@@ jump to first partition
if (SetFilePointer(_hDrive, sec*_drive._boot_sector.BytesPerSector, 0, 0) == INVALID_SET_FILE_POINTER) return false;
DWORD read;
if (!ReadFile(_hDrive, buf, len*_drive._boot_sector.BytesPerSector, &read, 0)) return false;
return true;}
DWORD FATDrive::read_FAT(DWORD cluster, bool& ok) //@@ use exception handling{ DWORD nClus; Buffer* FATBuf;
DWORD nclus = (_boot_sector.Sectors32? _boot_sector.Sectors32: _boot_sector.Sectors16) / _boot_sector.SectorsPerCluster; ///@todo cache result
if (cluster > nclus) { ok = false; return (DWORD)-1; }
if (nclus >= 65536) { // FAT32 DWORD FATsec = cluster / (_boot_sector.BytesPerSector/4); DWORD z = (cluster - _boot_sector.BytesPerSector/4 * FATsec)*4; FATsec += _boot_sector.ReservedSectors; if (!read_cache(FATsec, &FATBuf)) ok = false; nClus = dpeek(&FATBuf->dat[z]); } else if (nclus >= 4096) { // 16 Bit-FAT DWORD FATsec = cluster / (_boot_sector.BytesPerSector/2); DWORD z = (cluster - _boot_sector.BytesPerSector/2 * FATsec)*2; FATsec += _boot_sector.ReservedSectors; if (!read_cache(FATsec, &FATBuf)) ok = false; nClus = wpeek(&FATBuf->dat[z]);
if (nClus >= 0xfff0) nClus |= 0x0fff0000; } else { // 12 Bit-FAT DWORD FATsec = cluster*3 / (_boot_sector.BytesPerSector*2); DWORD z = (cluster*3 - _boot_sector.BytesPerSector*2*FATsec)/2; FATsec += _boot_sector.ReservedSectors; if (!read_cache(FATsec,&FATBuf)) ok = false; BYTE a = FATBuf->dat[z++];
if (z >= _boot_sector.BytesPerSector) if (!read_cache(FATsec+1,&FATBuf)) ok = false; z = 0;
BYTE b = FATBuf->dat[z];
if (cluster & 1) nClus = (a>>4) | (b<<4); else nClus = a | ((b & 0xf)<<8);
if (nClus >= 0xff0) nClus |= 0x0ffff000; }
return nClus;}
bool FATDrive::read_cache(DWORD sec, Buffer** bufptr){ int i, C, anz;
if (_boot_sector.BytesPerSector != BufLen) // no standard sector size? return read_sector(sec, *bufptr=(Buffer*)&_FATCache[0], 1);
_CacheCount++;
for(i=0; _CacheSec[i]!=sec && i<_Caches; ) ++i;
if (i < _Caches) { *bufptr = (Buffer*) &_FATCache[i]; // FAT-Sektor schon gepuffert _CacheCnt[i]++; return true; }
i = get_cache_buffer();
if (_cache_empty) // von get_cache_buffer() gesetzt { C = _CacheCount-1; anz = _boot_sector.SectorsPerFAT*_boot_sector.NumberFATs - sec;
if (anz > _read_ahead) anz = _read_ahead;
for(i=0; i<anz; i++) { _CacheSec[i] = sec++; _CacheCnt[i] = C; _CacheDty[i] = 0; }
_CacheCnt[0] = _CacheCount;
return read_sector(_CacheSec[0], *bufptr=(Buffer*) &_FATCache[0], anz); } else { _CacheDty[i] = 0; _CacheCnt[i] = _CacheCount;
return read_sector(_CacheSec[i]=sec, *bufptr=(Buffer*) &_FATCache[i], 1); }}
int FATDrive::get_cache_buffer() // search for free cache buffer{ int i, j, minCnt;
for(i=0; i<_Caches; i++) if (_CacheSec[i]) break;
_cache_empty = i==_Caches? true: false;
for(i=0; _CacheSec[i] && i<_Caches; ) ++i;
if (i < _Caches) j = i; else { minCnt = 0; // search for least used buffer
for(j=i=0; i<_Caches; i++) if (minCnt < _CacheCnt[i]) { minCnt = _CacheCnt[i]; j = i; }
/**@todo enable write back if (CacheDty[j]) // Dirty-Flag gesetzt? if (writesec(_CacheSec[j], (Buffer*) &_FATCache[j], 1)) FPara = _CacheSec[j], Frag(SecWriteErr);*/ }
return j;}
#endif // _DEBUG