1 /*
2  * Copyright 2004 Martin Fuchs
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 
20  //
21  // Explorer clone
22  //
23  // fatfs.cpp
24  //
25  // Martin Fuchs, 01.02.2004
26  //
27 
28 
29 #include <precomp.h>
30 
31 #include "fatfs.h"
32 
33 #ifdef _DEBUG
34 
link_dir_entries(struct dirent * dir,struct Kette * K,int cnt)35 static union DEntry* link_dir_entries(struct dirent* dir, struct Kette* K, int cnt)
36 {
37 	union DEntry* Ent = (union DEntry*) dir;
38 	struct Kette* L = NULL;
39 
40 	for(; cnt; cnt--) {
41 		K->Rueck = L;
42 		(L=K)->Ent = Ent;
43 		AddP(K, sizeof(struct Kette));
44 		L->Vorw = K;
45 		AddP(Ent, sizeof(union DEntry));
46 	}
47 
48 	L->Vorw = NULL;
49 
50 	return Ent;
51 }
52 
read_directory(int scan_flags)53 void FATDirectory::read_directory(int scan_flags)
54 {
55 	CONTEXT("FATDirectory::read_directory()");
56 
57 	read_dir();
58 
59 	union DEntry* p = (union DEntry*) _dir;
60 	int i = 0;
61 
62 	do {
63 /*		if (!IS_LNAME(p->E.attr) && p->E.name[0]!=FAT_DEL_CHAR)
64 			gesBytes += p->E.size;
65 */
66 
67 		AddP(p, sizeof(union DEntry));
68 	} while(++i<_ents && p->E.name[0]);
69 
70 	_alloc = (struct Kette*) malloc((size_t)((_ents=i)+8)*sizeof(struct Kette));
71 	if (!_alloc)
72 		return;
73 
74 	link_dir_entries(_dir, _alloc, i);
75 
76 	Entry* first_entry = NULL;
77 	int level = _level + 1;
78 
79 	Entry* last = NULL;
80 
81 	WIN32_FIND_DATA w32fd;
82 	FAT_attribute attr;
83 	String long_name;
84 
85 	TCHAR buffer[MAX_PATH];
86 
87 	_tcscpy(buffer, (LPCTSTR)_path);
88 	LPTSTR pname = buffer + _tcslen(buffer);
89 	int plen = COUNTOF(buffer) - _tcslen(buffer);
90 
91 	*pname++ = '\\';
92 	--plen;
93 
94 	for(Kette*p=_alloc; p; p=p->Vorw) {
95 		memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
96 
97 		DEntry_E& e = p->Ent->E;
98 
99 		 // get file/directory attributes
100 		attr.b = e.attr;
101 
102 		if (attr.b & (_A_DELETED | _A_ILLEGAL))
103 			attr.b |= _A_ILLEGAL;
104 
105 		const char* s = e.name;
106 		LPTSTR d = w32fd.cFileName;
107 
108 		if (!IS_LNAME(attr.b) || e.name[0]==FAT_DEL_CHAR) {
109 			if (e.name[0] == FAT_DEL_CHAR)
110 				w32fd.dwFileAttributes |= ATTRIBUTE_ERASED;
111 			else if (IS_LNAME(attr.b))
112 				w32fd.dwFileAttributes |= ATTRIBUTE_LONGNAME;
113 			else if (attr.a.directory)
114 				w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
115 			else if (attr.a.volume)
116 				w32fd.dwFileAttributes |= ATTRIBUTE_VOLNAME;	//@@ -> in Volume-Name der Root kopieren
117 
118 			 // get file name
119 			*d++ = *s==FAT_DEL_CHAR? '?': *s;
120 			++s;
121 
122 			for(i=0; i<7; ++i)
123 				*d++ = *s++;
124 
125 			while(d>w32fd.cFileName && d[-1]==' ')
126 				--d;
127 
128 			*d++ = '.';
129 
130 			for(; i<10; ++i)
131 				*d++ = *s++;
132 
133 			while(d>w32fd.cFileName && d[-1]==' ')
134 				--d;
135 
136 			if (d>w32fd.cFileName && d[-1]=='.')
137 				--d;
138 
139 			*d = '\0';
140 		} else {
141 			s = (const char*)p->Ent->B;	// no change of the pointer, just to avoid overung warnings in code checkers
142 
143 			 // read long file name
144 			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]};
145 
146 			long_name = String(lname, 13) + long_name;
147 		}
148 
149 		if (!IS_LNAME(attr.b) && !attr.a.volume) {
150 			 // get file size
151 			w32fd.nFileSizeLow = e.size;
152 
153 			 // convert date/time attribute into FILETIME
154 			const filedate& date = e.date;
155 			const filetime& time = e.time;
156 			SYSTEMTIME stime;
157 			FILETIME ftime;
158 
159 			stime.wYear = date.year + 1980;
160 			stime.wMonth = date.month;
161 			stime.wDayOfWeek = (WORD)-1;
162 			stime.wDay = date.day;
163 			stime.wHour = time.hour;
164 			stime.wMinute = time.min;
165 			stime.wSecond = time.sec2 * 2;
166 			stime.wMilliseconds = 0;
167 
168 			if (SystemTimeToFileTime(&stime, &ftime))
169 				LocalFileTimeToFileTime(&ftime, &w32fd.ftLastWriteTime);
170 
171 			if (!(w32fd.dwFileAttributes & ATTRIBUTE_ERASED)) { //@@
172 				Entry* entry;
173 
174 				if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
175 					_tcscpy_s(pname, plen, w32fd.cFileName);
176 					entry = new FATDirectory(_drive, this, buffer, e.fclus);
177 				} else
178 					entry = new FATEntry(this, e.fclus);
179 
180 				memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
181 
182 				if (!long_name.empty()) {
183 					entry->_content = _tcsdup(long_name);
184 					long_name.erase();
185 				}
186 
187 				if (!first_entry)
188 					first_entry = entry;
189 
190 				if (last)
191 					last->_next = entry;
192 
193 				entry->_level = level;
194 
195 				last = entry;
196 			}
197 		}
198 	}
199 
200 	if (last)
201 		last->_next = NULL;
202 
203 	_down = first_entry;
204 	_scanned = true;
205 }
206 
207 
get_next_path_component(const void * p) const208 const void* FATDirectory::get_next_path_component(const void* p) const
209 {
210 	LPCTSTR s = (LPCTSTR) p;
211 
212 	while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
213 		++s;
214 
215 	while(*s==TEXT('\\') || *s==TEXT('/'))
216 		++s;
217 
218 	if (!*s)
219 		return NULL;
220 
221 	return s;
222 }
223 
224 
find_entry(const void * p)225 Entry* FATDirectory::find_entry(const void* p)
226 {
227 	LPCTSTR name = (LPCTSTR)p;
228 
229 	for(Entry*entry=_down; entry; entry=entry->_next) {
230 		LPCTSTR p = name;
231 		LPCTSTR q = entry->_data.cFileName;
232 
233 		do {
234 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
235 				return entry;
236 		} while(tolower(*p++) == tolower(*q++));
237 
238 		p = name;
239 		q = entry->_data.cAlternateFileName;
240 
241 		do {
242 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
243 				return entry;
244 		} while(tolower(*p++) == tolower(*q++));
245 	}
246 
247 	return NULL;
248 }
249 
250 
251  // get full path of specified directory entry
get_path(PTSTR path,size_t path_count) const252 bool FATEntry::get_path(PTSTR path, size_t path_count) const
253 {
254 	return get_path_base ( path, path_count, ET_FAT );
255 }
256 
create_absolute_pidl() const257 ShellPath FATEntry::create_absolute_pidl() const
258 {
259 	CONTEXT("WinEntry::create_absolute_pidl()");
260 
261 	return (LPCITEMIDLIST)NULL;
262 /* prepend root path if the drive is currently actually mounted in the file system -> return working PIDL
263 	TCHAR path[MAX_PATH];
264 
265 	if (get_path(path, COUNTOF(path)))
266 		return ShellPath(path);
267 
268 	return ShellPath();
269 */
270 }
271 
272 
FATDirectory(FATDrive & drive,LPCTSTR root_path)273 FATDirectory::FATDirectory(FATDrive& drive, LPCTSTR root_path)
274  :	FATEntry(),
275 	_drive(drive)
276 {
277 	_path = _tcsdup(root_path);
278 
279 	_secarr 	= NULL;
280 	_cur_bufs	= 0;
281 	_ents		= 0;
282 	_dir		= NULL;
283 	_cluster	= 0;
284 }
285 
FATDirectory(FATDrive & drive,Entry * parent,LPCTSTR path,unsigned cluster)286 FATDirectory::FATDirectory(FATDrive& drive, Entry* parent, LPCTSTR path, unsigned cluster)
287  :	FATEntry(parent, cluster),
288 	_drive(drive)
289 {
290 	_path = _tcsdup(path);
291 
292 	_secarr 	= NULL;
293 	_cur_bufs	= 0;
294 	_ents		= 0;
295 	_dir		= NULL;
296 }
297 
~FATDirectory()298 FATDirectory::~FATDirectory()
299 {
300 	free(_path);
301 	_path = NULL;
302 }
303 
read_dir()304 bool FATDirectory::read_dir()
305 {
306 	int i;
307 
308 	if (_cluster == 0) {
309 		if (!_drive._boot_sector.SectorsPerFAT) {	// FAT32? [boot_sector32->reserved0==0]
310 			BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector;
311 			DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32;  // lese Root-Directory ein
312 			int RootEntries = boot_sector32->RootSectors * 32;	//@@
313 
314 			_secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=RootEntries)/_drive._bufents)));
315 
316 			for(i=0; i<_cur_bufs; i++)
317 				_secarr->s[i] = sect+i;
318 
319 			_dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry));
320 			if (!_dir)
321 				return false;
322 
323 			if (!(_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs)))
324 				return false;
325 		} else {
326 			DWORD sect = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT;  // read in root directory
327 
328 			_secarr = (struct dirsecz*)malloc(sizeof(DWORD) * (_cur_bufs = (int)((_ents=_drive._boot_sector.RootEntries)/_drive._bufents)));
329 
330 			for(i=0; i<_cur_bufs; i++)
331 				_secarr->s[i] = sect+i;
332 
333 			_dir = (struct dirent*)malloc((size_t)(_ents+16)*sizeof(union DEntry));
334 			if (!_dir)
335 				return false;
336 
337 			if (!_drive.read_sector(*_secarr->s,(Buffer*)_dir,_cur_bufs))
338 				return false;
339 		}
340 	} else {
341 		Buffer* buf;
342 		bool ok;
343 
344 		DWORD h = _cluster;
345 
346 		_cur_bufs = 0;
347 
348 		do {
349 			h = _drive.read_FAT(h, ok);
350 
351 			if (!ok)
352 				return false;
353 
354 			_cur_bufs++;
355 		} while (h<0x0ffffff0 && h);
356 
357 		_secarr = (struct dirsecz*) malloc(sizeof(DWORD) * _cur_bufs);
358 
359 		if (!_secarr)
360 			return false;
361 
362 		_ents = _drive._bufents * (size_t)_cur_bufs * _drive._SClus;
363 
364 		if ((buf=(Buffer*)(_dir=(struct dirent*)malloc((size_t) (_ents+16)*sizeof(union DEntry)))) == NULL)
365 			return false;
366 
367 		h = _cluster;
368 
369 		DWORD fdatsec;
370 
371 		if (!_drive._boot_sector.SectorsPerFAT) {	// FAT32 ?
372 			BootSector32* boot_sector32 = (BootSector32*) &_drive._boot_sector;
373 			//int RootEntries = boot_sector32->RootSectors * 32;	//@@
374 			//fdatsec = _drive._boot_sector.ReservedSectors + _drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector;	// dpb.fdirsec
375 			fdatsec = _drive._boot_sector.ReservedSectors +
376 						_drive._boot_sector.NumberFATs*boot_sector32->SectorsPerFAT32 + boot_sector32->RootSectors;
377 		} else
378 			fdatsec = _drive._boot_sector.ReservedSectors +
379 						_drive._boot_sector.NumberFATs*_drive._boot_sector.SectorsPerFAT +
380 						_drive._boot_sector.RootEntries*sizeof(DEntry)/_drive._boot_sector.BytesPerSector;	// dpb.fdirsec
381 
382 			for(i=0; i<_cur_bufs; i++) {
383 				_secarr->s[i] = fdatsec + (DWORD)_drive._SClus*(h-2);
384 
385 				h = _drive.read_FAT(h, ok);
386 
387 				if (!ok)
388 					return false;
389 			}
390 
391 			for(i=0; i<_cur_bufs; i++) {
392 				if ((ok = (_drive.read_sector(_secarr->s[i], buf, _drive._SClus))) == true)
393 					AddP(buf, _drive._bufl*_drive._SClus)
394 				else {
395 					//@@FPara = _secarr->s[i];
396 					return false;
397 				}
398 			}
399 
400 		buf->dat[0] = 0;	 // Endekennzeichen f�r Rekurs setzen
401 	}
402 
403 	return true;
404 }
405 
406 
407 #ifdef _MSC_VER
408 #pragma warning(disable: 4355)
409 #endif
410 
FATDrive(LPCTSTR path)411 FATDrive::FATDrive(LPCTSTR path)
412  :	FATDirectory(*this, TEXT("\\"))
413 {
414 	_bufl = 0;
415 	_bufents = 0;
416 	_SClus = 0;
417 	_FATCache = NULL;
418 	_CacheCount = 0;
419 	_CacheSec = NULL;
420 	_CacheCnt = NULL;
421 	_CacheDty = NULL;
422 	_Caches = 0;
423 
424 	_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
425 
426 	if (_hDrive != INVALID_HANDLE_VALUE) {
427 		_boot_sector.BytesPerSector = 512;
428 
429 		if (read_sector(0, (Buffer*)&_boot_sector, 1)) {
430 			_bufl = _boot_sector.BytesPerSector;
431 			_SClus = _boot_sector.SectorsPerCluster;
432 			_bufents = _bufl / sizeof(union DEntry);
433 		}
434 
435 		small_cache();
436 	}
437 }
438 
~FATDrive()439 FATDrive::~FATDrive()
440 {
441 	if (_hDrive != INVALID_HANDLE_VALUE)
442 		CloseHandle(_hDrive);
443 
444 	free(_path);
445 	_path = NULL;
446 }
447 
small_cache()448 void FATDrive::small_cache()
449 {
450 	if (_FATCache)
451 		free(_FATCache);
452 
453 	if (_CacheSec) {
454 		free(_CacheSec), _CacheSec = NULL;
455 		free(_CacheCnt);
456 		free(_CacheDty);
457 	}
458 
459 	_Caches = CACHE_SIZE_LOW;
460 	_FATCache = (struct Cache *) malloc((_Caches+1) * _drive._bufl);
461 
462 	reset_cache();
463 }
464 
reset_cache()465 void FATDrive::reset_cache()	// mark cache as empty
466 {
467 	int i;
468 
469 	if (!_CacheSec) {
470 		_CacheSec = (DWORD*) malloc(_Caches * sizeof(DWORD));
471 		_CacheCnt = (int*) malloc(_Caches * sizeof(int));
472 		_CacheDty = (bool*) malloc(_Caches * sizeof(bool));
473 	} else {
474 		_CacheSec = (DWORD*) realloc(_CacheSec, _Caches * sizeof(DWORD));
475 		_CacheCnt = (int*) realloc(_CacheCnt, _Caches * sizeof(int));
476 		_CacheDty = (bool*) realloc(_CacheDty, _Caches * sizeof(bool));
477 	}
478 
479 	for(i=0; i<_Caches; i++)
480 		_CacheSec[i] = 0;
481 
482 	_read_ahead = (_Caches+1) / 2;
483 }
484 
read_sector(DWORD sec,Buffer * buf,int len)485 bool FATDrive::read_sector(DWORD sec, Buffer* buf, int len)
486 {
487 	sec += 63;	//@@ jump to first partition
488 
489 	if (SetFilePointer(_hDrive, sec*_drive._boot_sector.BytesPerSector, 0, 0) == INVALID_SET_FILE_POINTER)
490 		return false;
491 
492 	DWORD read;
493 
494 	if (!ReadFile(_hDrive, buf, len*_drive._boot_sector.BytesPerSector, &read, 0))
495 		return false;
496 
497 	return true;
498 }
499 
read_FAT(DWORD cluster,bool & ok)500 DWORD FATDrive::read_FAT(DWORD cluster, bool& ok)	//@@ use exception handling
501 {
502 	DWORD nClus;
503 	Buffer* FATBuf;
504 
505 	DWORD nclus = (_boot_sector.Sectors32? _boot_sector.Sectors32: _boot_sector.Sectors16) / _boot_sector.SectorsPerCluster;	///@todo cache result
506 
507 	if (cluster > nclus) {
508 		ok = false;
509 		return (DWORD)-1;
510 	}
511 
512 	if (nclus >= 65536) {		// FAT32
513 		DWORD FATsec = cluster / (_boot_sector.BytesPerSector/4);
514 		DWORD z = (cluster - _boot_sector.BytesPerSector/4 * FATsec)*4;
515 		FATsec += _boot_sector.ReservedSectors;
516 		if (!read_cache(FATsec, &FATBuf))
517 			ok = false;
518 		nClus = dpeek(&FATBuf->dat[z]);
519 	} else if (nclus >= 4096) {	// 16 Bit-FAT
520 		DWORD FATsec = cluster / (_boot_sector.BytesPerSector/2);
521 		DWORD z = (cluster - _boot_sector.BytesPerSector/2 * FATsec)*2;
522 		FATsec += _boot_sector.ReservedSectors;
523 		if (!read_cache(FATsec, &FATBuf))
524 			ok = false;
525 		nClus = wpeek(&FATBuf->dat[z]);
526 
527 		if (nClus >= 0xfff0)
528 			nClus |= 0x0fff0000;
529 	} else {						// 12 Bit-FAT
530 		DWORD FATsec = cluster*3 / (_boot_sector.BytesPerSector*2);
531 		DWORD z = (cluster*3 - _boot_sector.BytesPerSector*2*FATsec)/2;
532 		FATsec += _boot_sector.ReservedSectors;
533 		if (!read_cache(FATsec,&FATBuf))
534 			ok = false;
535 		BYTE a = FATBuf->dat[z++];
536 
537 		if (z >= _boot_sector.BytesPerSector)
538 			if (!read_cache(FATsec+1,&FATBuf))
539 				ok = false;
540 		z = 0;
541 
542 		BYTE b = FATBuf->dat[z];
543 
544 		if (cluster & 1)
545 			nClus = (a>>4) | (b<<4);
546 		else
547 			nClus = a | ((b & 0xf)<<8);
548 
549 		if (nClus >= 0xff0)
550 			nClus |= 0x0ffff000;
551 	}
552 
553 	return nClus;
554 }
555 
read_cache(DWORD sec,Buffer ** bufptr)556 bool FATDrive::read_cache(DWORD sec, Buffer** bufptr)
557 {
558  int i, C, anz;
559 
560  if (_boot_sector.BytesPerSector != BufLen)  // no standard sector size?
561   return read_sector(sec, *bufptr=(Buffer*)&_FATCache[0], 1);
562 
563  _CacheCount++;
564 
565  for(i=0; _CacheSec[i]!=sec && i<_Caches; )
566   ++i;
567 
568  if (i < _Caches)
569   {
570    *bufptr = (Buffer*) &_FATCache[i];	 // FAT-Sektor schon gepuffert
571    _CacheCnt[i]++;
572    return true;
573   }
574 
575  i = get_cache_buffer();
576 
577  if (_cache_empty)		// von get_cache_buffer() gesetzt
578   {
579    C = _CacheCount-1;
580    anz = _boot_sector.SectorsPerFAT*_boot_sector.NumberFATs - sec;
581 
582    if (anz > _read_ahead)
583 	anz = _read_ahead;
584 
585    for(i=0; i<anz; i++) {
586 	_CacheSec[i] = sec++;
587 	_CacheCnt[i] = C;
588 	_CacheDty[i] = 0;
589    }
590 
591    _CacheCnt[0] = _CacheCount;
592 
593    return read_sector(_CacheSec[0], *bufptr=(Buffer*) &_FATCache[0], anz);
594   }
595  else
596   {
597    _CacheDty[i] = 0;
598    _CacheCnt[i] = _CacheCount;
599 
600    return read_sector(_CacheSec[i]=sec, *bufptr=(Buffer*) &_FATCache[i], 1);
601   }
602 }
603 
get_cache_buffer()604 int FATDrive::get_cache_buffer()	// search for free cache buffer
605 {
606  int i, j, minCnt;
607 
608  for(i=0; i<_Caches; i++)
609   if (_CacheSec[i])
610    break;
611 
612  _cache_empty = i==_Caches? true: false;
613 
614  for(i=0; _CacheSec[i] && i<_Caches; )
615   ++i;
616 
617  if (i < _Caches)
618   j = i;
619  else
620   {
621    minCnt = 0;			// search for least used buffer
622 
623    for(j=i=0; i<_Caches; i++)
624 	if (minCnt < _CacheCnt[i]) {
625 	 minCnt = _CacheCnt[i];
626 	 j = i;
627 	}
628 
629 /**@todo enable write back
630    if (CacheDty[j]) 	// Dirty-Flag gesetzt?
631 	if (writesec(_CacheSec[j], (Buffer*) &_FATCache[j], 1))
632 	 FPara = _CacheSec[j], Frag(SecWriteErr);
633 */
634   }
635 
636  return j;
637 }
638 
639 #endif // _DEBUG
640