fatfs.cpp

Go to the documentation of this file.
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 doxygen

ROS Explorer Homepage