ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 filedate& date = e.date;
00154             const filetime& 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;    
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 
00633   }
00634 
00635  return j;
00636 }

Generated on Sat May 26 2012 04:17:30 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.