* fix for theme font handling (when switching back to the default theme, the language...
[open-ps2-loader.git] / modules / usb / usbhdfsd / fat_write.c
blobdb668d7b0bc5cb3f449590e7f2beac824cc332f1
1 //---------------------------------------------------------------------------
2 //File name: fat_write.c
3 //---------------------------------------------------------------------------
4 /*
5 * fat_driver.c - USB Mass storage driver for PS2
7 * (C) 2005, Marek Olejnik (ole00@post.cz)
9 * FAT filesystem layer - write functions
11 * See the file LICENSE included with this distribution for licensing terms.
13 //---------------------------------------------------------------------------
14 #include <stdio.h>
15 #include <errno.h>
17 #ifdef WIN32
18 #include <malloc.h>
19 #include <memory.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #else
23 #include <cdvdman.h>
24 #include <sysclib.h>
25 #endif
27 #include "usbhd_common.h"
28 #include "fat_driver.h"
29 #include "fat.h"
30 #include "scache.h"
31 #include "mass_stor.h"
33 //#define DEBUG //comment out this line when not debugging
35 #include "mass_debug.h"
37 #define DATE_CREATE 1
38 #define DATE_MODIFY 2
40 #define READ_SECTOR(d, a, b) scache_readSector((d)->cache, (a), (void **)&b)
41 #define ALLOC_SECTOR(d, a, b) scache_allocSector((d)->cache, (a), (void **)&b)
42 #define WRITE_SECTOR(d, a) scache_writeSector((d)->cache, (a))
43 #define FLUSH_SECTORS(d) scache_flushSectors((d)->cache)
45 //---------------------------------------------------------------------------
47 reorder (swap) the cluster stack records
49 void swapClStack(fat_driver* fatd, int startIndex, int endIndex) {
50 int i;
51 int size;
52 int offset1, offset2;
53 unsigned int tmp;
55 size = endIndex-startIndex;
56 if (size < 2) {
57 return;
60 size/=2;
61 for (i = 0; i < size; i++) {
62 offset1 = startIndex + i;
63 offset2 = endIndex - 1 - i;
64 tmp = fatd->clStack[offset1];
65 fatd->clStack[offset1] = fatd->clStack[offset2];
66 fatd->clStack[offset2] = tmp;
70 //---------------------------------------------------------------------------
72 scan FAT12 for free clusters and store them to the cluster stack
75 int fat_readEmptyClusters12(fat_driver* fatd) {
76 int ret;
77 int i;
78 int recordOffset;
79 int sectorSpan;
80 int fatSector;
81 int cont;
82 int lastFatSector;
83 unsigned int cluster;
84 unsigned int clusterValue;
85 unsigned char xbuf[4];
86 int oldClStackIndex;
87 unsigned char* sbuf = NULL; //sector buffer
89 oldClStackIndex = fatd->clStackIndex;
91 cont = 1;
92 lastFatSector = -1;
93 i = 0;
94 cluster = fatd->clStackLast;
96 while(fatd->clStackIndex < MAX_CLUSTER_STACK ) {
97 recordOffset = (cluster * 3) / 2; //offset of the cluster record (in bytes) from the FAT start
98 fatSector = recordOffset / fatd->partBpb.sectorSize;
99 sectorSpan = 0;
100 if ((recordOffset % fatd->partBpb.sectorSize) == (fatd->partBpb.sectorSize - 1)) {
101 sectorSpan = 1;
103 if (lastFatSector != fatSector || sectorSpan) {
104 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector, sbuf);
105 if (ret < 0) {
106 printf("USBHDFSD: Read fat12 sector failed! sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector );
107 return -EIO;
109 lastFatSector = fatSector;
111 if (sectorSpan) {
112 xbuf[0] = sbuf[fatd->partBpb.sectorSize - 2];
113 xbuf[1] = sbuf[fatd->partBpb.sectorSize - 1];
114 ret = READ_SECTOR(fatd->dev, fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1, sbuf);
115 if (ret < 0) {
116 printf("USBHDFSD: Read fat12 sector failed sector=%i! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1);
117 return -EIO;
119 xbuf[2] = sbuf[0];
120 xbuf[3] = sbuf[1];
123 if (sectorSpan) { // use xbuf as source buffer
124 clusterValue = fat_getClusterRecord12(xbuf + (recordOffset % fatd->partBpb.sectorSize) - (fatd->partBpb.sectorSize-2), cluster % 2);
125 } else { // use sector buffer as source buffer
126 clusterValue = fat_getClusterRecord12(sbuf + (recordOffset % fatd->partBpb.sectorSize), cluster % 2);
128 if (clusterValue == 0) {
129 fatd->clStackLast = cluster;
130 fatd->clStack[fatd->clStackIndex] = cluster;
131 fatd->clStackIndex++;
134 cluster++; //read next cluster record in the sequence
136 //the stack operates as LIFO but we put in the clusters as FIFO
137 //we should reverse the cluster order - not necessary
138 //but it will retain the natural (increasing) order of
139 //the cluster chain
140 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
141 return fatd->clStackIndex;
146 //---------------------------------------------------------------------------
148 scan FAT32 for free clusters and store them to the cluster stack
150 int fat_readEmptyClusters32(fat_driver* fatd) {
151 unsigned int i,j;
152 int ret;
153 unsigned int indexCount;
154 unsigned int fatStartSector;
155 unsigned int cluster;
156 unsigned int clusterValue;
157 int oldClStackIndex;
158 int sectorSkip;
159 int recordSkip;
161 oldClStackIndex = fatd->clStackIndex;
163 //indexCount = numer of cluster indices per sector
164 indexCount = fatd->partBpb.sectorSize / 4; //FAT16->2, FAT32->4
165 //skip areas we have already searched through
166 sectorSkip = fatd->clStackLast / indexCount;
167 recordSkip = fatd->clStackLast % indexCount;
169 fatStartSector = fatd->partBpb.partStart + fatd->partBpb.resSectors;
171 for (i = sectorSkip; i < fatd->partBpb.fatSize && fatd->clStackIndex < MAX_CLUSTER_STACK ; i++) {
172 unsigned char* sbuf = NULL; //sector buffer
174 ret = READ_SECTOR(fatd->dev, fatStartSector + i, sbuf);
175 if (ret < 0) {
176 printf("USBHDFSD: Read fat32 sector failed! sector=%i! \n", fatStartSector + i);
177 return -EIO;
179 for (j = recordSkip; j < indexCount && fatd->clStackIndex < MAX_CLUSTER_STACK ; j++) {
180 cluster = getI32(sbuf + (j * 4));
181 if (cluster == 0) { //the cluster is free
182 clusterValue = (i * indexCount) + j;
183 if (clusterValue < 0xFFFFFF7) {
184 fatd->clStackLast = clusterValue;
185 fatd->clStack[fatd->clStackIndex] = clusterValue;
186 fatd->clStackIndex++;
190 recordSkip = 0;
192 //the stack operates as LIFO but we put in the clusters as FIFO
193 //we should reverse the cluster order - not necessary
194 //but it will retain the natural (increasing) order of
195 //the cluster chain
196 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
197 return fatd->clStackIndex;
200 //---------------------------------------------------------------------------
202 scan FAT16 for free clusters and store them to the cluster stack
204 int fat_readEmptyClusters16(fat_driver* fatd) {
205 unsigned int i,j;
206 int ret;
207 unsigned int indexCount;
208 unsigned int fatStartSector;
209 unsigned int cluster;
210 int oldClStackIndex;
211 int sectorSkip;
212 int recordSkip;
214 oldClStackIndex = fatd->clStackIndex;
215 //XPRINTF("USBHDFSD: #### Read empty clusters16: clStackIndex=%d MAX=%d\n", clStackIndex, MAX_CLUSTER_STACK);
217 //indexCount = numer of cluster indices per sector
218 indexCount = fatd->partBpb.sectorSize / 2; //FAT16->2, FAT32->4
220 //skip areas we have already searched through
221 sectorSkip = fatd->clStackLast / indexCount;
222 recordSkip = fatd->clStackLast % indexCount;
224 fatStartSector = fatd->partBpb.partStart + fatd->partBpb.resSectors;
226 for (i = sectorSkip; i < fatd->partBpb.fatSize && fatd->clStackIndex < MAX_CLUSTER_STACK ; i++) {
227 unsigned char* sbuf = NULL; //sector buffer
229 ret = READ_SECTOR(fatd->dev, fatStartSector + i, sbuf);
230 if (ret < 0) {
231 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatStartSector + i);
232 return -EIO;
234 for (j = recordSkip; j < indexCount && fatd->clStackIndex < MAX_CLUSTER_STACK ; j++) {
235 cluster = getI16(sbuf + (j * 2));
236 if (cluster == 0) { //the cluster is free
237 fatd->clStackLast = (i * indexCount) + j;
238 fatd->clStack[fatd->clStackIndex] = fatd->clStackLast;
239 XPRINTF("USBHDFSD: %d ", fatd->clStack[fatd->clStackIndex]);
240 fatd->clStackIndex++;
243 recordSkip = 0;
245 XPRINTF("USBHDFSD: \n");
246 //the stack operates as LIFO but we put in the clusters as FIFO
247 //we should reverse the cluster order - not necessary
248 //but it will retain the natural (increasing) order of
249 //the cluster chain
250 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
251 return fatd->clStackIndex;
254 //---------------------------------------------------------------------------
256 scan FAT for free clusters and store them to the cluster stack
258 int fat_readEmptyClusters(fat_driver* fatd) {
259 switch (fatd->partBpb.fatType)
261 case FAT12: return fat_readEmptyClusters12(fatd);
262 case FAT16: return fat_readEmptyClusters16(fatd);
263 case FAT32: return fat_readEmptyClusters32(fatd);
266 return(-1);
270 //---------------------------------------------------------------------------
272 set sinlge cluster record (FAT12)into buffer
274 0x321, 0xABC
276 byte0|byte1|byte2|
277 +--+--+--+--+--+--+
278 |2 |1 |C |3 |A |B |
279 +--+--+--+--+--+--+
282 void fat_setClusterRecord12(unsigned char* buf, unsigned int cluster, int type) {
284 if (type) { //type 1
285 buf[0] = (buf[0] & 0x0F) + ((cluster & 0x0F)<<4) ;
286 buf[1] = (cluster & 0xFF0) >> 4;
287 } else { // type 0
288 buf[0] = (cluster & 0xFF);
289 buf[1] = (buf[1] & 0xF0) + ((cluster & 0xF00) >> 8);
294 //---------------------------------------------------------------------------
295 void fat_setClusterRecord12part1(unsigned char* buf, unsigned int cluster, int type) {
296 if (type) { //type 1
297 buf[0] = (buf[0] & 0x0F) + ((cluster & 0x0F)<<4);
298 } else { // type 0
299 buf[0] = (cluster & 0xFF);
303 //---------------------------------------------------------------------------
304 void fat_setClusterRecord12part2(unsigned char* buf, unsigned int cluster, int type) {
305 if (type) { //type 1
306 buf[0] = (cluster & 0xFF0) >> 4;
307 } else { // type 0
308 buf[0] = (buf[0] & 0xF0) + ((cluster & 0xF00) >> 8);
312 //---------------------------------------------------------------------------
314 save value at the cluster record in FAT 12
316 int fat_saveClusterRecord12(fat_driver* fatd, unsigned int currentCluster, unsigned int value)
318 int ret;
319 int sectorSpan;
320 int recordOffset;
321 int recordType;
322 int fatNumber;
323 unsigned int fatSector;
325 ret = -1;
326 //recordOffset is byte offset of the record from the start of the fat table
327 recordOffset = (currentCluster * 3) / 2;
329 //save both fat tables
330 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
331 unsigned char* sbuf = NULL; //sector buffer
333 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
334 fatSector += recordOffset / fatd->partBpb.sectorSize;
335 sectorSpan = fatd->partBpb.sectorSize - (recordOffset % fatd->partBpb.sectorSize);
336 if (sectorSpan > 1) {
337 sectorSpan = 0;
339 recordType = currentCluster % 2;
341 ret = READ_SECTOR(fatd->dev, fatSector, sbuf);
342 if (ret < 0) {
343 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector);
344 return -EIO;
346 if (!sectorSpan) { // not sector span - the record is copmact and fits in single sector
347 fat_setClusterRecord12(sbuf + (recordOffset % fatd->partBpb.sectorSize), value, recordType);
348 ret = WRITE_SECTOR(fatd->dev, fatSector);
349 if (ret < 0) {
350 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector);
351 return -EIO;
353 } else { // sector span - the record is broken in 2 pieces - each one on different sector
354 //modify one last byte of the sector buffer
355 fat_setClusterRecord12part1(sbuf + (recordOffset % fatd->partBpb.sectorSize), value, recordType);
356 //save current sector
357 ret = WRITE_SECTOR(fatd->dev, fatSector);
358 if (ret < 0) {
359 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector);
360 return -EIO;
362 //read next sector from the fat
363 fatSector++;
364 ret = READ_SECTOR(fatd->dev, fatSector, sbuf);
365 if (ret < 0) {
366 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector);
367 return -EIO;
369 //modify first byte of the sector buffer
370 fat_setClusterRecord12part2(sbuf, value, recordType);
371 //save current sector
372 ret = WRITE_SECTOR(fatd->dev, fatSector);
373 if (ret < 0) {
374 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector);
375 return -EIO;
378 } //end for
379 return ret;
382 //---------------------------------------------------------------------------
384 save value at the cluster record in FAT 32
386 int fat_saveClusterRecord16(fat_driver* fatd, unsigned int currentCluster, unsigned int value) {
387 int i;
388 int ret;
389 int indexCount;
390 int fatNumber;
391 unsigned int fatSector;
393 ret = -1;
394 //indexCount is numer of cluster indices per sector
395 indexCount = fatd->partBpb.sectorSize / 2; //FAT16->2, FAT32->4
397 //save both fat tables
398 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
399 unsigned char* sbuf = NULL; //sector buffer
401 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
402 fatSector += currentCluster / indexCount;
404 ret = READ_SECTOR(fatd->dev, fatSector, sbuf);
405 if (ret < 0) {
406 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector);
407 return -EIO;
409 i = currentCluster % indexCount;
410 i*=2; //fat16
411 sbuf[i++] = value & 0xFF;
412 sbuf[i] = ((value & 0xFF00) >> 8);
413 ret = WRITE_SECTOR(fatd->dev, fatSector);
414 if (ret < 0) {
415 printf("USBHDFSD: Write fat16 sector failed! sector=%i! \n", fatSector);
416 return -EIO;
419 return ret;
422 //---------------------------------------------------------------------------
424 save value at the cluster record in FAT 16
426 int fat_saveClusterRecord32(fat_driver* fatd, unsigned int currentCluster, unsigned int value) {
427 int i;
428 int ret;
429 int indexCount;
430 int fatNumber;
431 unsigned int fatSector;
433 ret = -1;
434 //indexCount is numer of cluster indices per sector
435 indexCount = fatd->partBpb.sectorSize / 4; //FAT16->2, FAT32->4
437 //save both fat tables
438 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
439 unsigned char* sbuf = NULL; //sector buffer
441 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
442 fatSector += currentCluster / indexCount;
444 ret = READ_SECTOR(fatd->dev, fatSector, sbuf);
445 if (ret < 0) {
446 printf("USBHDFSD: Read fat32 sector failed! sector=%i! \n", fatSector);
447 return -EIO;
449 i = currentCluster % indexCount;
450 i*=4; //fat32
451 sbuf[i++] = value & 0xFF;
452 sbuf[i++] = ((value & 0xFF00) >> 8);
453 sbuf[i++] = ((value & 0xFF0000) >> 16);
454 sbuf[i] = (sbuf[i] &0xF0) + ((value >> 24) & 0x0F); //preserve the highest nibble intact
456 ret = WRITE_SECTOR(fatd->dev, fatSector);
457 if (ret < 0) {
458 printf("USBHDFSD: Write fat32 sector failed! sector=%i! \n", fatSector);
459 return -EIO;
462 return ret;
466 //---------------------------------------------------------------------------
468 Append (and write) cluster chain to the FAT table.
470 currentCluster - current end cluster record.
471 endCluster - new end cluster record.
473 Note: there is no checking wether the currentCluster holds the EOF marker!
475 Example
476 current FAT:
478 index 09 10 11 12
479 +-----+-----+-----+-----+
480 value + 10 | EOF | 0 | 0 |
481 +-----+-----+-----+-----+
484 currentcluster = 10, endcluster = 12
485 updated FAT (after the function ends):
487 index 09 10 11 12
488 +-----+-----+-----+-----+
489 value + 10 | 12 | 0 | EOF |
490 +-----+-----+-----+-----+
493 //---------------------------------------------------------------------------
494 int fat_appendClusterChain(fat_driver* fatd, unsigned int currentCluster, unsigned int endCluster) {
495 int ret;
496 ret = -1;
497 switch (fatd->partBpb.fatType) {
498 case FAT12:
499 ret = fat_saveClusterRecord12(fatd, currentCluster, endCluster);
500 if (ret < 0) return ret;
501 ret = fat_saveClusterRecord12(fatd, endCluster, 0xFFF);
502 break;
504 case FAT16:
505 XPRINTF("USBHDFSD: I: appending cluster chain : current=%d end=%d \n", currentCluster, endCluster);
506 ret = fat_saveClusterRecord16(fatd, currentCluster, endCluster);
507 if (ret < 0) return ret;
508 ret = fat_saveClusterRecord16(fatd, endCluster, 0xFFFF);
509 break;
511 case FAT32:
512 ret = fat_saveClusterRecord32(fatd, currentCluster, endCluster);
513 if (ret < 0) return ret;
514 ret = fat_saveClusterRecord32(fatd, endCluster, 0xFFFFFFF);
515 break;
517 return ret;
520 //---------------------------------------------------------------------------
522 create new cluster chain (of size 1 cluster) at the cluster index
524 int fat_createClusterChain(fat_driver* fatd, unsigned int cluster) {
525 switch (fatd->partBpb.fatType) {
526 case FAT12: return fat_saveClusterRecord12(fatd, cluster, 0xFFF);
527 case FAT16: return fat_saveClusterRecord16(fatd, cluster, 0xFFFF);
528 case FAT32: return fat_saveClusterRecord32(fatd, cluster, 0xFFFFFFF);
530 return -EFAULT;
533 //---------------------------------------------------------------------------
535 modify the cluster (in FAT table) at the cluster index
537 int fat_modifyClusterChain(fat_driver* fatd, unsigned int cluster, unsigned int value) {
538 switch (fatd->partBpb.fatType) {
539 case FAT12: return fat_saveClusterRecord12(fatd, cluster, value);
540 case FAT16: return fat_saveClusterRecord16(fatd, cluster, value);
541 case FAT32: return fat_saveClusterRecord32(fatd, cluster, value);
543 return -EFAULT;
546 //---------------------------------------------------------------------------
548 delete cluster chain starting at cluster
550 int fat_deleteClusterChain(fat_driver* fatd, unsigned int cluster) {
551 int ret;
552 int size;
553 int cont;
554 int end;
555 int i;
557 if (cluster < 2) {
558 return -EFAULT;
560 XPRINTF("USBHDFSD: I: delete cluster chain starting at cluster=%d\n", cluster);
562 cont = 1;
564 while (cont) {
565 size = fat_getClusterChain(fatd, cluster, fatd->cbuf, MAX_DIR_CLUSTER, 1);
567 end = size-1; //do not delete last cluster in the chain buffer
569 for (i = 0 ; i < end; i++) {
570 ret = fat_modifyClusterChain(fatd, fatd->cbuf[i], 0);
571 if (ret < 0) {
572 return ret;
575 //the cluster chain continues
576 if (size == MAX_DIR_CLUSTER) {
577 cluster = fatd->cbuf[end];
578 } else {
579 //no more cluster entries - delete the last cluster entry
580 ret = fat_modifyClusterChain(fatd, fatd->cbuf[end], 0);
581 if (ret < 0) {
582 return ret;
584 cont = 0;
586 fat_invalidateLastChainResult(fatd); //prevent to misuse current (now deleted) fatd->cbuf
588 return 1;
591 //---------------------------------------------------------------------------
593 Get single empty cluster from the clusterStack (cS is small cache of free clusters)
594 Passed currentCluster is updated in the FAT and the new returned cluster index is
595 appended at the end of fat chain!
597 unsigned int fat_getFreeCluster(fat_driver* fatd, unsigned int currentCluster) {
599 int ret;
600 unsigned int result;
602 //cluster stack is empty - find and fill the cS
603 if (fatd->clStackIndex <= 0) {
604 fatd->clStackIndex = 0;
605 ret = fat_readEmptyClusters(fatd);
606 if (ret <= 0) return 0;
607 fatd->clStackIndex = ret;
610 //pop from cluster stack
611 fatd->clStackIndex--;
612 result = fatd->clStack[fatd->clStackIndex];
613 //append the cluster chain
614 if (currentCluster) {
615 ret = fat_appendClusterChain(fatd, currentCluster, result);
616 } else { //create new cluster chain
617 ret = fat_createClusterChain(fatd, result);
619 if (ret < 0) return 0;
620 return result;
623 //---------------------------------------------------------------------------
625 simple conversion of the char from lower case to upper case
627 USBHD_INLINE unsigned char toUpperChar(unsigned char c) {
628 if (c >96 && c < 123) {
629 return (c - 32);
631 return c;
634 //---------------------------------------------------------------------------
636 returns number of direntry positions that the name takes
637 //dlanor: Note that this only includes the long_name entries
639 int getDirentrySize(const unsigned char* lname) {
640 int len;
641 int result;
642 len = strlen(lname);
643 result = len / 13;
644 if (len % 13 > 0) result++;
645 return result;
648 //---------------------------------------------------------------------------
650 compute checksum of the short filename
652 unsigned char computeNameChecksum(const unsigned char* sname) {
653 unsigned char result;
654 int i;
656 result = 0;
657 for (i = 0; i < 11; i++) {
658 result = (0x80 * (0x01 & result)) + (result >> 1); //ROR 1
659 result += sname[i];
661 return result;
664 //---------------------------------------------------------------------------
666 fill the LFN (long filename) direntry
668 void setLfnEntry(const unsigned char* lname, int nameSize, unsigned char chsum, fat_direntry_lfn* dlfn, int part, int maxPart){
669 int i,j;
670 unsigned char name[26]; //unicode name buffer = 13 characters per 2 bytes
671 int nameStart;
673 nameStart = 13 * (part - 1);
674 j = nameSize - nameStart;
675 if (j > 13) {
676 j = 13;
679 //fake unicode conversion
680 for (i = 0; i < j; i++) {
681 name[i*2] = lname[nameStart + i];
682 name[i*2+1] = 0;
685 //rest of the name is zero terminated and padded with 0xFF
686 for (i = j; i < 13; i++) {
687 if (i == j) {
688 name[i*2] = 0;
689 name[i*2+1] = 0;
690 } else {
691 name[i*2] = 0xFF;
692 name[i*2+1] = 0xFF;
696 dlfn->entrySeq = part;
697 if (maxPart == part)
698 dlfn->entrySeq |= 0x40;
699 dlfn->checksum = chsum;
700 //1st part of the name
701 for (i = 0; i < 10; i++) dlfn->name1[i] = name[i];
702 //2nd part of the name
703 for (i = 0; i < 12; i++) dlfn->name2[i] = name[i+10];
704 //3rd part of the name
705 for (i = 0; i < 4; i++) dlfn->name3[i] = name[i+22];
706 dlfn->rshv = 0x0f;
707 dlfn->reserved1 = 0;
708 dlfn->reserved2[0] = 0;
709 dlfn->reserved2[1] = 0;
712 //---------------------------------------------------------------------------
714 update the SFN (long filename) direntry - DATE and TIME
716 void setSfnDate(fat_direntry_sfn* dsfn, int mode) {
717 int year, month, day, hour, minute, sec;
718 unsigned char tmpClk[4];
720 #ifdef WIN32
721 year = 0;
722 month = 0;
723 day = 0;
724 hour = 0;
725 minute = 0;
726 sec = 0;
727 #else
728 //ps2 specific routine to get time and date
729 cd_clock_t cdtime;
730 s32 tmp;
732 if(CdReadClock(&cdtime)!=0 && cdtime.stat==0)
735 tmp=cdtime.second>>4;
736 sec=(u32)(((tmp<<2)+tmp)<<1)+(cdtime.second&0x0F);
738 tmp=cdtime.minute>>4;
739 minute=(((tmp<<2)+tmp)<<1)+(cdtime.minute&0x0F);
741 tmp=cdtime.hour>>4;
742 hour=(((tmp<<2)+tmp)<<1)+(cdtime.hour&0x0F);
743 //hour= (hour + 4 + 12) % 24; // TEMP FIX (need to deal with timezones?)
745 tmp=cdtime.day>>4;
746 day=(((tmp<<2)+tmp)<<1)+(cdtime.day&0x0F);
748 tmp=cdtime.month>>4;
749 month=(((tmp<<2)+tmp)<<1)+(cdtime.month&0x0F);
751 tmp=cdtime.year>>4;
752 year=(((tmp<<2)+tmp)<<1)+(cdtime.year&0xF)+2000;
753 } else {
754 year = 2005; month = 1; day = 6;
755 hour = 14; minute = 12; sec = 10;
757 #endif
759 if (dsfn == NULL || mode == 0) {
760 return;
763 tmpClk[0] = (sec / 2) & 0x1F; //seconds
764 tmpClk[0] += (minute & 0x07) << 5; // minute
765 tmpClk[1] = (minute & 0x38) >> 3; // minute
766 tmpClk[1] += (hour & 0x1F) << 3; // hour
768 tmpClk[2] = (day & 0x1F); //day
769 tmpClk[2] += (month & 0x07) << 5; // month
770 tmpClk[3] = (month & 0x08) >> 3; // month
771 tmpClk[3] += ((year-1980) & 0x7F) << 1; //year
773 XPRINTF("USBHDFSD: year=%d, month=%d, day=%d h=%d m=%d s=%d \n", year, month, day, hour, minute, sec);
774 //set date & time of creation
775 if (mode & DATE_CREATE) {
776 dsfn->timeCreate[0] = tmpClk[0];
777 dsfn->timeCreate[1] = tmpClk[1];
778 dsfn->dateCreate[0] = tmpClk[2];
779 dsfn->dateCreate[1] = tmpClk[3];
780 dsfn->dateAccess[0] = tmpClk[2];
781 dsfn->dateAccess[1] = tmpClk[3];
783 //set date & time of modification
784 if (mode & DATE_MODIFY) {
785 dsfn->timeWrite[0] = tmpClk[0];
786 dsfn->timeWrite[1] = tmpClk[1];
787 dsfn->dateWrite[0] = tmpClk[2];
788 dsfn->dateWrite[1] = tmpClk[3];
792 //---------------------------------------------------------------------------
794 fill the SFN (short filename) direntry
796 void setSfnEntry(const unsigned char* shortName, char directory, fat_direntry_sfn* dsfn, unsigned int cluster) {
797 int i;
799 //name + ext
800 for (i = 0; i < 8; i++) dsfn->name[i] = shortName[i];
801 for (i = 0; i < 3; i++) dsfn->ext[i] = shortName[i+8];
803 if (directory > 0) {
804 dsfn->attr = FAT_ATTR_DIRECTORY;
805 } else {
806 dsfn->attr = FAT_ATTR_ARCHIVE;
808 dsfn->reservedNT = 0;
809 dsfn->clusterH[0] = (cluster & 0xFF0000) >> 16;
810 dsfn->clusterH[1] = (cluster & 0xFF000000) >> 24;
811 dsfn->clusterL[0] = (cluster & 0x00FF);
812 dsfn->clusterL[1] = (cluster & 0xFF00) >> 8;
814 //size is zero - because we don't know the filesize yet
815 for (i = 0; i < 4; i++) dsfn->size[i] = 0;
817 setSfnDate(dsfn, DATE_CREATE + DATE_MODIFY);
820 //---------------------------------------------------------------------------
822 Create short name by squeezing long name into the 8.3 name boundaries
823 lname - existing long name
824 sname - buffer where to store short name
826 returns: 0 if longname completely fits into the 8.3 boundaries
827 1 if long name have to be truncated (ie. INFORM~1.TXT)
828 <0 if invalid long name detected
830 int createShortNameMask(unsigned char* lname, unsigned char* sname) {
831 int i;
832 int size;
833 int j;
834 int fit;
836 if( (lname[0] == '.')
837 &&( (lname[1] == 0)
838 ||( (lname[1] == '.')
839 &&(lname[2] == 0))
843 return -EINVAL;
846 fit = 0;
847 //clean short name by putting space
848 for (i = 0; i < 11; i++) sname[i] = 32;
849 XPRINTF("USBHDFSD: Clear short name ='%s'\n", sname);
851 //detect number of dots and space characters in the long name
852 j = 0;
853 for (i = 0; lname[i] != 0; i++) {
854 if (lname[i] == '.') j++; else
855 if (lname[i] == 32 ) j+=2;
857 //long name contains no dot or one dot and no space char
858 if (j <= 1) fit++;
859 //XPRINTF("USBHDFSD: fit1=%d j=%d\n", fit, j);
861 //store name
862 for (i = 0; lname[i] !=0 && lname[i] != '.' && i < 8; i++) {
863 sname[i] = toUpperChar(lname[i]);
864 //short name must not contain spaces - replace space by underscore
865 if (sname[i] == 32) sname[i]='_';
867 //check wether last char is '.' and the name is shorter than 8
868 if (lname[i] == '.' || lname[i] == 0) {
869 fit++;
871 //XPRINTF("USBHDFSD: fit2=%d\n", fit);
873 //find the last dot "." - filename extension
874 size = strlen((const char*)lname);
875 size--;
877 for (i = size; i > 0 && lname[i] !='.'; i--);
878 if (lname[i] == '.') {
879 i++;
880 for (j=0; lname[i] != 0 && j < 3; i++, j++) {
881 sname[j+8] = toUpperChar(lname[i]);
883 //no more than 3 characters of the extension
884 if (lname[i] == 0) fit++;
885 } else {
886 //no dot detected in the long filename
887 fit++;
889 // XPRINTF("USBHDFSD: fit3=%d\n", fit);
890 // XPRINTF("USBHDFSD: Long name=%s Short name=%s \n", lname, sname);
892 //all 3 checks passed - the long name fits in the short name without restrictions
893 if (fit == 3) {
894 XPRINTF("USBHDFSD: Short name is loseles!\n");
895 return 0;
898 //one of the check failed - the short name have to be 'sequenced'
899 //do not allow spaces in the short name
900 for (i = 0; i < 8;i++) {
901 if (sname[i] == 32) sname[i] = '_';
903 return 1;
906 //---------------------------------------------------------------------------
908 separate path and filename
909 fname - the source (merged) string (input)
910 path - separated path (output)
911 name - separated filename (output)
913 int separatePathAndName(const unsigned char* fname, unsigned char* path, unsigned char* name) {
914 int path_len;
915 unsigned char *sp, *np;
917 if(!(sp=strrchr(fname, '/'))) //if last path separator missing ?
918 np = (char *)fname; // name starts at start of fname string
919 else //else last path separator found
920 np = sp+1; // name starts after separator
921 if(strlen(np) >= FAT_MAX_NAME) //if name is too long
922 return -ENAMETOOLONG; // return error code
923 strcpy(name, np); //copy name from correct part of fname string
924 if((path_len = (np - fname)) >= FAT_MAX_PATH) //if path is too long
925 return -ENAMETOOLONG; // return error code
926 strncpy(path, fname, path_len);//copy path from start of fname string
927 path[path_len] = 0; //terminate path
928 return 1;
931 //---------------------------------------------------------------------------
933 get the sequence number from existing direntry name
935 int getShortNameSequence(unsigned char* name, unsigned char* ext, unsigned char* sname) {
936 int i,j;
937 unsigned char* tmp;
938 unsigned char buf[8];
940 //at first: compare extensions
941 //if extensions differ then filenames are diffrerent and seq is 0
942 tmp = sname+8;
943 for (i = 0; i < 3; i++) {
944 if (ext[i] != tmp[i]) return 0;
947 //at second: find tilde '~' character (search backward from the end)
948 for (i = 7; i > 0 && name[i] !='~'; i--);
950 if (i == 0) return 0; // tilde char was not found or is at first character
952 //now compare the names - up to '~' position
953 //if names differ then filenames are different;
954 for (j=0; j < i;j++) {
955 if (name[j] != sname[j]) return 0;
958 //if we get to this point we know that extension and name match
959 //now get the sequence number behind the '~'
960 for (j = i+1; j<8; j++) buf[j-i-1] = name[j];
961 buf[j-i-1] = 0; //terminate
963 XPRINTF("USBHDFSD: found short name sequence number='%s' \n", buf);
964 return strtol((const char*)buf, NULL, 10);
967 //---------------------------------------------------------------------------
969 set the short name sequence number
971 int setShortNameSequence(fat_driver* fatd, unsigned char* sname) {
972 char number[8];
973 unsigned char *buf;
974 int i,j;
975 int seq;
976 unsigned char mask;
978 //dlanor: The code below was bugged in several ways, as it treated the high seq
979 //values stored in long_name records as separate seqs, and also failed to accept
980 //any valid seq value whose low part (stored in short_name record) was zero.
981 //I'm now replacing this garbage with a bit-mask oriented scheme
983 seq = SEQ_MASK_SIZE;
984 for(i=0; (i < (SEQ_MASK_SIZE>>3)); i++) { //for each mask byte
985 if((mask = fatd->seq_mask[i]) != 0xFF) { //if mask byte has any bit free
986 for(j=0; j<8; j++, mask>>=1) { //for each bit in byte
987 if((mask & 1)==0) { //if free bit found
988 seq = (i<<3)+j; //set seq value
989 break; //break bit loop
990 }//ends "if free bit found"
991 }//ends "for each bit in byte"
992 break; //break byte loop
993 }//ends "if mask byte has any bit free"
994 }//ends "for each mask byte"
996 memset(number, 0, 8);
997 sprintf(number, "%d", seq);
998 j = strlen(number);
1000 buf = sname + 7 - j;
1001 buf[0] = '~';
1002 buf++;
1003 for (i = 0; i < j; i++) buf[i] = number[i];
1005 return 0;
1008 //---------------------------------------------------------------------------
1010 find space where to put the direntry
1012 int getDirentryStoreOffset(fat_driver* fatd, int entryCount, int direntrySize ) {
1013 int i;
1014 int tightIndex;
1015 int looseIndex;
1016 int cont;
1017 int id;
1018 int slotStart;
1019 int slotSize;
1020 int mask_ix, mask_sh;
1023 //we search for sequence of deleted or empty entries (cleared bits in dir_used_mask)
1024 //1) search the tight slot (that fits completely. ex: size = 3, and slot space is 3 )
1025 //2) search the suitable (loose) slot (ex: size = 3, slot space is 5)
1027 slotStart = -1;
1028 slotSize = 0;
1029 tightIndex = -1;
1030 looseIndex = -1;
1031 cont = 1;
1032 //search the entries for entry types
1033 for (i = 0; i < entryCount && cont; i++) {
1034 mask_ix = i>>3;
1035 mask_sh = i&7;
1036 id = fatd->dir_used_mask[mask_ix] & (1<<mask_sh);
1037 if (id == 0) { //empty entry
1038 if (slotStart >= 0) {
1039 slotSize++;
1040 } else {
1041 slotStart = i;
1042 slotSize = 1;
1043 XPRINTF("USBHDFSD: *Start slot at index=%d ",slotStart);
1045 } else { //occupied entry
1046 if (tightIndex < 0 && slotSize == direntrySize) {
1047 tightIndex = slotStart;
1048 XPRINTF("USBHDFSD: !Set tight index= %d\n", tightIndex);
1050 if (looseIndex < 0 && slotSize > direntrySize) {
1051 looseIndex = slotStart + slotSize - direntrySize;
1052 XPRINTF("USBHDFSD: !Set loose index= %d\n", looseIndex);
1054 if (tightIndex >= 0 && looseIndex >= 0) {
1055 cont = 0;
1057 slotStart = -1;
1058 slotSize = 0;
1061 XPRINTF("USBHDFSD: \n");
1063 // tight index - smaller fragmentation of space, the larger blocks
1064 // are left for larger filenames.
1065 // loose index - more fragmentation of direntry space, but the direntry
1066 // name has space for future enlargement (of the name).
1067 // i.e. no need to reposition the direntry and / or
1068 // to allocate additional fat cluster for direntry space.
1070 // we prefere tight slot if available, othervise we use the loose slot.
1071 // if there are no tight and no loose slot then we position new direntry
1072 // at the end of current direntry space
1073 if (tightIndex >=0) {
1074 return tightIndex;
1076 if (looseIndex >=0) {
1077 return looseIndex;
1079 //last entry is (most likely) empty - and if so, use it
1080 mask_ix = (entryCount-1)>>3;
1081 mask_sh = (entryCount-1)&7;
1082 id = fatd->dir_used_mask[mask_ix] & (1<<mask_sh);
1083 if (id == 0) {
1084 return entryCount - 1;
1087 return entryCount;
1091 //---------------------------------------------------------------------------
1093 scans current directory entries and fills the info records
1095 lname - long filename (to test wether existing entry match the long name) (input)
1096 sname - short filename ( ditto ^^ ) (input)
1097 startCluster - valid start cluster of the directory or 0 if we scan the root directory (input)
1099 if file/directory already exist (return code 0) then:
1100 retSector - contains sector number of the direntry (output)
1101 retOffset - contains byte offse of the SFN direntry from start of the sector (output)
1102 the reason is to speed up modification of the SFN (size of the file)
1103 //dlanor: This function has been rewritten to use global bitmask arrays for output
1105 int fat_fillDirentryInfo(fat_driver* fatd, unsigned char* lname, unsigned char* sname,
1106 char directory, unsigned int* startCluster,
1107 unsigned int* retSector, int* retOffset) {
1108 fat_direntry_summary dir;
1109 int i, j;
1110 int dirSector;
1111 unsigned int startSector;
1112 unsigned int theSector;
1113 int cont;
1114 int ret;
1115 unsigned int dirPos;
1116 int seq;
1117 int mask_ix, mask_sh;
1118 mass_dev* mass_device = fatd->dev;
1120 memset(fatd->dir_used_mask, 0, DIR_MASK_SIZE/8);
1121 memset(fatd->seq_mask, 0, SEQ_MASK_SIZE/8);
1123 cont = 1;
1124 //clear name strings
1125 dir.sname[0] = 0;
1126 dir.name[0] = 0;
1128 j = 0;
1129 if (directory) directory = FAT_ATTR_DIRECTORY;
1131 fat_getDirentrySectorData(fatd, startCluster, &startSector, &dirSector);
1133 XPRINTF("USBHDFSD: dirCluster=%i startSector=%i (%i) dirSector=%i \n", *startCluster, startSector, startSector * mass_device->sectorSize, dirSector);
1135 //go through first directory sector till the max number of directory sectors
1136 //or stop when no more direntries detected
1137 for (i = 0; i < dirSector && cont; i++) {
1138 unsigned char* sbuf = NULL; //sector buffer
1140 //At cluster borders, get correct sector from cluster chain buffer
1141 if ((*startCluster != 0) && (i % fatd->partBpb.clusterSize == 0)) {
1142 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)]) -i;
1144 theSector = startSector + i;
1145 ret = READ_SECTOR(fatd->dev, theSector, sbuf);
1146 if (ret < 0) {
1147 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector);
1148 return -EIO;
1150 XPRINTF("USBHDFSD: read sector ok, scanning sector for direntries...\n");
1151 dirPos = 0;
1153 // go through start of the sector till the end of sector
1154 while (cont && (dirPos < fatd->partBpb.sectorSize) && (j < DIR_MASK_SIZE)) {
1155 fat_direntry* dir_entry = (fat_direntry*) (sbuf + dirPos);
1156 cont = fat_getDirentry(fatd->partBpb.fatType, dir_entry, &dir); //get single directory entry from sector buffer
1157 mask_ix = j>>3;
1158 mask_sh = j&7;
1159 switch (cont) {
1160 case 1: //short name
1161 fatd->dir_used_mask[mask_ix] |= (1<<mask_sh);
1162 if (!(dir.attr & FAT_ATTR_VOLUME_LABEL)) { //not volume label
1163 if ((strEqual(dir.sname, lname) == 0) || (strEqual(dir.name, lname) == 0) ) {
1164 //file we want to create already exist - return the cluster of the file
1165 if ((dir.attr & FAT_ATTR_DIRECTORY) != directory) {
1166 //found directory but requested is file (and vice veresa)
1167 if (directory) return -ENOTDIR;
1168 return -EISDIR;
1169 }//ends "if" clause for mismatched file/folder state
1170 XPRINTF("USBHDFSD: I: entry found! %s, %s = %s\n", dir.name, dir.sname, lname);
1171 *retSector = theSector;
1172 *retOffset = dirPos;
1173 *startCluster = dir.cluster;
1174 fatd->deSec[fatd->deIdx] = theSector;
1175 fatd->deOfs[fatd->deIdx] = dirPos;
1176 fatd->deIdx++;
1177 return 0;
1178 }//ends "if" clause for matching name
1179 seq = getShortNameSequence(dir_entry->sfn.name, dir_entry->sfn.ext, sname);
1180 if(seq < SEQ_MASK_SIZE)
1181 fatd->seq_mask[seq>>3] |= (1<<(seq & 7));
1182 fatd->deIdx = 0;
1183 //clear name strings
1184 dir.sname[0] = 0;
1185 dir.name[0] = 0;
1186 }//ends "if(!(dir.attr & FAT_ATTR_VOLUME_LABEL))"
1187 else { //dlanor: Volume label
1188 fatd->deIdx = 0;
1190 break;
1191 case 2: //long name
1192 fatd->dir_used_mask[mask_ix] |= (1<<mask_sh);
1193 fatd->deSec[fatd->deIdx] = theSector;
1194 fatd->deOfs[fatd->deIdx] = dirPos;
1195 fatd->deIdx++;
1196 break;
1197 case 3: //empty
1198 fatd->deIdx = 0;
1199 break;
1200 }//ends "switch"
1201 dirPos += sizeof(fat_direntry);
1202 j++;
1205 //indicate inconsistency
1206 if (j >= DIR_MASK_SIZE) {
1207 j++;
1209 return j;
1212 //---------------------------------------------------------------------------
1214 check wether the new direntries (note: one file have at least 2 direntries for 1 SFN and 1..n LFN)
1215 fit into the current directory space.
1216 Enlarges the directory space if needed and possible (note: root dirspace can't be enlarged for fat12 and fat16)
1218 startCluster - valid start cluster of dirpace or 0 for the root directory
1219 entryCount - number of direntries of the filename (at least 2)
1220 entryIndex - index where to store new direntries
1221 direntrySize - number of all direntries in the directory
1224 int enlargeDirentryClusterSpace(fat_driver* fatd, unsigned int startCluster, int entryCount, int entryIndex, int direntrySize)
1226 int ret;
1227 int dirSector;
1228 unsigned int startSector;
1229 int i;
1230 int maxSector;
1231 int entriesPerSector;
1232 int chainSize;
1233 unsigned int currentCluster;
1234 unsigned int newCluster;
1236 i = entryIndex + direntrySize;
1237 XPRINTF("USBHDFSD: cur=%d ecount=%d \n", i, entryCount);
1238 //we don't need to enlarge directory cluster space
1239 if (i <= entryCount) return 0; //direntry fits into current space
1241 entriesPerSector = fatd->partBpb.sectorSize / 32;
1242 maxSector = i / entriesPerSector;
1243 if (i%entriesPerSector) {
1244 maxSector++;
1247 chainSize = fat_getDirentrySectorData(fatd, &startCluster, &startSector, &dirSector);
1249 XPRINTF("USBHDFSD: maxSector=%d dirSector=%d\n", maxSector, dirSector);
1251 if (maxSector<=dirSector) return 0;
1253 //Root directory of FAT12 or FAT16 - space can't be enlarged!
1254 if (startCluster == 0 && fatd->partBpb.fatType < FAT32) {
1255 return -EMLINK; //too many direntries in the root directory
1258 //in the fatd->cbuf we have the cluster chain
1260 //get last cluster of the cluster chain
1261 currentCluster = fatd->cbuf[chainSize-1];
1262 XPRINTF("USBHDFSD: current (last) cluster=%d \n", currentCluster);
1264 //get 1 cluster from cluster stack and append the chain
1265 newCluster = fat_getFreeCluster(fatd, currentCluster);
1266 XPRINTF("USBHDFSD: new cluster=%d \n", newCluster);
1267 fat_invalidateLastChainResult(fatd); //prevent to misuse current (now updated) fatd->cbuf
1268 //if new cluster cannot be allocated
1269 if (newCluster == 0) {
1270 return -ENOSPC;
1273 // now clean the directory space
1274 startSector = fat_cluster2sector(&fatd->partBpb, newCluster);
1275 for (i = 0; i < fatd->partBpb.clusterSize; i++) {
1276 unsigned char* sbuf = NULL; //sector buffer
1278 ret = ALLOC_SECTOR(fatd->dev, startSector + i, sbuf);
1279 memset(sbuf, 0 , fatd->partBpb.sectorSize); //fill whole sector with zeros
1280 ret = WRITE_SECTOR(fatd->dev, startSector + i);
1281 if (ret < 0) return -EIO;
1283 return 1; // 1 cluster allocated
1286 //---------------------------------------------------------------------------
1288 Create empty directory space with two SFN direntries:
1289 1) current directory "."
1290 2) parent directory ".."
1293 int createDirectorySpace(fat_driver* fatd, unsigned int dirCluster, unsigned int parentDirCluster) {
1294 int i, j;
1295 int ret;
1296 unsigned int startSector;
1298 //we do not mess with root directory
1299 if (dirCluster < 2) {
1300 return -EFAULT;
1303 //we create directory space inside one cluster. No need to worry about
1304 //large dir space spread on multiple clusters
1305 startSector = fat_cluster2sector(&fatd->partBpb, dirCluster);
1306 XPRINTF("USBHDFSD: I: create dir space: cluster=%d sector=%d (%d) \n", dirCluster, startSector, startSector * fatd->partBpb.sectorSize);
1308 //go through all sectors of the cluster
1309 for (i = 0; i < fatd->partBpb.clusterSize; i++) {
1310 unsigned char* sbuf = NULL; //sector buffer
1312 ret = READ_SECTOR(fatd->dev, startSector + i, sbuf);
1313 if (ret < 0) {
1314 printf("USBHDFSD: read directory sector failed ! sector=%i\n", startSector + i);
1315 return -EIO;
1317 memset(sbuf, 0, fatd->partBpb.sectorSize); //clean the sector
1318 if (i == 0) {
1319 fat_direntry_sfn* dsfn = (fat_direntry_sfn*) sbuf;
1320 unsigned char name[11];
1321 for (j = 0; j< 11; j++) name[j] = 32;
1322 name[0] = '.';
1323 setSfnEntry(name, 1, dsfn + 0, dirCluster);
1324 name[1] = '.';
1325 setSfnEntry(name, 1, dsfn + 1, parentDirCluster);
1327 ret = WRITE_SECTOR(fatd->dev, startSector + i);
1328 if (ret < 0) {
1329 printf("USBHDFSD: write directory sector failed ! sector=%i\n", startSector + i);
1330 return -EIO;
1334 return(0);
1338 //---------------------------------------------------------------------------
1340 Save direntries of the long and short filename to the directory space on the disk
1342 startCluster - start cluster of the directory space
1343 lname : long name
1344 sname : short name
1345 directory : 0-file, 1-directory
1346 cluster : start cluster of the file/directory
1348 entrySize - number of direntries to store
1349 entryIndex - index of the direntry start in the directory space
1351 retSector - contains sector number of the direntry (output)
1352 retOffset - contains byte offse of the SFN direntry from start of the sector (output)
1353 the reason is to speed up modification of the SFN (size of the file)
1355 note: the filesize set in the direntry is 0 (for both directory and file)
1357 int saveDirentry(fat_driver* fatd, unsigned int startCluster,
1358 const unsigned char* lname, const unsigned char* sname, char directory, unsigned int cluster,
1359 int entrySize, int entryIndex, unsigned int* retSector, int* retOffset) {
1360 int i, j;
1361 int dirSector;
1362 unsigned int startSector;
1363 unsigned int theSector;
1364 int cont;
1365 int ret;
1366 unsigned int dirPos;
1367 int entryEndIndex;
1368 int writeFlag;
1369 mass_dev* mass_device = fatd->dev;
1370 int part = entrySize - 1;
1371 int nameSize;
1372 unsigned char chsum;
1374 chsum = computeNameChecksum(sname);
1375 nameSize = strlen(lname);
1377 cont = 1;
1378 //clear name strings
1379 entryEndIndex = entryIndex + entrySize;
1381 j = 0;
1383 fat_getDirentrySectorData(fatd, &startCluster, &startSector, &dirSector);
1385 XPRINTF("USBHDFSD: dirCluster=%i startSector=%i (%i) dirSector=%i \n", startCluster, startSector, startSector * mass_device->sectorSize, dirSector);
1387 //go through first directory sector till the max number of directory sectors
1388 //or stop when no more direntries detected
1389 for (i = 0; i < dirSector && cont; i++) {
1390 unsigned char* sbuf = NULL; //sector buffer
1392 //At cluster borders, get correct sector from cluster chain buffer
1393 if ((startCluster != 0) && (i % fatd->partBpb.clusterSize == 0)) {
1394 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)]) -i;
1396 theSector = startSector + i;
1397 ret = READ_SECTOR(fatd->dev, theSector, sbuf);
1398 if (ret < 0) {
1399 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector);
1400 return -EIO;
1402 XPRINTF("USBHDFSD: read sector ok, scanning sector for direntries...\n");
1403 dirPos = 0;
1404 writeFlag = 0;
1405 // go through start of the sector till the end of sector
1406 while (dirPos < fatd->partBpb.sectorSize) {
1407 if (j >=entryIndex && j < entryEndIndex) {
1408 fat_direntry* dir_entry = (fat_direntry*) (sbuf + dirPos);
1409 if (part == 0)
1410 setSfnEntry(sname, directory, &dir_entry->sfn, cluster);
1411 else
1412 setLfnEntry(lname, nameSize, chsum, &dir_entry->lfn, part, entrySize - 1);
1413 part--;
1414 writeFlag++;
1415 //SFN is stored
1416 if (j == entryEndIndex-1) {
1417 *retSector = theSector;
1418 *retOffset = dirPos;
1421 //sbuf + dirPos
1422 dirPos += sizeof(fat_direntry);
1423 j++;
1424 }//ends "while"
1425 //store modified sector
1426 if (writeFlag) {
1427 ret = WRITE_SECTOR(fatd->dev, theSector);
1428 if (ret < 0) {
1429 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector);
1430 return -EIO;
1433 if (j >= entryEndIndex) {
1434 cont = 0; //do not continue
1437 return j;
1440 //---------------------------------------------------------------------------
1442 - create/convert long name to short name
1443 - analyse directory space
1444 - enlarge directory space
1445 - save direntries
1447 lname - long name
1448 directory - 0-> create file 1->create directory
1449 escapeNoExist - 0->allways create file 1->early exit if file doesn't exist
1450 startCluster - directory space start cluster (set to zero for root directory)
1451 retSector - SFN sector - sector of the SFN direntry (output)
1452 retOffset - byte offset of the SFN direntry counting from the start of the sector (output)
1455 int fat_modifyDirSpace(fat_driver* fatd, unsigned char* lname, char directory, char escapeNotExist, unsigned int* startCluster, unsigned int* retSector, int* retOffset) {
1456 int ret;
1457 unsigned char sname[12]; //short name 8+3 + terminator
1458 unsigned int newCluster;
1459 int entryCount;
1460 int compressShortName;
1461 int entryIndex;
1462 int direntrySize;
1464 //dlanor: Since each filename may need up to 11 directory entries (MAX_FAT_NAME==128)
1465 //dlanor: I've rewritten the methods of this function to use global bitmasks as this
1466 //dlanor: allows more effective entry handling than most other methods
1468 //memo buffer for each direntry - up to 1024 entries in directory
1469 // 7 6 5 4 3 2 | 1 0
1470 // ------------+-----
1471 // SEQ HI/LO | ID
1472 // ------------------
1473 // ID : 0 - entry is empty or deleted
1474 // 1 - sfn entry
1475 // 2 - lfn entry
1476 // 3 - other entry (volume label etc.)
1477 // SEQ: sequence number of the short filename.
1478 // if our long filename is "Quitelongname.txt" then
1479 // seq for existing entry:
1480 // ABCD.TXT seq = 0 (no sequence number in name and name doesn't match)
1481 // ABCDEF~1.TXT seq = 0 (because the short names doesn't match)
1482 // QUITELON.TXT seq = 0 (again the short name doesn't match)
1483 // QUITEL~1.JPG seq = 0 (name match but extension desn't match)
1484 // QUITEL~1.TXT seq = 1 (both name and extension match - sequence number 1)
1485 // QUITE~85.TXT seq = 85 ( dtto. ^^^^)
1487 // If the sfn has sequence it means the filename should be long
1488 // and preceeding entry should be lfn. In this case the preceeding (lfn)
1489 // entry seq holds the high 6 bites of the whole sequence. If preceding
1490 // entry is another sfn direntry then we report error (even if it might be
1491 // (in some rare occasions) correct directory structure).
1494 sname[11] = 0;
1496 //create short name from long name
1497 ret = createShortNameMask(lname,sname);
1498 if (ret < 0) {
1499 XPRINTF("USBHDFSD: E: short name invalid!\n");
1500 return ret;
1502 compressShortName = ret;
1504 //get information about existing direntries (palcement of the empty/reusable direntries)
1505 //and sequence numbers of the short filenames
1506 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1507 startCluster, retSector, retOffset);
1508 if (ret < 0) {
1509 XPRINTF("USBHDFSD: E: direntry data invalid!\n");
1510 return ret;
1512 //ret 0 means that exact filename/directory already exist
1513 if (ret == 0) {
1514 return ret;
1517 //exact filename not exist and we want to report it
1518 if (escapeNotExist) {
1519 return -ENOENT;
1523 if (ret > DIR_MASK_SIZE) {
1524 XPRINTF("USBHDFSD: W: Direntry count is larger than number of records!\n");
1525 ret = DIR_MASK_SIZE;
1527 entryCount = ret;
1528 XPRINTF("USBHDFSD: I: direntry count=%d\n", entryCount);
1530 if (compressShortName) {
1531 setShortNameSequence(fatd, sname);
1533 XPRINTF("USBHDFSD: I: new short name='%s' \n", sname);
1535 //direntry size for long name + 1 additional direntry for short name
1536 direntrySize = getDirentrySize(lname) + 1;
1537 XPRINTF("USBHDFSD: Direntry size=%d\n", direntrySize);
1539 //find the offset (index) of the direntry space where to put this direntry
1540 entryIndex = getDirentryStoreOffset(fatd, entryCount, direntrySize);
1541 XPRINTF("USBHDFSD: I: direntry store offset=%d\n", entryIndex);
1543 //if the direntry offset excede current space of directory clusters
1544 //we have to add one cluster to directory space
1545 ret = enlargeDirentryClusterSpace(fatd, *startCluster, entryCount, entryIndex, direntrySize);
1546 XPRINTF("USBHDFSD: I: enlarge direntry cluster space ret=%d\n", ret);
1547 if (ret < 0) {
1548 return ret;
1551 //get new cluster for file/directory
1552 newCluster = fat_getFreeCluster(fatd, 0);
1553 if (newCluster == 0) {
1554 return -ENOSPC;
1556 XPRINTF("USBHDFSD: I: new file/dir cluster=%d\n", newCluster);
1558 //now store direntries into the directory space
1559 ret = saveDirentry(fatd, *startCluster, lname, sname, directory, newCluster, direntrySize, entryIndex, retSector, retOffset);
1560 XPRINTF("USBHDFSD: I: save direntry ret=%d\n", ret);
1561 if (ret < 0) {
1562 return ret;
1565 //create empty directory structure
1566 if (directory) {
1567 ret = createDirectorySpace(fatd, newCluster, *startCluster);
1568 XPRINTF("USBHDFSD: I: create directory space ret=%d\n", ret);
1569 if (ret < 0) {
1570 return ret;
1574 return 1;
1578 //---------------------------------------------------------------------------
1580 Check whether directory space contain any file or directory
1582 startCluster - start cluster of the directory space
1584 returns: 0 - false - directory space contains files or directories (except '.' and '..')
1585 1 - true - directory space is empty or contains deleted entries
1586 -X - error
1588 int checkDirspaceEmpty(fat_driver* fatd, unsigned int startCluster) {
1589 int ret;
1590 int i;
1591 unsigned char sname[12]; //short name 8+3 + terminator
1592 int entryCount;
1594 unsigned int retSector;
1595 int retOffset;
1597 XPRINTF("USBHDFSD: I: checkDirspaceEmpty directory cluster=%d \n", startCluster);
1598 if (startCluster < 2) { // do not check root directory!
1599 return -EFAULT;
1602 sname[0] = 0;
1605 ret = fat_fillDirentryInfo(fatd, sname, sname, 1,
1606 &startCluster, &retSector, &retOffset);
1607 if (ret > DIR_MASK_SIZE) {
1608 XPRINTF("USBHDFSD: W: Direntry count is larger than number of records! directory space cluster =%d maxRecords=%d\n", startCluster, DIR_MASK_SIZE);
1609 ret = DIR_MASK_SIZE;
1611 entryCount = ret;
1612 //first two records should be '.' & '..', which don't count as real content
1613 if((fatd->dir_used_mask[0] & 0xFC) != 0)
1614 goto non_empty;
1615 for (i=1; i < (entryCount/8); i++) {
1616 if(fatd->dir_used_mask[i] != 0) {
1617 non_empty:
1618 XPRINTF("USBHDFSD: I: directory not empty!\n");
1619 return 0;
1620 }//ends "if"
1621 }//ends "for"
1622 XPRINTF("USBHDFSD: I: directory is empty.\n");
1623 return 1;
1626 //---------------------------------------------------------------------------
1628 Remove the name (direntries of the file or directory) from the directory space.
1630 lname - long name (without the path)
1631 directory - 0->delete file 1-delete directory
1632 startCluster - start cluster of the directory space
1635 int fat_clearDirSpace(fat_driver* fatd, unsigned char* lname, char directory, unsigned int* startCluster) {
1636 int ret;
1637 int i;
1638 unsigned char sname[12]; //short name 8+3 + terminator
1639 unsigned int dirCluster;
1640 unsigned int theSector;
1641 unsigned int sfnSector;
1642 int sfnOffset;
1643 unsigned char* sbuf = NULL; //sector buffer ????
1645 sname[0] = 0;
1648 dirCluster = *startCluster;
1649 //get information about existing direntries (palcement of the empty/reusable direntries)
1650 //and find the lname in the directory
1651 //also fill up the dsSec and dsOfs information
1652 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1653 startCluster, &sfnSector, &sfnOffset);
1654 if (ret != 0) {
1655 XPRINTF("USBHDFSD: E: direntry not found!\n");
1656 return -ENOENT;
1658 XPRINTF("USBHDFSD: clear dir space: dir found at cluster=%d \n ", *startCluster);
1660 //Check wether any file or directory exist in te target directory space.
1661 //We should not delete the directory if files/directories exist
1662 //because just clearing the dir doesn't free the fat clusters
1663 //occupied by files.
1664 if (directory) {
1665 //check wether sub-directory is empty
1666 //startCluster now points to subdirectory start cluster
1667 ret = checkDirspaceEmpty(fatd, *startCluster);
1668 if (ret == 0) { //directorty contains some files
1669 return -ENOTEMPTY;
1671 //read the direntry info again, because we lost it during subdir check
1672 *startCluster = dirCluster;
1674 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1675 startCluster, &sfnSector, &sfnOffset);
1676 if (ret != 0) {
1677 XPRINTF("USBHDFSD: E: direntry not found!\n");
1678 return -ENOENT;
1682 //now mark direntries as deleted
1683 theSector = 0;
1684 for (i = 0; i < fatd->deIdx; i++) {
1685 if (fatd->deSec[i] != theSector) {
1686 if (theSector > 0) {
1687 ret = WRITE_SECTOR(fatd->dev, theSector);
1688 if (ret < 0) {
1689 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector);
1690 return -EIO;
1693 theSector = fatd->deSec[i];
1694 ret = READ_SECTOR(fatd->dev, theSector, sbuf);
1695 if (ret < 0) {
1696 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector);
1697 return -EIO;
1700 sbuf[fatd->deOfs[i]] = 0xE5; //delete marker
1702 if (theSector > 0) {
1703 ret = WRITE_SECTOR(fatd->dev, theSector);
1704 if (ret < 0) {
1705 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector);
1706 return -EIO;
1710 //now delete whole cluster chain starting at the file's first cluster
1711 ret = fat_deleteClusterChain(fatd, *startCluster);
1712 if (ret < 0) {
1713 XPRINTF("USBHDFSD: E: delete cluster chain failed!\n");
1714 return ret;
1716 return 1;
1722 /* ===================================================================== */
1725 cluster - start cluster of the file
1726 sfnSector - short filename entry sector
1727 sfnOffset - short filename entry offset from the sector start
1729 int fat_truncateFile(fat_driver* fatd, unsigned int cluster, unsigned int sfnSector, int sfnOffset ) {
1730 int ret;
1731 fat_direntry_sfn* dsfn;
1732 unsigned char* sbuf = NULL; //sector buffer
1734 if (cluster == 0 || sfnSector == 0) {
1735 return -EFAULT;
1739 //now delete whole cluster chain starting at the file's first cluster
1740 ret = fat_deleteClusterChain(fatd, cluster);
1741 if (ret < 0) {
1742 XPRINTF("USBHDFSD: E: delete cluster chain failed!\n");
1743 return ret;
1746 //terminate cluster
1747 ret = fat_createClusterChain(fatd, cluster);
1748 if (ret < 0) {
1749 XPRINTF("USBHDFSD: E: truncate cluster chain failed!\n");
1750 return ret;
1753 ret = READ_SECTOR(fatd->dev, sfnSector, sbuf);
1754 if (ret < 0) {
1755 printf("USBHDFSD: read direntry sector failed ! sector=%i\n", sfnSector);
1756 return -EIO;
1758 dsfn = (fat_direntry_sfn*) (sbuf + sfnOffset);
1759 dsfn->size[0] = 0;
1760 dsfn->size[1] = 0;
1761 dsfn->size[2] = 0;
1762 dsfn->size[3] = 0;
1764 ret = WRITE_SECTOR(fatd->dev, sfnSector);
1765 if (ret < 0) {
1766 printf("USBHDFSD: write directory sector failed ! sector=%i\n", sfnSector);
1767 return -EIO;
1769 return 1;
1773 //---------------------------------------------------------------------------
1775 Update size of the SFN entry
1777 cluster - start cluster of the file
1778 sfnSector - short filename entry sector
1779 sfnOffset - short filename entry offset from the sector start
1781 int fat_updateSfn(fat_driver* fatd, int size, unsigned int sfnSector, int sfnOffset ) {
1782 int ret;
1783 fat_direntry_sfn* dsfn;
1784 unsigned char* sbuf = NULL; //sector buffer
1786 if (sfnSector == 0) {
1787 return -EFAULT;
1791 ret = READ_SECTOR(fatd->dev, sfnSector, sbuf);
1792 if (ret < 0) {
1793 printf("USBHDFSD: read direntry sector failed ! sector=%i\n", sfnSector);
1794 return -EIO;
1796 dsfn = (fat_direntry_sfn*) (sbuf + sfnOffset);
1797 dsfn->size[0] = size & 0xFF;
1798 dsfn->size[1] = (size & 0xFF00) >> 8;
1799 dsfn->size[2] = (size & 0xFF0000) >> 16;
1800 dsfn->size[3] = (size & 0xFF000000) >> 24;
1802 setSfnDate(dsfn, DATE_MODIFY);
1804 ret = WRITE_SECTOR(fatd->dev, sfnSector);
1805 if (ret < 0) {
1806 printf("USBHDFSD: write directory sector failed ! sector=%i\n", sfnSector);
1807 return -EIO;
1809 XPRINTF("USBHDFSD: I: sfn updated, file size=%d \n", size);
1810 return 1;
1814 //---------------------------------------------------------------------------
1816 create file or directory
1818 fname - path and filename
1819 directory - set to 0 to create file, 1 to create directory
1820 escapeNotExist - set to 1 if you want to report error if file not exist.
1821 Otherwise set to 0 and file/dir will be created.
1822 cluster - start cluster of the directory space - default is 0 -> root directory
1823 sfnSector - sector of the SFN entry (output) - helps to modify direntry (size, date, time)
1824 sfnOffset - offset (in bytes) of the SFN entry (output)
1827 int fat_createFile(fat_driver* fatd, const unsigned char* fname, char directory, char escapeNotExist, unsigned int* cluster, unsigned int* sfnSector, int* sfnOffset) {
1828 int ret;
1829 unsigned int startCluster;
1830 unsigned int directoryCluster;
1831 unsigned char path[FAT_MAX_PATH];
1832 unsigned char lname[FAT_MAX_NAME];
1833 fat_dir fatdir;
1835 ret = separatePathAndName(fname, path, lname);
1836 if( (ret < 0) //if name invalid to separation routine
1837 ||( (lname[0] == 0) //or name is empty string
1838 ||( (lname[0]=='.')
1839 &&( (lname[1]==0) //or name is single period
1840 ||( (lname[1]=='.')
1841 &&(lname[2]==0) //or name is two periods
1848 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
1849 return -ENOENT;
1852 XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fat_createFile\n");
1853 //get start cluster of the last sub-directory of the path
1854 startCluster = 0;
1855 ret = fat_getFileStartCluster(fatd, (const char*)path, &startCluster, &fatdir);
1856 if (ret < 0) {
1857 XPRINTF("USBHDFSD: E: directory not found! \n");
1858 return ret;
1861 if (!(fatdir.attr & FAT_ATTR_DIRECTORY)) {
1862 XPRINTF("USBHDFSD: E: directory not found! \n");
1863 return -ENOENT;
1866 XPRINTF("USBHDFSD: directory=%s name=%s cluster=%d \n", path, lname, startCluster);
1868 if (fatdir.attr & FAT_ATTR_READONLY)
1869 return -EACCES;
1871 //modify directory space of the path (cread direntries)
1872 //and/or create new (empty) directory space if directory creation requested
1873 directoryCluster = startCluster;
1874 ret = fat_modifyDirSpace(fatd, lname, directory, escapeNotExist, &startCluster, sfnSector, sfnOffset);
1875 if (ret < 0) {
1876 XPRINTF("USBHDFSD: E: modifyDirSpace failed!\n");
1877 return ret;
1879 XPRINTF("USBHDFSD: I: SFN info: sector=%d (%d) offset=%d (%d) startCluster=%d\n", *sfnSector, *sfnSector * fatd->partBpb.sectorSize, *sfnOffset, *sfnOffset + (*sfnSector * fatd->partBpb.sectorSize), startCluster);
1880 *cluster = startCluster;
1881 //dlanor: I've repatched the stuff below to improve functionality
1882 //The simple test below was bugged for the case of creating a folder in root
1883 //if (startCluster != directoryCluster) {
1884 //That test (on the line above) fails in root because created folders never
1885 //get a startCluster of 0. That is reserved for root only.
1886 //The test below replaces this with a more complex test that takes all of this
1887 //stuff into proper account, but behaves like the old test for other cases.
1888 //That's mainly because I can't tell how consistent name conflict flagging is
1889 //for those other cases, and it's not really worth the trouble of finding out :)
1890 if( (ret == 0) //if we have a directly flagged name conflict
1891 ||( (directoryCluster || !directory) //OR working in non_root, or making a file
1892 &&(startCluster != directoryCluster) //AND we get an unexpected startCluster
1895 XPRINTF("USBHDFSD: I: file already exists at cluster=%d\n", startCluster);
1896 return 2;
1898 return 0;
1902 //---------------------------------------------------------------------------
1903 int fat_deleteFile(fat_driver* fatd, const unsigned char* fname, char directory) {
1904 int ret;
1905 unsigned int startCluster;
1906 unsigned int directoryCluster;
1907 unsigned char path[FAT_MAX_PATH];
1908 unsigned char lname[FAT_MAX_NAME];
1909 fat_dir fatdir;
1911 ret = separatePathAndName(fname, path, lname);
1912 if( (ret < 0) //if name invalid to separation routine
1913 ||( (lname[0] == 0) //or name is empty string
1914 ||( (lname[0]=='.')
1915 &&( (lname[1]==0) //or name is single period
1916 ||( (lname[1]=='.')
1917 &&(lname[2]==0) //or name is two periods
1924 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
1925 return -ENOENT;
1928 XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fat_deleteFile\n");
1929 //get start cluster of the last sub-directory of the path
1930 startCluster = 0;
1931 ret = fat_getFileStartCluster(fatd, (const char*)path, &startCluster, &fatdir);
1932 if (ret < 0) {
1933 XPRINTF("USBHDFSD: E: directory not found! \n");
1934 return ret;
1937 if (!(fatdir.attr & FAT_ATTR_DIRECTORY)) {
1938 XPRINTF("USBHDFSD: E: directory not found! \n");
1939 return -ENOENT;
1942 XPRINTF("USBHDFSD: directory=%s name=%s cluster=%d \n", path, lname, startCluster);
1944 if (fatdir.attr & FAT_ATTR_READONLY) {
1945 XPRINTF("USBHDFSD: E: directory read only! \n");
1946 return -EACCES;
1949 //delete direntries and modify fat
1950 directoryCluster = startCluster;
1951 ret = fat_clearDirSpace(fatd, lname, directory, &startCluster);
1952 if (ret < 0) {
1953 XPRINTF("USBHDFSD: E: cleanDirSpace failed!\n");
1954 return ret;
1956 if (startCluster != directoryCluster) {
1957 XPRINTF("USBHDFSD: I: file/dir removed from cluster=%d\n", startCluster);
1959 return 0;
1963 //---------------------------------------------------------------------------
1964 /* //This will eventually become a function for renaming objects on mass:,
1965 //but it's not yet operational, and therefore commented out
1967 int fat_renameFile(fat_driver* fatd, char* sPName, char* dPName, char directory) {
1968 int ret;
1969 unsigned int startCluster;
1970 unsigned int sDirCluster;
1971 unsigned int dDirCluster;
1972 unsigned char sPath[FAT_MAX_PATH];
1973 unsigned char sName[FAT_MAX_NAME];
1974 unsigned char dPath[FAT_MAX_PATH];
1975 unsigned char dName[FAT_MAX_NAME];
1978 ret = separatePathAndName(sPName, sPath, sName);
1979 if( (ret < 0) //if name invalid to separation routine
1980 ||( (sName[0] == 0) //or name is empty string
1981 ||( (sName[0]=='.')
1982 &&( (sName[1]==0) //or name is single period
1983 ||( (sName[1]=='.')
1984 &&(sName[2]==0) //or name is two periods
1991 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
1992 return -ENOENT;
1994 ret = separatePathAndName(dPName, dPath, dName);
1995 if( (ret < 0) //if name invalid to separation routine
1996 ||( (dName[0] == 0) //or name is empty string
1997 ||( (dName[0]=='.')
1998 &&( (dName[1]==0) //or name is single period
1999 ||( (dName[1]=='.')
2000 &&(dName[2]==0) //or name is two periods
2007 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
2008 return -ENOENT;
2011 } //ends fat_renameFile
2012 */ //End of commented out function (rename function for future implementation)
2013 //---------------------------------------------------------------------------
2014 int fat_writeFile(fat_driver* fatd, fat_dir* fatDir, int* updateClusterIndices, unsigned int filePos, unsigned char* buffer, unsigned int size) {
2015 int ret;
2016 int i,j;
2017 int chainSize;
2018 int nextChain;
2019 int startSector;
2020 unsigned int bufSize;
2021 int sectorSkip;
2022 int clusterSkip;
2023 int dataSkip;
2025 unsigned int bufferPos;
2026 unsigned int fileCluster;
2027 unsigned int clusterPos;
2028 unsigned int endPosFile;
2029 unsigned int endPosCluster;
2030 unsigned int lastCluster;
2032 int clusterChainStart;
2034 mass_dev* mass_device = fatd->dev;
2036 //check wether we have enough clusters allocated
2037 i = fatd->partBpb.clusterSize * fatd->partBpb.sectorSize; //the size (in bytes) of the one cluster
2038 j = fatDir->size / i;
2039 if (fatDir->size % i) {
2040 j++;
2042 if (j == 0) j = 1; //the file have allways at least one cluster allocated
2044 endPosCluster = j * i;
2045 endPosFile = filePos + size;
2047 *updateClusterIndices = 0;
2049 //allocate additional cluster(s)
2050 if (endPosFile > endPosCluster) {
2051 ret = endPosFile - endPosCluster; //additional space needed in bytes
2052 j = ret / i; //additional space needed (given in number of clusters)
2053 if (ret % i) {
2054 j++;
2056 lastCluster = fatDir->lastCluster;
2057 XPRINTF("USBHDFSD: I: writeFile: last cluster= %d \n", lastCluster);
2059 if (lastCluster == 0) return -ENOSPC; // no more free clusters or data invalid
2060 for (i = 0; i < j; i++) {
2061 lastCluster = fat_getFreeCluster(fatd, lastCluster);
2062 if (lastCluster == 0) return -ENOSPC; // no more free clusters
2064 fatDir->lastCluster = lastCluster;
2065 *updateClusterIndices = j;
2066 fat_invalidateLastChainResult(fatd); //prevent to misuse current (now deleted) fatd->cbuf
2068 XPRINTF("USBHDFSD: I: writeFile: new clusters allocated = %d new lastCluster=%d \n", j, lastCluster);
2070 XPRINTF("USBHDFSD: I: write file: filePos=%d dataSize=%d \n", filePos, size);
2073 fat_getClusterAtFilePos(fatd, fatDir, filePos, &fileCluster, &clusterPos);
2074 sectorSkip = (filePos - clusterPos) / fatd->partBpb.sectorSize;
2075 clusterSkip = sectorSkip / fatd->partBpb.clusterSize;
2076 sectorSkip %= fatd->partBpb.clusterSize;
2077 dataSkip = filePos % fatd->partBpb.sectorSize;
2078 bufferPos = 0;
2081 XPRINTF("USBHDFSD: fileCluster = %i, clusterPos= %i clusterSkip=%i, sectorSkip=%i dataSkip=%i \n",
2082 fileCluster, clusterPos, clusterSkip, sectorSkip, dataSkip);
2084 if (fileCluster < 2) {
2085 return -EFAULT;
2088 bufSize = mass_device->sectorSize;
2089 nextChain = 1;
2090 clusterChainStart = 1;
2092 while (nextChain && size > 0 ) {
2093 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
2094 clusterChainStart = 0;
2095 if (chainSize >= MAX_DIR_CLUSTER) { //the chain is full, but more chain parts exist
2096 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
2097 }else { //chain fits in the chain buffer completely - no next chain needed
2098 nextChain = 0;
2100 while (clusterSkip >= MAX_DIR_CLUSTER) {
2101 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
2102 clusterChainStart = 0;
2103 if (chainSize >= MAX_DIR_CLUSTER) { //the chain is full, but more chain parts exist
2104 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
2105 }else { //chain fits in the chain buffer completely - no next chain needed
2106 nextChain = 0;
2108 clusterSkip -= MAX_DIR_CLUSTER;
2111 //process the cluster chain (fatd->cbuf) and skip leading clusters if needed
2112 for (i = 0 + clusterSkip; i < chainSize && size > 0; i++) {
2113 //read cluster and save cluster content
2114 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[i]);
2115 //process all sectors of the cluster (and skip leading sectors if needed)
2116 for (j = 0 + sectorSkip; j < fatd->partBpb.clusterSize && size > 0; j++) {
2117 unsigned char* sbuf = NULL; //sector buffer
2119 //TODO - do not read when writing to unallocated sectors
2120 ret = READ_SECTOR(fatd->dev, startSector + j, sbuf);
2121 if (ret < 0) {
2122 printf("USBHDFSD: Read sector failed ! sector=%i\n", startSector + j);
2123 return bufferPos; //return number of bytes already written
2126 //compute exact size of transfered bytes
2127 if (size < bufSize) {
2128 bufSize = size + dataSkip;
2130 if (bufSize > mass_device->sectorSize) {
2131 bufSize = mass_device->sectorSize;
2133 XPRINTF("USBHDFSD: memcopy dst=%i, src=%i, size=%i bufSize=%i \n", dataSkip, bufferPos,bufSize-dataSkip, bufSize);
2134 memcpy(sbuf + dataSkip, buffer+bufferPos, bufSize - dataSkip);
2135 ret = WRITE_SECTOR(fatd->dev, startSector + j);
2136 if (ret < 0) {
2137 printf("USBHDFSD: Write sector failed ! sector=%i\n", startSector + j);
2138 return bufferPos; //return number of bytes already written
2141 size-= (bufSize - dataSkip);
2142 bufferPos += (bufSize - dataSkip);
2143 dataSkip = 0;
2144 bufSize = mass_device->sectorSize;
2146 sectorSkip = 0;
2148 clusterSkip = 0;
2151 return bufferPos; //return number of bytes already written
2155 //---------------------------------------------------------------------------
2156 int fat_allocSector(fat_driver* fatd, unsigned int sector, unsigned char** buf) {
2157 int ret;
2158 mass_dev* mass_device = fatd->dev;
2159 unsigned char* sbuf = NULL; //sector buffer
2161 ret = ALLOC_SECTOR(fatd->dev, sector, sbuf);
2162 if (ret < 0) {
2163 printf("USBHDFSD: Alloc sector failed ! sector=%i\n", sector);
2164 return -1;
2166 *buf = sbuf;
2167 return mass_device->sectorSize;
2170 //---------------------------------------------------------------------------
2171 int fat_writeSector(fat_driver* fatd, unsigned int sector) {
2172 int ret;
2173 mass_dev* mass_device = fatd->dev;
2175 ret = WRITE_SECTOR(fatd->dev, sector);
2176 if (ret < 0) {
2177 printf("USBHDFSD: Write sector failed ! sector=%i\n", sector);
2178 return -1;
2180 return mass_device->sectorSize;
2183 //---------------------------------------------------------------------------
2184 int fat_flushSectors(fat_driver* fatd)
2186 FLUSH_SECTORS(fatd->dev);
2187 return(0);
2189 //---------------------------------------------------------------------------
2190 //End of file: fat_write.c
2191 //---------------------------------------------------------------------------