From 51612d040b2d738723e9b4c97ce5913eff8fcedb Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Mon, 2 Feb 2004 23:18:07 +0000 Subject: [PATCH] reading of FAT image files (work in progress) svn path=/trunk/; revision=8005 --- reactos/subsys/system/explorer/Jamfile | 1 + reactos/subsys/system/explorer/Makefile | 1 + reactos/subsys/system/explorer/Makefile.MinGW | 1 + reactos/subsys/system/explorer/Makefile.Wine | 1 + .../subsys/system/explorer/doc/changes.txt | 1 + .../subsys/system/explorer/doxy-footer.html | 2 +- reactos/subsys/system/explorer/explorer.dsp | 8 + .../subsys/system/explorer/explorer_intres.h | 3 +- .../subsys/system/explorer/explorer_intres.rc | 2 +- .../subsys/system/explorer/shell/entries.h | 6 +- .../subsys/system/explorer/shell/fatfs.cpp | 661 ++++++++++++++++++ reactos/subsys/system/explorer/shell/fatfs.h | 258 +++++++ .../system/explorer/shell/filechild.cpp | 31 +- .../subsys/system/explorer/shell/filechild.h | 6 + .../system/explorer/shell/mainframe.cpp | 21 + .../subsys/system/explorer/shell/ntobjfs.cpp | 3 - reactos/subsys/system/explorer/shell/pane.cpp | 18 +- .../subsys/system/explorer/shell/regfs.cpp | 17 +- .../system/explorer/shell/shellbrowser.cpp | 6 + .../subsys/system/explorer/shell/shellfs.cpp | 7 - .../subsys/system/explorer/shell/unixfs.cpp | 1 - .../subsys/system/explorer/shell/winfs.cpp | 13 +- .../system/explorer/utility/utility.cpp | 3 +- 23 files changed, 1019 insertions(+), 52 deletions(-) create mode 100644 reactos/subsys/system/explorer/shell/fatfs.cpp create mode 100644 reactos/subsys/system/explorer/shell/fatfs.h diff --git a/reactos/subsys/system/explorer/Jamfile b/reactos/subsys/system/explorer/Jamfile index 189954029c7..e8f2fcf9b28 100644 --- a/reactos/subsys/system/explorer/Jamfile +++ b/reactos/subsys/system/explorer/Jamfile @@ -23,6 +23,7 @@ exe explorer : shell/winfs.cpp shell/ntobjfs.cpp shell/regfs.cpp + shell/fatfs.cpp shell/startup.c taskbar/desktopbar.cpp taskbar/quicklaunch.cpp diff --git a/reactos/subsys/system/explorer/Makefile b/reactos/subsys/system/explorer/Makefile index 21d1a9d5475..990cf3a35e1 100644 --- a/reactos/subsys/system/explorer/Makefile +++ b/reactos/subsys/system/explorer/Makefile @@ -82,6 +82,7 @@ OBJECTS = \ shellfs.o \ ntobjfs.o \ regfs.o \ + fatfs.o \ mainframe.o \ filechild.o \ pane.o \ diff --git a/reactos/subsys/system/explorer/Makefile.MinGW b/reactos/subsys/system/explorer/Makefile.MinGW index b0d61afb299..5d35b4edc43 100644 --- a/reactos/subsys/system/explorer/Makefile.MinGW +++ b/reactos/subsys/system/explorer/Makefile.MinGW @@ -56,6 +56,7 @@ OBJECTS = \ shellfs.o \ ntobjfs.o \ regfs.o \ + fatfs.o \ mainframe.o \ filechild.o \ pane.o \ diff --git a/reactos/subsys/system/explorer/Makefile.Wine b/reactos/subsys/system/explorer/Makefile.Wine index 6a73833d169..f84158f92aa 100644 --- a/reactos/subsys/system/explorer/Makefile.Wine +++ b/reactos/subsys/system/explorer/Makefile.Wine @@ -30,6 +30,7 @@ CPP_SRCS = \ shell/pane.cpp \ shell/shellbrowser.cpp \ shell/ntobjfs.cpp \ + shell/fatfs.cpp \ shell/regfs.cpp \ taskbar/desktopbar.cpp \ taskbar/taskbar.cpp \ diff --git a/reactos/subsys/system/explorer/doc/changes.txt b/reactos/subsys/system/explorer/doc/changes.txt index 9c1aae589a0..c8573e4a55d 100644 --- a/reactos/subsys/system/explorer/doc/changes.txt +++ b/reactos/subsys/system/explorer/doc/changes.txt @@ -59,3 +59,4 @@ If you search for more information, look into the CVS repository. 18.01.2004 m. fuchs explorer/desktop settings property sheet 31.01.2004 m. fuchs included NT Object namespace as virtual file system 31.01.2004 m. fuchs included Registry as virtual file system +02.02.2004 m. fuchs reading of FAT image files diff --git a/reactos/subsys/system/explorer/doxy-footer.html b/reactos/subsys/system/explorer/doxy-footer.html index 32c0449b746..a64ab65e893 100644 --- a/reactos/subsys/system/explorer/doxy-footer.html +++ b/reactos/subsys/system/explorer/doxy-footer.html @@ -3,7 +3,7 @@
ROS Explorer Source Code Documentation -
generated on 01.02.2004 by +
generated on 03.02.2004 by
doxygen
diff --git a/reactos/subsys/system/explorer/explorer.dsp b/reactos/subsys/system/explorer/explorer.dsp index b50ba704bf1..a33392fb841 100644 --- a/reactos/subsys/system/explorer/explorer.dsp +++ b/reactos/subsys/system/explorer/explorer.dsp @@ -728,6 +728,14 @@ SOURCE=.\shell\entries.h # End Source File # Begin Source File +SOURCE=.\shell\fatfs.cpp +# End Source File +# Begin Source File + +SOURCE=.\shell\fatfs.h +# End Source File +# Begin Source File + SOURCE=.\shell\filechild.cpp # End Source File # Begin Source File diff --git a/reactos/subsys/system/explorer/explorer_intres.h b/reactos/subsys/system/explorer/explorer_intres.h index 0d70dc01904..b049da16af4 100644 --- a/reactos/subsys/system/explorer/explorer_intres.h +++ b/reactos/subsys/system/explorer/explorer_intres.h @@ -120,7 +120,8 @@ #define ID_DRIVE_UNIX_FS 0x9002 #define ID_DRIVE_NTOBJ_NS 0x9003 #define ID_DRIVE_REGISTRY 0x9004 -#define ID_DRIVE_FIRST 0x9005 +#define ID_DRIVE_FAT 0x9005 +#define ID_DRIVE_FIRST 0x9006 #define ID_ABOUT_WINDOWS 40002 #define ID_ABOUT_EXPLORER 40003 #define ID_DESKTOPBAR_SETTINGS 40005 diff --git a/reactos/subsys/system/explorer/explorer_intres.rc b/reactos/subsys/system/explorer/explorer_intres.rc index 7a1fcab119d..dda2bd8378d 100644 --- a/reactos/subsys/system/explorer/explorer_intres.rc +++ b/reactos/subsys/system/explorer/explorer_intres.rc @@ -353,7 +353,7 @@ CAPTION "About ReactOS Explorer" FONT 10, "MS Sans Serif" BEGIN LTEXT "ReactOS Explorer",IDC_ROS_EXPLORER,91,29,90,11 - LTEXT "(c) 2003 Martin Fuchs",IDC_STATIC,90,50,70,8 + LTEXT "(c) 2003/2004 Martin Fuchs",IDC_STATIC,90,50,79,8 LTEXT "http://www.sky.franken.de/explorer/",IDC_WWW,21,84,104, 8 CONTROL "&OK",IDOK,"Button",BS_OWNERDRAW | BS_FLAT | WS_GROUP, diff --git a/reactos/subsys/system/explorer/shell/entries.h b/reactos/subsys/system/explorer/shell/entries.h index acf146e111b..7050c55828b 100644 --- a/reactos/subsys/system/explorer/shell/entries.h +++ b/reactos/subsys/system/explorer/shell/entries.h @@ -33,7 +33,8 @@ enum ENTRY_TYPE { #endif ET_SHELL, ET_NTOBJS, - ET_REGISTRY + ET_REGISTRY, + ET_FAT }; enum SORT_ORDER { @@ -54,6 +55,9 @@ enum SCAN_FLAGS { }; #ifndef ATTRIBUTE_SYMBOLIC_LINK +#define ATTRIBUTE_LONGNAME 0x08000000 +#define ATTRIBUTE_VOLNAME 0x10000000 +#define ATTRIBUTE_ERASED 0x20000000 #define ATTRIBUTE_SYMBOLIC_LINK 0x40000000 #define ATTRIBUTE_EXECUTABLE 0x80000000 #endif diff --git a/reactos/subsys/system/explorer/shell/fatfs.cpp b/reactos/subsys/system/explorer/shell/fatfs.cpp new file mode 100644 index 00000000000..1dbe4c8bd1b --- /dev/null +++ b/reactos/subsys/system/explorer/shell/fatfs.cpp @@ -0,0 +1,661 @@ +/* + * Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // Explorer clone + // + // fatfs.cpp + // + // Martin Fuchs, 01.02.2004 + // + + +#include "../utility/utility.h" +#include "../utility/shellclasses.h" +#include "../globals.h" + +#include "entries.h" +#include "fatfs.h" + + +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); + + *pname++ = '\\'; + + 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 { + // read long file name + 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]}; + + 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 fdate& date = e.date; + const ftime& 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(pname, 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; +} + + +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 entry +bool FATEntry::get_path(PTSTR path) const +{ + int level = 0; + int len = 0; + int l = 0; + LPCTSTR name = NULL; + TCHAR buffer[MAX_PATH]; + + const Entry* entry; + for(entry=this; entry; level++) { + l = 0; + + if (entry->_etype == ET_FAT) { + name = entry->_data.cFileName; + + for(LPCTSTR s=name; *s && *s!=TEXT('/') && *s!=TEXT('\\'); s++) + ++l; + + if (!entry->_up) + break; + } else { + if (entry->get_path(buffer)) { + l = _tcslen(buffer); + name = buffer; + + /* special handling of drive names */ + if (l>0 && buffer[l-1]=='\\' && path[0]=='\\') + --l; + + memmove(path+l, path, len*sizeof(TCHAR)); + memcpy(path, name, l*sizeof(TCHAR)); + len += l; + } + + entry = NULL; + break; + } + + if (l > 0) { + memmove(path+l+1, path, len*sizeof(TCHAR)); + memcpy(path+1, name, l*sizeof(TCHAR)); + len += l+1; + + path[0] = TEXT('\\'); + } + + entry = entry->_up; + } + + if (entry) { + memmove(path+l, path, len*sizeof(TCHAR)); + memcpy(path, name, l*sizeof(TCHAR)); + len += l; + } + + if (!level) + path[len++] = TEXT('\\'); + + path[len] = TEXT('\0'); + + return true; +} + + +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, 0, 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