* fix for theme font handling (when switching back to the default theme, the language...
[open-ps2-loader.git] / modules / usb / usbhdfsd / fat_driver.c
blobf1541e48679108e7dcabe1d24bba618802a72c70
1 //---------------------------------------------------------------------------
2 //File name: fat_driver.c
3 //---------------------------------------------------------------------------
4 #include <stdio.h>
5 #include <errno.h>
7 #ifdef WIN32
8 #include <malloc.h>
9 #include <memory.h>
10 #include <string.h>
11 #else
12 #include <sysclib.h>
13 //#include <sys/stat.h>
15 #include <thbase.h>
16 #include <sysmem.h>
17 #define malloc(a) AllocSysMemory(0,(a), NULL)
18 #define free(a) FreeSysMemory((a))
19 #endif
21 #include "usbhd_common.h"
22 #include "scache.h"
23 #include "fat_driver.h"
24 #include "fat.h"
25 //#include "fat_write.h"
26 #include "mass_stor.h"
28 //#define DEBUG //comment out this line when not debugging
30 #include "mass_debug.h"
32 //#define DISK_INIT(d,b) scache_init((d), (b))
33 //#define DISK_CLOSE scache_close
34 //#define DISK_KILL scache_kill //dlanor: added for disconnection events (no flush)
35 #define READ_SECTOR(d, a, b) scache_readSector((d)->cache, (a), (void **)&b)
36 //#define FLUSH_SECTORS scache_flushSectors
38 #define NUM_DRIVES 10
39 static fat_driver* g_fatd[NUM_DRIVES];
41 //---------------------------------------------------------------------------
42 int InitFAT()
44 int i;
45 int ret = 0;
46 for (i = 0; i < NUM_DRIVES; ++i)
47 g_fatd[i] = NULL;
48 return ret;
51 //---------------------------------------------------------------------------
52 int strEqual(const unsigned char *s1, const unsigned char* s2) {
53 unsigned char u1, u2;
54 for (;;) {
55 u1 = *s1++;
56 u2 = *s2++;
57 if (u1 >64 && u1 < 91) u1+=32;
58 if (u2 >64 && u2 < 91) u2+=32;
60 if (u1 != u2) {
61 return -1;
63 if (u1 == '\0') {
64 return 0;
71 0x321, 0xABC
73 byte| byte| byte|
74 +--+--+--+--+--+--+
75 |2 |1 |C |3 |A |B |
76 +--+--+--+--+--+--+
80 //---------------------------------------------------------------------------
81 unsigned int fat_getClusterRecord12(unsigned char* buf, int type) {
82 if (type) { //1
83 return ((buf[1]<< 4) + (buf[0] >>4));
84 } else { // 0
85 return (((buf[1] & 0x0F) << 8) + buf[0]);
89 //---------------------------------------------------------------------------
90 // Get Cluster chain into <buf> buffer
91 // returns:
92 // 0 :if buf is full (bufSize entries) and more chain entries exist
93 // 1-n :number of filled entries of the buf
94 // -1 :error
95 //---------------------------------------------------------------------------
96 //for fat12
97 /* fat12 cluster records can overlap the edge of the sector so we need to detect and maintain
98 these cases
100 int fat_getClusterChain12(fat_driver* fatd, unsigned int cluster, unsigned int* buf, int bufSize, int start) {
101 int ret;
102 int i;
103 int recordOffset;
104 int sectorSpan;
105 int fatSector;
106 int cont;
107 int lastFatSector;
108 unsigned char xbuf[4];
109 unsigned char* sbuf = NULL; //sector buffer
111 cont = 1;
112 lastFatSector = -1;
113 i = 0;
114 if (start) {
115 buf[i] = cluster; //strore first cluster
116 i++;
118 while(i < bufSize && cont) {
119 recordOffset = (cluster * 3) / 2; //offset of the cluster record (in bytes) from the FAT start
120 fatSector = recordOffset / fatd->partBpb.sectorSize;
121 sectorSpan = 0;
122 if ((recordOffset % fatd->partBpb.sectorSize) == (fatd->partBpb.sectorSize - 1)) {
123 sectorSpan = 1;
125 if (lastFatSector != fatSector || sectorSpan) {
126 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector, sbuf);
127 if (ret < 0) {
128 printf("USBHDFSD: Read fat12 sector failed! sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector );
129 return -EIO;
131 lastFatSector = fatSector;
133 if (sectorSpan) {
134 xbuf[0] = sbuf[fatd->partBpb.sectorSize - 2];
135 xbuf[1] = sbuf[fatd->partBpb.sectorSize - 1];
136 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1, sbuf);
137 if (ret < 0) {
138 printf("USBHDFSD: Read fat12 sector failed sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1);
139 return -EIO;
141 xbuf[2] = sbuf[0];
142 xbuf[3] = sbuf[1];
145 if (sectorSpan) { // use xbuf as source buffer
146 cluster = fat_getClusterRecord12(xbuf + (recordOffset % fatd->partBpb.sectorSize) - (fatd->partBpb.sectorSize-2), cluster % 2);
147 } else { // use sector buffer as source buffer
148 cluster = fat_getClusterRecord12(sbuf + (recordOffset % fatd->partBpb.sectorSize), cluster % 2);
151 if ((cluster & 0xFFF) >= 0xFF8) {
152 cont = 0; //continue = false
153 } else {
154 buf[i] = cluster & 0xFFF;
155 i++;
158 return i;
162 //---------------------------------------------------------------------------
163 //for fat16
164 int fat_getClusterChain16(fat_driver* fatd, unsigned int cluster, unsigned int* buf, int bufSize, int start) {
165 int ret;
166 int i;
167 int indexCount;
168 int fatSector;
169 int cont;
170 int lastFatSector;
171 unsigned char* sbuf = NULL; //sector buffer
173 cont = 1;
174 indexCount = fatd->partBpb.sectorSize / 2; //FAT16->2, FAT32->4
175 lastFatSector = -1;
176 i = 0;
177 if (start) {
178 buf[i] = cluster; //strore first cluster
179 i++;
181 while(i < bufSize && cont) {
182 fatSector = cluster / indexCount;
183 if (lastFatSector != fatSector) {
184 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector, sbuf);
185 if (ret < 0) {
186 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector );
187 return -EIO;
190 lastFatSector = fatSector;
192 cluster = getI16(sbuf + ((cluster % indexCount) * 2));
193 if ((cluster & 0xFFFF) >= 0xFFF8) {
194 cont = 0; //continue = false
195 } else {
196 buf[i] = cluster & 0xFFFF;
197 i++;
200 return i;
203 //---------------------------------------------------------------------------
204 //for fat32
205 int fat_getClusterChain32(fat_driver* fatd, unsigned int cluster, unsigned int* buf, int bufSize, int start) {
206 int ret;
207 int i;
208 int indexCount;
209 int fatSector;
210 int cont;
211 int lastFatSector;
212 unsigned char* sbuf = NULL; //sector buffer
214 cont = 1;
215 indexCount = fatd->partBpb.sectorSize / 4; //FAT16->2, FAT32->4
216 lastFatSector = -1;
217 i = 0;
218 if (start) {
219 buf[i] = cluster; //store first cluster
220 i++;
222 while(i < bufSize && cont) {
223 fatSector = cluster / indexCount;
224 if (lastFatSector != fatSector) {
225 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector, sbuf);
226 if (ret < 0) {
227 printf("USBHDFSD: Read fat32 sector failed sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector );
228 return -EIO;
231 lastFatSector = fatSector;
233 cluster = getI32(sbuf + ((cluster % indexCount) * 4));
234 if ((cluster & 0xFFFFFFF) >= 0xFFFFFF8) {
235 cont = 0; //continue = false
236 } else {
237 buf[i] = cluster & 0xFFFFFFF;
238 i++;
241 return i;
244 //---------------------------------------------------------------------------
245 int fat_getClusterChain(fat_driver* fatd, unsigned int cluster, unsigned int* buf, int bufSize, int start) {
247 if (cluster == fatd->lastChainCluster) {
248 return fatd->lastChainResult;
251 switch (fatd->partBpb.fatType) {
252 case FAT12: fatd->lastChainResult = fat_getClusterChain12(fatd, cluster, buf, bufSize, start); break;
253 case FAT16: fatd->lastChainResult = fat_getClusterChain16(fatd, cluster, buf, bufSize, start); break;
254 case FAT32: fatd->lastChainResult = fat_getClusterChain32(fatd, cluster, buf, bufSize, start); break;
256 fatd->lastChainCluster = cluster;
257 return fatd->lastChainResult;
260 //---------------------------------------------------------------------------
261 void fat_invalidateLastChainResult(fat_driver* fatd)
263 fatd->lastChainCluster = 0;
266 //---------------------------------------------------------------------------
267 void fat_determineFatType(fat_bpb* partBpb) {
268 int sector;
269 int clusterCount;
271 //get sector of cluster 0
272 sector = fat_cluster2sector(partBpb, 0);
273 //remove partition start sector to get BR+FAT+ROOT_DIR sector count
274 sector -= partBpb->partStart;
275 sector = partBpb->sectorCount - sector;
276 clusterCount = sector / partBpb->clusterSize;
277 //printf("USBHDFSD: Data cluster count = %i \n", clusterCount);
279 if (clusterCount < 4085) {
280 partBpb->fatType = FAT12;
281 } else
282 if (clusterCount < 65525) {
283 partBpb->fatType = FAT16;
284 } else {
285 partBpb->fatType = FAT32;
289 //---------------------------------------------------------------------------
290 int fat_getPartitionBootSector(mass_dev* dev, unsigned int sector, fat_bpb* partBpb) {
291 fat_raw_bpb* bpb_raw; //fat16, fat12
292 fat32_raw_bpb* bpb32_raw; //fat32
293 int ret;
294 unsigned char* sbuf = NULL; //sector buffer
296 ret = READ_SECTOR(dev, sector, sbuf); //read partition boot sector (first sector on partition)
297 if (ret < 0) {
298 printf("USBHDFSD: Read partition boot sector failed sector=%i! \n", sector);
299 return -EIO;
302 bpb_raw = (fat_raw_bpb*) sbuf;
303 bpb32_raw = (fat32_raw_bpb*) sbuf;
305 //set fat common properties
306 partBpb->sectorSize = getI16(bpb_raw->sectorSize);
307 partBpb->clusterSize = bpb_raw->clusterSize;
308 partBpb->resSectors = getI16(bpb_raw->resSectors);
309 partBpb->fatCount = bpb_raw->fatCount;
310 partBpb->rootSize = getI16(bpb_raw->rootSize);
311 partBpb->fatSize = getI16(bpb_raw->fatSize);
312 partBpb->trackSize = getI16(bpb_raw->trackSize);
313 partBpb->headCount = getI16(bpb_raw->headCount);
314 partBpb->sectorCount = getI16(bpb_raw->sectorCountO);
315 if (partBpb->sectorCount == 0) {
316 partBpb->sectorCount = getI32(bpb_raw->sectorCount); // large partition
318 partBpb->partStart = sector;
319 partBpb->rootDirStart = partBpb->partStart + (partBpb->fatCount * partBpb->fatSize) + partBpb->resSectors;
320 for (ret = 0; ret < 8; ret++) {
321 partBpb->fatId[ret] = bpb_raw->fatId[ret];
323 partBpb->fatId[ret] = 0;
324 partBpb->rootDirCluster = 0;
325 partBpb->dataStart = partBpb->rootDirStart + (partBpb->rootSize / (partBpb->sectorSize >> 5));
327 fat_determineFatType(partBpb);
329 //fat32 specific info
330 if (partBpb->fatType == FAT32 && partBpb->fatSize == 0) {
331 partBpb->fatSize = getI32(bpb32_raw->fatSize32);
332 partBpb->activeFat = getI16(bpb32_raw->fatStatus);
333 if (partBpb->activeFat & 0x80) { //fat not synced
334 partBpb->activeFat = (partBpb->activeFat & 0xF);
335 } else {
336 partBpb->activeFat = 0;
338 partBpb->rootDirStart = partBpb->partStart + (partBpb->fatCount * partBpb->fatSize) + partBpb->resSectors;
339 partBpb->rootDirCluster = getI32(bpb32_raw->rootDirCluster);
340 for (ret = 0; ret < 8; ret++) {
341 partBpb->fatId[ret] = bpb32_raw->fatId[ret];
343 partBpb->fatId[ret] = 0;
344 partBpb->dataStart = partBpb->rootDirStart;
346 printf("USBHDFSD: Fat type %i Id %s \n", partBpb->fatType, partBpb->fatId);
347 return 1;
350 //---------------------------------------------------------------------------
352 returns:
353 0 - no more dir entries
354 1 - short name dir entry found
355 2 - long name dir entry found
356 3 - deleted dir entry found
358 int fat_getDirentry(unsigned char fatType, fat_direntry* dir_entry, fat_direntry_summary* dir ) {
359 int i, j;
360 int offset;
361 int cont;
363 //detect last entry - all zeros (slight modification by radad)
364 if (dir_entry->sfn.name[0] == 0) {
365 return 0;
367 //detect deleted entry - it will be ignored
368 if (dir_entry->sfn.name[0] == 0xE5) {
369 return 3;
372 //detect long filename
373 if (dir_entry->lfn.rshv == 0x0F && dir_entry->lfn.reserved1 == 0x00 && dir_entry->lfn.reserved2[0] == 0x00) {
374 //long filename - almost whole direntry is unicode string - extract it
375 offset = dir_entry->lfn.entrySeq & 0x3f;
376 offset--;
377 offset = offset * 13;
378 //name - 1st part
379 cont = 1;
380 for (i = 0; i < 10 && cont; i+=2) {
381 if (dir_entry->lfn.name1[i]==0 && dir_entry->lfn.name1[i+1] == 0) {
382 dir->name[offset] = 0; //terminate
383 cont = 0; //stop
384 } else {
385 dir->name[offset] = dir_entry->lfn.name1[i];
386 offset++;
389 //name - 2nd part
390 for (i = 0; i < 12 && cont; i+=2) {
391 if (dir_entry->lfn.name2[i]==0 && dir_entry->lfn.name2[i+1] == 0) {
392 dir->name[offset] = 0; //terminate
393 cont = 0; //stop
394 } else {
395 dir->name[offset] = dir_entry->lfn.name2[i];
396 offset++;
399 //name - 3rd part
400 for (i = 0; i < 4 && cont; i+=2) {
401 if (dir_entry->lfn.name3[i]==0 && dir_entry->lfn.name3[i+1] == 0) {
402 dir->name[offset] = 0; //terminate
403 cont = 0; //stop
404 } else {
405 dir->name[offset] = dir_entry->lfn.name3[i];
406 offset++;
409 if ((dir_entry->lfn.entrySeq & 0x40)) { //terminate string flag
410 dir->name[offset] = 0;
412 return 2;
413 } else {
414 //short filename
415 //copy name
416 for (i = 0; i < 8 && dir_entry->sfn.name[i]!= 32; i++) {
417 dir->sname[i] = dir_entry->sfn.name[i];
418 // NT—adaption for LaunchELF
419 if (dir_entry->sfn.reservedNT & 0x08 &&
420 dir->sname[i] >= 'A' && dir->sname[i] <= 'Z') {
421 dir->sname[i] += 0x20; //Force standard letters in name to lower case
424 for (j=0; j < 3 && dir_entry->sfn.ext[j] != 32; j++) {
425 if (j == 0) {
426 dir->sname[i] = '.';
427 i++;
429 dir->sname[i+j] = dir_entry->sfn.ext[j];
430 // NT—adaption for LaunchELF
431 if (dir_entry->sfn.reservedNT & 0x10 &&
432 dir->sname[i+j] >= 'A' && dir->sname[i+j] <= 'Z') {
433 dir->sname[i+j] += 0x20; //Force standard letters in ext to lower case
436 dir->sname[i+j] = 0; //terminate
437 if (dir->name[0] == 0) { //long name desn't exit
438 for (i =0 ; dir->sname[i] !=0; i++) dir->name[i] = dir->sname[i];
439 dir->name[i] = 0;
441 dir->attr = dir_entry->sfn.attr;
442 dir->size = getI32(dir_entry->sfn.size);
443 if (fatType == FAT32)
444 dir->cluster = getI32_2(dir_entry->sfn.clusterL, dir_entry->sfn.clusterH);
445 else
446 dir->cluster = getI16(dir_entry->sfn.clusterL);
447 return 1;
451 //---------------------------------------------------------------------------
452 //Set chain info (cluster/offset) cache
453 void fat_setFatDirChain(fat_driver* fatd, fat_dir* fatDir) {
454 int i,j;
455 int index;
456 int chainSize;
457 int nextChain;
458 int clusterChainStart ;
459 unsigned int fileCluster;
460 int fileSize;
461 int blockSize;
464 XPRINTF("USBHDFSD: reading cluster chain \n");
465 fileCluster = fatDir->chain[0].cluster;
467 if (fileCluster < 2) {
468 XPRINTF("USBHDFSD: early exit... \n");
469 return;
472 fileSize = fatDir->size;
473 blockSize = fileSize / DIR_CHAIN_SIZE;
475 nextChain = 1;
476 clusterChainStart = 0;
477 j = 1;
478 fileSize = 0;
479 index = 0;
481 while (nextChain) {
482 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, 1);
483 if (chainSize >= MAX_DIR_CLUSTER) { //the chain is full, but more chain parts exist
484 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
485 }else { //chain fits in the chain buffer completely - no next chain exist
486 nextChain = 0;
488 //process the cluster chain (fatd->cbuf)
489 for (i = clusterChainStart; i < chainSize; i++) {
490 fileSize += (fatd->partBpb.clusterSize * fatd->partBpb.sectorSize);
491 while (fileSize >= (j * blockSize) && j < DIR_CHAIN_SIZE) {
492 fatDir->chain[j].cluster = fatd->cbuf[i];
493 fatDir->chain[j].index = index;
494 j++;
495 }//ends "while"
496 index++;
497 }//ends "for"
498 clusterChainStart = 1;
499 }//ends "while"
500 fatDir->lastCluster = fatd->cbuf[i-1];
502 #ifdef DEBUG_EXTREME //dlanor: I patched this because this bloat hid important stuff
503 //debug
504 printf("USBHDFSD: SEEK CLUSTER CHAIN CACHE fileSize=%i blockSize=%i \n", fatDir->size, blockSize);
505 for (i = 0; i < DIR_CHAIN_SIZE; i++) {
506 printf("USBHDFSD: index=%i cluster=%i offset= %i - %i start=%i \n",
507 fatDir->chain[i].index, fatDir->chain[i].cluster,
508 fatDir->chain[i].index * fatd->partBpb.clusterSize * fatd->partBpb.sectorSize,
509 (fatDir->chain[i].index+1) * fatd->partBpb.clusterSize * fatd->partBpb.sectorSize,
510 i * blockSize);
512 #endif /* debug */
513 XPRINTF("USBHDFSD: read cluster chain done!\n");
518 //---------------------------------------------------------------------------
519 /* Set base attributes of direntry */
520 void fat_setFatDir(fat_driver* fatd, fat_dir* fatDir, fat_direntry_sfn* dsfn, fat_direntry_summary* dir, int getClusterInfo ) {
521 int i;
522 unsigned char* srcName;
524 XPRINTF("USBHDFSD: setting fat dir...\n");
525 srcName = dir->sname;
526 if (dir->name[0] != 0) { //long filename not empty
527 srcName = dir->name;
529 //copy name
530 for (i = 0; srcName[i] != 0; i++) fatDir->name[i] = srcName[i];
531 fatDir->name[i] = 0; //terminate
533 fatDir->attr = dir->attr;
534 fatDir->size = dir->size;
536 //created Date: Day, Month, Year-low, Year-high
537 fatDir->cdate[0] = (dsfn->dateCreate[0] & 0x1F);
538 fatDir->cdate[1] = (dsfn->dateCreate[0] >> 5) + ((dsfn->dateCreate[1] & 0x01) << 3 );
539 i = 1980 + (dsfn->dateCreate[1] >> 1);
540 fatDir->cdate[2] = (i & 0xFF);
541 fatDir->cdate[3] = ((i & 0xFF00)>> 8);
543 //created Time: Hours, Minutes, Seconds
544 fatDir->ctime[0] = ((dsfn->timeCreate[1] & 0xF8) >> 3);
545 fatDir->ctime[1] = ((dsfn->timeCreate[1] & 0x07) << 3) + ((dsfn->timeCreate[0] & 0xE0) >> 5);
546 fatDir->ctime[6] = ((dsfn->timeCreate[0] & 0x1F) << 1);
548 //accessed Date: Day, Month, Year-low, Year-high
549 fatDir->adate[0] = (dsfn->dateAccess[0] & 0x1F);
550 fatDir->adate[1] = (dsfn->dateAccess[0] >> 5) + ((dsfn->dateAccess[1] & 0x01) << 3 );
551 i = 1980 + (dsfn->dateAccess[1] >> 1);
552 fatDir->adate[2] = (i & 0xFF);
553 fatDir->adate[3] = ((i & 0xFF00)>> 8);
555 //modified Date: Day, Month, Year-low, Year-high
556 fatDir->mdate[0] = (dsfn->dateWrite[0] & 0x1F);
557 fatDir->mdate[1] = (dsfn->dateWrite[0] >> 5) + ((dsfn->dateWrite[1] & 0x01) << 3 );
558 i = 1980 + (dsfn->dateWrite[1] >> 1);
559 fatDir->mdate[2] = (i & 0xFF);
560 fatDir->mdate[3] = ((i & 0xFF00)>> 8);
562 //modified Time: Hours, Minutes, Seconds
563 fatDir->mtime[0] = ((dsfn->timeWrite[1] & 0xF8) >> 3);
564 fatDir->mtime[1] = ((dsfn->timeWrite[1] & 0x07) << 3) + ((dsfn->timeWrite[0] & 0xE0) >> 5);
565 fatDir->mtime[2] = ((dsfn->timeWrite[0] & 0x1F) << 1);
567 fatDir->chain[0].cluster = dir->cluster;
568 fatDir->chain[0].index = 0;
569 if (getClusterInfo) {
570 fat_setFatDirChain(fatd, fatDir);
574 //---------------------------------------------------------------------------
575 int fat_getDirentrySectorData(fat_driver* fatd, unsigned int* startCluster, unsigned int* startSector, int* dirSector) {
576 int chainSize;
578 if (*startCluster == 0 && fatd->partBpb.fatType < FAT32) { //Root directory
579 *startSector = fatd->partBpb.rootDirStart;
580 *dirSector = fatd->partBpb.rootSize / (fatd->partBpb.sectorSize / 32);
581 return 0;
583 //other directory or fat 32
584 if (*startCluster == 0 && fatd->partBpb.fatType == FAT32) {
585 *startCluster = fatd->partBpb.rootDirCluster;
587 *startSector = fat_cluster2sector(&fatd->partBpb, *startCluster);
588 chainSize = fat_getClusterChain(fatd, *startCluster, fatd->cbuf, MAX_DIR_CLUSTER, 1);
589 if (chainSize >= MAX_DIR_CLUSTER) {
590 printf("USBHDFSD: Chain too large\n");
591 return -EFAULT;
592 } else if (chainSize > 0) {
593 *dirSector = chainSize * fatd->partBpb.clusterSize;
594 } else {
595 printf("USBHDFSD: Error getting cluster chain! startCluster=%i \n", *startCluster);
596 return -EFAULT;
599 return chainSize;
602 //---------------------------------------------------------------------------
603 int fat_getDirentryStartCluster(fat_driver* fatd, unsigned char* dirName, unsigned int* startCluster, fat_dir* fatDir) {
604 fat_direntry_summary dir;
605 int i;
606 int dirSector;
607 unsigned int startSector;
608 int cont;
609 int ret;
610 unsigned int dirPos;
611 mass_dev* mass_device = fatd->dev;
613 cont = 1;
614 XPRINTF("USBHDFSD: getting cluster for dir entry: %s \n", dirName);
615 //clear name strings
616 dir.sname[0] = 0;
617 dir.name[0] = 0;
619 ret = fat_getDirentrySectorData(fatd, startCluster, &startSector, &dirSector);
620 if (ret < 0)
621 return ret;
623 XPRINTF("USBHDFSD: dirCluster=%i startSector=%i (%i) dirSector=%i \n", *startCluster, startSector, startSector * mass_device->sectorSize, dirSector);
625 //go through first directory sector till the max number of directory sectors
626 //or stop when no more direntries detected
627 for (i = 0; i < dirSector && cont; i++) {
628 unsigned char* sbuf = NULL; //sector buffer
630 //At cluster borders, get correct sector from cluster chain buffer
631 if ((*startCluster != 0) && (i % fatd->partBpb.clusterSize == 0)) {
632 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)]) -i;
635 ret = READ_SECTOR(fatd->dev, startSector + i, sbuf);
636 if (ret < 0) {
637 printf("USBHDFSD: read directory sector failed ! sector=%i\n", startSector + i);
638 return -EIO;
640 XPRINTF("USBHDFSD: read sector ok, scanning sector for direntries...\n");
641 dirPos = 0;
643 // go through start of the sector till the end of sector
644 while (cont && dirPos < fatd->partBpb.sectorSize) {
645 fat_direntry* dir_entry = (fat_direntry*) (sbuf + dirPos);
646 cont = fat_getDirentry(fatd->partBpb.fatType, dir_entry, &dir); //get single directory entry from sector buffer
647 if (cont == 1) { //when short file name entry detected
648 if (!(dir.attr & FAT_ATTR_VOLUME_LABEL)) { //not volume label
649 if ((strEqual(dir.sname, dirName) == 0) ||
650 (strEqual(dir.name, dirName) == 0) ) {
651 XPRINTF("USBHDFSD: found! %s\n", dir.name);
652 if (fatDir != NULL) { //fill the directory properties
653 fat_setFatDir(fatd, fatDir, &dir_entry->sfn, &dir, 1);
655 *startCluster = dir.cluster;
656 XPRINTF("USBHDFSD: direntry %s found at cluster: %i \n", dirName, dir.cluster);
657 return dir.attr; //returns file or directory attr
659 }//ends "if(!(dir.attr & FAT_ATTR_VOLUME_LABEL))"
660 //clear name strings
661 dir.sname[0] = 0;
662 dir.name[0] = 0;
663 }//ends "if (cont == 1)"
664 dirPos += sizeof(fat_direntry);
665 }//ends "while"
666 }//ends "for"
667 XPRINTF("USBHDFSD: direntry %s not found! \n", dirName);
668 return -ENOENT;
671 //---------------------------------------------------------------------------
672 // start cluster should be 0 - if we want to search from root directory
673 // otherwise the start cluster should be correct cluster of directory
674 // to search directory - set fatDir as NULL
675 int fat_getFileStartCluster(fat_driver* fatd, const unsigned char* fname, unsigned int* startCluster, fat_dir* fatDir) {
676 unsigned char tmpName[257];
677 int i;
678 int offset;
679 int cont;
680 int ret;
682 XPRINTF("USBHDFSD: Entering fat_getFileStartCluster\n");
684 cont = 1;
685 offset = 0;
686 i=0;
688 *startCluster = 0;
689 if (fatDir != NULL) {
690 memset(fatDir, 0, sizeof(fat_dir));
691 fatDir->attr = FAT_ATTR_DIRECTORY;
693 if (fname[i] == '/') {
694 i++;
697 for ( ; fname[i] !=0; i++) {
698 if (fname[i] == '/') { //directory separator
699 tmpName[offset] = 0; //terminate string
700 ret = fat_getDirentryStartCluster(fatd, tmpName, startCluster, fatDir);
701 if (ret < 0) {
702 return -ENOENT;
704 offset = 0;
705 } else{
706 tmpName[offset] = fname[i];
707 offset++;
709 }//ends "for"
710 //and the final file
711 tmpName[offset] = 0; //terminate string
712 XPRINTF("USBHDFSD: Ready to get cluster for file \"%s\"\n", tmpName);
713 if (fatDir != NULL) {
714 //if the last char of the name was slash - the name was already found -exit
715 if (offset == 0) {
716 XPRINTF("USBHDFSD: Exiting from fat_getFileStartCluster with a folder\n");
717 return 2;
719 ret = fat_getDirentryStartCluster(fatd, tmpName, startCluster, fatDir);
720 if (ret < 0) {
721 XPRINTF("USBHDFSD: Exiting from fat_getFileStartCluster with error %i\n", ret);
722 return ret;
724 XPRINTF("USBHDFSD: file's startCluster found. Name=%s, cluster=%i \n", fname, *startCluster);
726 XPRINTF("USBHDFSD: Exiting from fat_getFileStartCluster with a file\n");
727 return 1;
730 //---------------------------------------------------------------------------
731 void fat_getClusterAtFilePos(fat_driver* fatd, fat_dir* fatDir, unsigned int filePos, unsigned int* cluster, unsigned int* clusterPos) {
732 int i;
733 int blockSize;
734 int j = (DIR_CHAIN_SIZE-1);
736 blockSize = fatd->partBpb.clusterSize * fatd->partBpb.sectorSize;
738 for (i = 0; i < (DIR_CHAIN_SIZE-1); i++) {
739 if (fatDir->chain[i].index * blockSize <= filePos &&
740 fatDir->chain[i+1].index * blockSize > filePos) {
741 j = i;
742 break;
745 *cluster = fatDir->chain[j].cluster;
746 *clusterPos = (fatDir->chain[j].index * blockSize);
749 //---------------------------------------------------------------------------
750 int fat_readFile(fat_driver* fatd, fat_dir* fatDir, unsigned int filePos, unsigned char* buffer, unsigned int size) {
751 int ret;
752 int i,j;
753 int chainSize;
754 int nextChain;
755 int startSector;
756 unsigned int bufSize;
757 int sectorSkip;
758 int clusterSkip;
759 int dataSkip;
760 mass_dev* mass_device = fatd->dev;
762 unsigned int bufferPos;
763 unsigned int fileCluster;
764 unsigned int clusterPos;
766 int clusterChainStart;
768 fat_getClusterAtFilePos(fatd, fatDir, filePos, &fileCluster, &clusterPos);
769 sectorSkip = (filePos - clusterPos) / fatd->partBpb.sectorSize;
770 clusterSkip = sectorSkip / fatd->partBpb.clusterSize;
771 sectorSkip %= fatd->partBpb.clusterSize;
772 dataSkip = filePos % fatd->partBpb.sectorSize;
773 bufferPos = 0;
775 XPRINTF("USBHDFSD: fileCluster = %i, clusterPos= %i clusterSkip=%i, sectorSkip=%i dataSkip=%i \n",
776 fileCluster, clusterPos, clusterSkip, sectorSkip, dataSkip);
778 if (fileCluster < 2) {
779 return 0;
782 bufSize = mass_device->sectorSize;
783 nextChain = 1;
784 clusterChainStart = 1;
786 while (nextChain && size > 0 ) {
787 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
788 clusterChainStart = 0;
789 if (chainSize >= MAX_DIR_CLUSTER) { //the chain is full, but more chain parts exist
790 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
791 }else { //chain fits in the chain buffer completely - no next chain needed
792 nextChain = 0;
794 while (clusterSkip >= MAX_DIR_CLUSTER) {
795 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
796 clusterChainStart = 0;
797 if (chainSize >= MAX_DIR_CLUSTER) { //the chain is full, but more chain parts exist
798 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
799 }else { //chain fits in the chain buffer completely - no next chain needed
800 nextChain = 0;
802 clusterSkip -= MAX_DIR_CLUSTER;
805 //process the cluster chain (fatd->cbuf) and skip leading clusters if needed
806 for (i = 0 + clusterSkip; i < chainSize && size > 0; i++) {
807 //read cluster and save cluster content
808 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[i]);
809 //process all sectors of the cluster (and skip leading sectors if needed)
810 for (j = 0 + sectorSkip; j < fatd->partBpb.clusterSize && size > 0; j++) {
811 unsigned char* sbuf = NULL; //sector buffer
813 ret = READ_SECTOR(fatd->dev, startSector + j, sbuf);
814 if (ret < 0) {
815 printf("USBHDFSD: Read sector failed ! sector=%i\n", startSector + j);
816 return bufferPos;
819 //compute exact size of transfered bytes
820 if (size < bufSize) {
821 bufSize = size + dataSkip;
823 if (bufSize > mass_device->sectorSize) {
824 bufSize = mass_device->sectorSize;
826 XPRINTF("USBHDFSD: memcopy dst=%i, src=%i, size=%i bufSize=%i \n", bufferPos, dataSkip, bufSize-dataSkip, bufSize);
827 memcpy(buffer+bufferPos, sbuf + dataSkip, bufSize - dataSkip);
828 size-= (bufSize - dataSkip);
829 bufferPos += (bufSize - dataSkip);
830 dataSkip = 0;
831 bufSize = mass_device->sectorSize;
833 sectorSkip = 0;
835 clusterSkip = 0;
837 return bufferPos;
840 //---------------------------------------------------------------------------
841 int fat_getNextDirentry(fat_driver* fatd, fat_dir_list* fatdlist, fat_dir* fatDir) {
842 fat_direntry_summary dir;
843 int i;
844 int dirSector;
845 unsigned int startSector;
846 int cont, new_entry;
847 int ret;
848 unsigned int dirPos;
849 unsigned int dirCluster;
850 mass_dev* mass_device = fatd->dev;
852 //the getFirst function was not called
853 if (fatdlist->direntryCluster == 0xFFFFFFFF || fatDir == NULL) {
854 return -EFAULT;
857 dirCluster = fatdlist->direntryCluster;
859 //clear name strings
860 dir.sname[0] = 0;
861 dir.name[0] = 0;
863 ret = fat_getDirentrySectorData(fatd, &dirCluster, &startSector, &dirSector);
864 if (ret < 0)
865 return ret;
867 XPRINTF("USBHDFSD: dirCluster=%i startSector=%i (%i) dirSector=%i \n", dirCluster, startSector, startSector * mass_device->sectorSize, dirSector);
869 //go through first directory sector till the max number of directory sectors
870 //or stop when no more direntries detected
871 //dlanor: but avoid rescanning same areas redundantly (if possible)
872 cont = 1;
873 new_entry = 1;
874 dirPos = (fatdlist->direntryIndex*32) % fatd->partBpb.sectorSize;
875 for (i = ((fatdlist->direntryIndex*32) / fatd->partBpb.sectorSize); (i < dirSector) && cont; i++) {
876 unsigned char* sbuf = NULL; //sector buffer
878 //At cluster borders, get correct sector from cluster chain buffer
879 if ((dirCluster != 0) && (new_entry || (i % fatd->partBpb.clusterSize == 0))) {
880 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)])
881 -i + (i % fatd->partBpb.clusterSize);
882 new_entry = 0;
884 ret = READ_SECTOR(fatd->dev, startSector + i, sbuf);
885 if (ret < 0) {
886 printf("USBHDFSD: Read directory sector failed ! sector=%i\n", startSector + i);
887 return -EIO;
890 // go through sector from current pos till its end
891 while (cont && (dirPos < fatd->partBpb.sectorSize)) {
892 fat_direntry* dir_entry = (fat_direntry*) (sbuf + dirPos);
893 cont = fat_getDirentry(fatd->partBpb.fatType, dir_entry, &dir); //get a directory entry from sector
894 fatdlist->direntryIndex++; //Note current entry processed
895 if (cont == 1) { //when short file name entry detected
896 fat_setFatDir(fatd, fatDir, &dir_entry->sfn, &dir, 0);
897 #if 0
898 printf("USBHDFSD: fat_getNextDirentry %c%c%c%c%c%c %x %s %s\n",
899 (dir.attr & FAT_ATTR_VOLUME_LABEL) ? 'v' : '-',
900 (dir.attr & FAT_ATTR_DIRECTORY) ? 'd' : '-',
901 (dir.attr & FAT_ATTR_READONLY) ? 'r' : '-',
902 (dir.attr & FAT_ATTR_ARCHIVE) ? 'a' : '-',
903 (dir.attr & FAT_ATTR_SYSTEM) ? 's' : '-',
904 (dir.attr & FAT_ATTR_HIDDEN) ? 'h' : '-',
905 dir.attr,
906 dir.sname,
907 dir.name);
908 #endif
909 return 1;
911 dirPos += sizeof(fat_direntry);
912 }//ends "while"
913 dirPos = 0;
914 }//ends "for"
915 // when we get this far - reset the direntry cluster
916 fatdlist->direntryCluster = 0xFFFFFFFF; //no more files
917 return 0; //indicate that no direntry is avalable
920 //---------------------------------------------------------------------------
921 int fat_getFirstDirentry(fat_driver* fatd, const unsigned char* dirName, fat_dir_list* fatdlist, fat_dir* fatDir) {
922 int ret;
923 unsigned int startCluster = 0;
925 ret = fat_getFileStartCluster(fatd, dirName, &startCluster, fatDir);
926 if (ret < 0) { //dir name not found
927 return -ENOENT;
929 //check that direntry is directory
930 if (!(fatDir->attr & FAT_ATTR_DIRECTORY)) {
931 return -ENOTDIR; //it's a file - exit
933 fatdlist->direntryCluster = startCluster;
934 fatdlist->direntryIndex = 0;
935 return fat_getNextDirentry(fatd, fatdlist, fatDir);
938 //---------------------------------------------------------------------------
939 int fat_mount(mass_dev* dev, unsigned int start, unsigned int count)
941 fat_driver* fatd = NULL;
942 int i;
943 for (i = 0; i < NUM_DRIVES && fatd == NULL; ++i)
945 if (g_fatd[i] == NULL)
947 XPRINTF("USBHDFSD: usb fat: allocate fat_driver %d!\n", sizeof(fat_driver));
948 g_fatd[i] = malloc(sizeof(fat_driver));
949 if (g_fatd[i] != NULL)
951 g_fatd[i]->dev = NULL;
953 fatd = g_fatd[i];
955 else if(g_fatd[i]->dev == NULL)
957 fatd = g_fatd[i];
961 if (fatd == NULL)
963 printf("USBHDFSD: usb fat: unable to allocate drive!\n");
964 return -1;
967 if (fatd->dev != NULL)
969 printf("USBHDFSD: usb fat: mount ERROR: alread mounted\n");
970 fat_forceUnmount(fatd->dev);
973 if (fat_getPartitionBootSector(dev, start, &fatd->partBpb) < 0)
974 return -1;
976 fatd->dev = dev;
977 fatd->deIdx = 0;
978 fatd->clStackIndex = 0;
979 fatd->clStackLast = 0;
980 fatd->lastChainCluster = 0xFFFFFFFF;
981 fatd->lastChainResult = -1;
982 return 0;
985 //---------------------------------------------------------------------------
986 void fat_forceUnmount(mass_dev* dev)
988 int i;
989 XPRINTF("USBHDFSD: usb fat: forceUnmount devId %i \n", dev->devId);
991 for (i = 0; i < NUM_DRIVES; ++i)
993 if (g_fatd[i] != NULL && g_fatd[i]->dev == dev)
994 g_fatd[i] = NULL;
998 //---------------------------------------------------------------------------
999 fat_driver * fat_getData(int device)
1001 if (device >= NUM_DRIVES)
1002 return NULL;
1004 while (g_fatd[device] == NULL || g_fatd[device]->dev == NULL)
1006 if (mass_stor_configureNextDevice() <= 0)
1007 break;
1010 if (g_fatd[device] == NULL || g_fatd[device]->dev == NULL)
1011 return NULL;
1012 else
1013 return g_fatd[device];
1016 //---------------------------------------------------------------------------
1017 //End of file: fat_driver.c
1018 //---------------------------------------------------------------------------