1 //---------------------------------------------------------------------------
2 //File name: fat_write.c
3 //---------------------------------------------------------------------------
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 //---------------------------------------------------------------------------
27 #include "usbhd_common.h"
28 #include "fat_driver.h"
31 #include "mass_stor.h"
33 //#define DEBUG //comment out this line when not debugging
35 #include "mass_debug.h"
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
) {
55 size
= endIndex
-startIndex
;
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
) {
84 unsigned int clusterValue
;
85 unsigned char xbuf
[4];
87 unsigned char* sbuf
= NULL
; //sector buffer
89 oldClStackIndex
= fatd
->clStackIndex
;
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
;
100 if ((recordOffset
% fatd
->partBpb
.sectorSize
) == (fatd
->partBpb
.sectorSize
- 1)) {
103 if (lastFatSector
!= fatSector
|| sectorSpan
) {
104 ret
= READ_SECTOR(fatd
->dev
, fatd
->partBpb
.partStart
+ fatd
->partBpb
.resSectors
+ fatSector
, sbuf
);
106 printf("USBHDFSD: Read fat12 sector failed! sector=%i! \n", fatd
->partBpb
.partStart
+ fatd
->partBpb
.resSectors
+ fatSector
);
109 lastFatSector
= fatSector
;
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
);
116 printf("USBHDFSD: Read fat12 sector failed sector=%i! \n", fatd
->partBpb
.partStart
+ fatd
->partBpb
.resSectors
+ fatSector
+ 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
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
) {
153 unsigned int indexCount
;
154 unsigned int fatStartSector
;
155 unsigned int cluster
;
156 unsigned int clusterValue
;
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
);
176 printf("USBHDFSD: Read fat32 sector failed! sector=%i! \n", fatStartSector
+ i
);
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
++;
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
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
) {
207 unsigned int indexCount
;
208 unsigned int fatStartSector
;
209 unsigned int cluster
;
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
);
231 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatStartSector
+ i
);
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
++;
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
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
);
270 //---------------------------------------------------------------------------
272 set sinlge cluster record (FAT12)into buffer
282 void fat_setClusterRecord12(unsigned char* buf
, unsigned int cluster
, int type
) {
285 buf
[0] = (buf
[0] & 0x0F) + ((cluster
& 0x0F)<<4) ;
286 buf
[1] = (cluster
& 0xFF0) >> 4;
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
) {
297 buf
[0] = (buf
[0] & 0x0F) + ((cluster
& 0x0F)<<4);
299 buf
[0] = (cluster
& 0xFF);
303 //---------------------------------------------------------------------------
304 void fat_setClusterRecord12part2(unsigned char* buf
, unsigned int cluster
, int type
) {
306 buf
[0] = (cluster
& 0xFF0) >> 4;
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
)
323 unsigned int fatSector
;
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) {
339 recordType
= currentCluster
% 2;
341 ret
= READ_SECTOR(fatd
->dev
, fatSector
, sbuf
);
343 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector
);
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
);
350 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector
);
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
);
359 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector
);
362 //read next sector from the fat
364 ret
= READ_SECTOR(fatd
->dev
, fatSector
, sbuf
);
366 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector
);
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
);
374 printf("USBHDFSD: Write fat12 sector failed! sector=%i! \n", fatSector
);
382 //---------------------------------------------------------------------------
384 save value at the cluster record in FAT 32
386 int fat_saveClusterRecord16(fat_driver
* fatd
, unsigned int currentCluster
, unsigned int value
) {
391 unsigned int fatSector
;
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
);
406 printf("USBHDFSD: Read fat16 sector failed! sector=%i! \n", fatSector
);
409 i
= currentCluster
% indexCount
;
411 sbuf
[i
++] = value
& 0xFF;
412 sbuf
[i
] = ((value
& 0xFF00) >> 8);
413 ret
= WRITE_SECTOR(fatd
->dev
, fatSector
);
415 printf("USBHDFSD: Write fat16 sector failed! sector=%i! \n", fatSector
);
422 //---------------------------------------------------------------------------
424 save value at the cluster record in FAT 16
426 int fat_saveClusterRecord32(fat_driver
* fatd
, unsigned int currentCluster
, unsigned int value
) {
431 unsigned int fatSector
;
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
);
446 printf("USBHDFSD: Read fat32 sector failed! sector=%i! \n", fatSector
);
449 i
= currentCluster
% indexCount
;
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
);
458 printf("USBHDFSD: Write fat32 sector failed! sector=%i! \n", fatSector
);
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!
479 +-----+-----+-----+-----+
480 value + 10 | EOF | 0 | 0 |
481 +-----+-----+-----+-----+
484 currentcluster = 10, endcluster = 12
485 updated FAT (after the function ends):
488 +-----+-----+-----+-----+
489 value + 10 | 12 | 0 | EOF |
490 +-----+-----+-----+-----+
493 //---------------------------------------------------------------------------
494 int fat_appendClusterChain(fat_driver
* fatd
, unsigned int currentCluster
, unsigned int endCluster
) {
497 switch (fatd
->partBpb
.fatType
) {
499 ret
= fat_saveClusterRecord12(fatd
, currentCluster
, endCluster
);
500 if (ret
< 0) return ret
;
501 ret
= fat_saveClusterRecord12(fatd
, endCluster
, 0xFFF);
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);
512 ret
= fat_saveClusterRecord32(fatd
, currentCluster
, endCluster
);
513 if (ret
< 0) return ret
;
514 ret
= fat_saveClusterRecord32(fatd
, endCluster
, 0xFFFFFFF);
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);
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
);
546 //---------------------------------------------------------------------------
548 delete cluster chain starting at cluster
550 int fat_deleteClusterChain(fat_driver
* fatd
, unsigned int cluster
) {
560 XPRINTF("USBHDFSD: I: delete cluster chain starting at cluster=%d\n", cluster
);
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);
575 //the cluster chain continues
576 if (size
== MAX_DIR_CLUSTER
) {
577 cluster
= fatd
->cbuf
[end
];
579 //no more cluster entries - delete the last cluster entry
580 ret
= fat_modifyClusterChain(fatd
, fatd
->cbuf
[end
], 0);
586 fat_invalidateLastChainResult(fatd
); //prevent to misuse current (now deleted) fatd->cbuf
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
) {
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;
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) {
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
) {
644 if (len
% 13 > 0) result
++;
648 //---------------------------------------------------------------------------
650 compute checksum of the short filename
652 unsigned char computeNameChecksum(const unsigned char* sname
) {
653 unsigned char result
;
657 for (i
= 0; i
< 11; i
++) {
658 result
= (0x80 * (0x01 & result
)) + (result
>> 1); //ROR 1
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
){
670 unsigned char name
[26]; //unicode name buffer = 13 characters per 2 bytes
673 nameStart
= 13 * (part
- 1);
674 j
= nameSize
- nameStart
;
679 //fake unicode conversion
680 for (i
= 0; i
< j
; i
++) {
681 name
[i
*2] = lname
[nameStart
+ i
];
685 //rest of the name is zero terminated and padded with 0xFF
686 for (i
= j
; i
< 13; i
++) {
696 dlfn
->entrySeq
= 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];
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];
728 //ps2 specific routine to get time and date
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);
742 hour
=(((tmp
<<2)+tmp
)<<1)+(cdtime
.hour
&0x0F);
743 //hour= (hour + 4 + 12) % 24; // TEMP FIX (need to deal with timezones?)
746 day
=(((tmp
<<2)+tmp
)<<1)+(cdtime
.day
&0x0F);
749 month
=(((tmp
<<2)+tmp
)<<1)+(cdtime
.month
&0x0F);
752 year
=(((tmp
<<2)+tmp
)<<1)+(cdtime
.year
&0xF)+2000;
754 year
= 2005; month
= 1; day
= 6;
755 hour
= 14; minute
= 12; sec
= 10;
759 if (dsfn
== NULL
|| mode
== 0) {
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
) {
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];
804 dsfn
->attr
= FAT_ATTR_DIRECTORY
;
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
) {
836 if( (lname
[0] == '.')
838 ||( (lname
[1] == '.')
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
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
859 //XPRINTF("USBHDFSD: fit1=%d j=%d\n", fit, j);
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) {
871 //XPRINTF("USBHDFSD: fit2=%d\n", fit);
873 //find the last dot "." - filename extension
874 size
= strlen((const char*)lname
);
877 for (i
= size
; i
> 0 && lname
[i
] !='.'; i
--);
878 if (lname
[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
++;
886 //no dot detected in the long filename
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
894 XPRINTF("USBHDFSD: Short name is loseles!\n");
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
] = '_';
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
) {
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
931 //---------------------------------------------------------------------------
933 get the sequence number from existing direntry name
935 int getShortNameSequence(unsigned char* name
, unsigned char* ext
, unsigned char* sname
) {
938 unsigned char buf
[8];
940 //at first: compare extensions
941 //if extensions differ then filenames are diffrerent and seq is 0
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
) {
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
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
);
1000 buf
= sname
+ 7 - j
;
1003 for (i
= 0; i
< j
; i
++) buf
[i
] = number
[i
];
1008 //---------------------------------------------------------------------------
1010 find space where to put the direntry
1012 int getDirentryStoreOffset(fat_driver
* fatd
, int entryCount
, int direntrySize
) {
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)
1032 //search the entries for entry types
1033 for (i
= 0; i
< entryCount
&& cont
; i
++) {
1036 id
= fatd
->dir_used_mask
[mask_ix
] & (1<<mask_sh
);
1037 if (id
== 0) { //empty entry
1038 if (slotStart
>= 0) {
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) {
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) {
1076 if (looseIndex
>=0) {
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
);
1084 return entryCount
- 1;
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
;
1111 unsigned int startSector
;
1112 unsigned int theSector
;
1115 unsigned int dirPos
;
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);
1124 //clear name strings
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
);
1147 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector
);
1150 XPRINTF("USBHDFSD: read sector ok, scanning sector for direntries...\n");
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
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
;
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
;
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));
1183 //clear name strings
1186 }//ends "if(!(dir.attr & FAT_ATTR_VOLUME_LABEL))"
1187 else { //dlanor: Volume label
1192 fatd
->dir_used_mask
[mask_ix
] |= (1<<mask_sh
);
1193 fatd
->deSec
[fatd
->deIdx
] = theSector
;
1194 fatd
->deOfs
[fatd
->deIdx
] = dirPos
;
1201 dirPos
+= sizeof(fat_direntry
);
1205 //indicate inconsistency
1206 if (j
>= DIR_MASK_SIZE
) {
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
)
1228 unsigned int startSector
;
1231 int entriesPerSector
;
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
) {
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) {
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
) {
1296 unsigned int startSector
;
1298 //we do not mess with root directory
1299 if (dirCluster
< 2) {
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
);
1314 printf("USBHDFSD: read directory sector failed ! sector=%i\n", startSector
+ i
);
1317 memset(sbuf
, 0, fatd
->partBpb
.sectorSize
); //clean the sector
1319 fat_direntry_sfn
* dsfn
= (fat_direntry_sfn
*) sbuf
;
1320 unsigned char name
[11];
1321 for (j
= 0; j
< 11; j
++) name
[j
] = 32;
1323 setSfnEntry(name
, 1, dsfn
+ 0, dirCluster
);
1325 setSfnEntry(name
, 1, dsfn
+ 1, parentDirCluster
);
1327 ret
= WRITE_SECTOR(fatd
->dev
, startSector
+ i
);
1329 printf("USBHDFSD: write directory sector failed ! sector=%i\n", startSector
+ i
);
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
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
) {
1362 unsigned int startSector
;
1363 unsigned int theSector
;
1366 unsigned int dirPos
;
1369 mass_dev
* mass_device
= fatd
->dev
;
1370 int part
= entrySize
- 1;
1372 unsigned char chsum
;
1374 chsum
= computeNameChecksum(sname
);
1375 nameSize
= strlen(lname
);
1378 //clear name strings
1379 entryEndIndex
= entryIndex
+ entrySize
;
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
);
1399 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector
);
1402 XPRINTF("USBHDFSD: read sector ok, scanning sector for direntries...\n");
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
);
1410 setSfnEntry(sname
, directory
, &dir_entry
->sfn
, cluster
);
1412 setLfnEntry(lname
, nameSize
, chsum
, &dir_entry
->lfn
, part
, entrySize
- 1);
1416 if (j
== entryEndIndex
-1) {
1417 *retSector
= theSector
;
1418 *retOffset
= dirPos
;
1422 dirPos
+= sizeof(fat_direntry
);
1425 //store modified sector
1427 ret
= WRITE_SECTOR(fatd
->dev
, theSector
);
1429 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector
);
1433 if (j
>= entryEndIndex
) {
1434 cont
= 0; //do not continue
1440 //---------------------------------------------------------------------------
1442 - create/convert long name to short name
1443 - analyse directory space
1444 - enlarge directory space
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
) {
1457 unsigned char sname
[12]; //short name 8+3 + terminator
1458 unsigned int newCluster
;
1460 int compressShortName
;
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 // ------------+-----
1472 // ------------------
1473 // ID : 0 - entry is empty or deleted
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).
1496 //create short name from long name
1497 ret
= createShortNameMask(lname
,sname
);
1499 XPRINTF("USBHDFSD: E: short name invalid!\n");
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
);
1509 XPRINTF("USBHDFSD: E: direntry data invalid!\n");
1512 //ret 0 means that exact filename/directory already exist
1517 //exact filename not exist and we want to report it
1518 if (escapeNotExist
) {
1523 if (ret
> DIR_MASK_SIZE
) {
1524 XPRINTF("USBHDFSD: W: Direntry count is larger than number of records!\n");
1525 ret
= DIR_MASK_SIZE
;
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
);
1551 //get new cluster for file/directory
1552 newCluster
= fat_getFreeCluster(fatd
, 0);
1553 if (newCluster
== 0) {
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
);
1565 //create empty directory structure
1567 ret
= createDirectorySpace(fatd
, newCluster
, *startCluster
);
1568 XPRINTF("USBHDFSD: I: create directory space ret=%d\n", ret
);
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
1588 int checkDirspaceEmpty(fat_driver
* fatd
, unsigned int startCluster
) {
1591 unsigned char sname
[12]; //short name 8+3 + terminator
1594 unsigned int retSector
;
1597 XPRINTF("USBHDFSD: I: checkDirspaceEmpty directory cluster=%d \n", startCluster
);
1598 if (startCluster
< 2) { // do not check root directory!
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
;
1612 //first two records should be '.' & '..', which don't count as real content
1613 if((fatd
->dir_used_mask
[0] & 0xFC) != 0)
1615 for (i
=1; i
< (entryCount
/8); i
++) {
1616 if(fatd
->dir_used_mask
[i
] != 0) {
1618 XPRINTF("USBHDFSD: I: directory not empty!\n");
1622 XPRINTF("USBHDFSD: I: directory is empty.\n");
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
) {
1638 unsigned char sname
[12]; //short name 8+3 + terminator
1639 unsigned int dirCluster
;
1640 unsigned int theSector
;
1641 unsigned int sfnSector
;
1643 unsigned char* sbuf
= NULL
; //sector buffer ????
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
);
1655 XPRINTF("USBHDFSD: E: direntry not found!\n");
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.
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
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
);
1677 XPRINTF("USBHDFSD: E: direntry not found!\n");
1682 //now mark direntries as deleted
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
);
1689 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector
);
1693 theSector
= fatd
->deSec
[i
];
1694 ret
= READ_SECTOR(fatd
->dev
, theSector
, sbuf
);
1696 printf("USBHDFSD: read directory sector failed ! sector=%i\n", theSector
);
1700 sbuf
[fatd
->deOfs
[i
]] = 0xE5; //delete marker
1702 if (theSector
> 0) {
1703 ret
= WRITE_SECTOR(fatd
->dev
, theSector
);
1705 printf("USBHDFSD: write directory sector failed ! sector=%i\n", theSector
);
1710 //now delete whole cluster chain starting at the file's first cluster
1711 ret
= fat_deleteClusterChain(fatd
, *startCluster
);
1713 XPRINTF("USBHDFSD: E: delete cluster chain failed!\n");
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
) {
1731 fat_direntry_sfn
* dsfn
;
1732 unsigned char* sbuf
= NULL
; //sector buffer
1734 if (cluster
== 0 || sfnSector
== 0) {
1739 //now delete whole cluster chain starting at the file's first cluster
1740 ret
= fat_deleteClusterChain(fatd
, cluster
);
1742 XPRINTF("USBHDFSD: E: delete cluster chain failed!\n");
1747 ret
= fat_createClusterChain(fatd
, cluster
);
1749 XPRINTF("USBHDFSD: E: truncate cluster chain failed!\n");
1753 ret
= READ_SECTOR(fatd
->dev
, sfnSector
, sbuf
);
1755 printf("USBHDFSD: read direntry sector failed ! sector=%i\n", sfnSector
);
1758 dsfn
= (fat_direntry_sfn
*) (sbuf
+ sfnOffset
);
1764 ret
= WRITE_SECTOR(fatd
->dev
, sfnSector
);
1766 printf("USBHDFSD: write directory sector failed ! sector=%i\n", sfnSector
);
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
) {
1783 fat_direntry_sfn
* dsfn
;
1784 unsigned char* sbuf
= NULL
; //sector buffer
1786 if (sfnSector
== 0) {
1791 ret
= READ_SECTOR(fatd
->dev
, sfnSector
, sbuf
);
1793 printf("USBHDFSD: read direntry sector failed ! sector=%i\n", sfnSector
);
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
);
1806 printf("USBHDFSD: write directory sector failed ! sector=%i\n", sfnSector
);
1809 XPRINTF("USBHDFSD: I: sfn updated, file size=%d \n", size
);
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
) {
1829 unsigned int startCluster
;
1830 unsigned int directoryCluster
;
1831 unsigned char path
[FAT_MAX_PATH
];
1832 unsigned char lname
[FAT_MAX_NAME
];
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
1839 &&( (lname
[1]==0) //or name is single period
1841 &&(lname
[2]==0) //or name is two periods
1848 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
1852 XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fat_createFile\n");
1853 //get start cluster of the last sub-directory of the path
1855 ret
= fat_getFileStartCluster(fatd
, (const char*)path
, &startCluster
, &fatdir
);
1857 XPRINTF("USBHDFSD: E: directory not found! \n");
1861 if (!(fatdir
.attr
& FAT_ATTR_DIRECTORY
)) {
1862 XPRINTF("USBHDFSD: E: directory not found! \n");
1866 XPRINTF("USBHDFSD: directory=%s name=%s cluster=%d \n", path
, lname
, startCluster
);
1868 if (fatdir
.attr
& FAT_ATTR_READONLY
)
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
);
1876 XPRINTF("USBHDFSD: E: modifyDirSpace failed!\n");
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
);
1902 //---------------------------------------------------------------------------
1903 int fat_deleteFile(fat_driver
* fatd
, const unsigned char* fname
, char directory
) {
1905 unsigned int startCluster
;
1906 unsigned int directoryCluster
;
1907 unsigned char path
[FAT_MAX_PATH
];
1908 unsigned char lname
[FAT_MAX_NAME
];
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
1915 &&( (lname
[1]==0) //or name is single period
1917 &&(lname
[2]==0) //or name is two periods
1924 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
1928 XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fat_deleteFile\n");
1929 //get start cluster of the last sub-directory of the path
1931 ret
= fat_getFileStartCluster(fatd
, (const char*)path
, &startCluster
, &fatdir
);
1933 XPRINTF("USBHDFSD: E: directory not found! \n");
1937 if (!(fatdir
.attr
& FAT_ATTR_DIRECTORY
)) {
1938 XPRINTF("USBHDFSD: E: directory not found! \n");
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");
1949 //delete direntries and modify fat
1950 directoryCluster
= startCluster
;
1951 ret
= fat_clearDirSpace(fatd
, lname
, directory
, &startCluster
);
1953 XPRINTF("USBHDFSD: E: cleanDirSpace failed!\n");
1956 if (startCluster
!= directoryCluster
) {
1957 XPRINTF("USBHDFSD: I: file/dir removed from cluster=%d\n", startCluster
);
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) {
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
1982 &&( (sName[1]==0) //or name is single period
1984 &&(sName[2]==0) //or name is two periods
1991 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
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
1998 &&( (dName[1]==0) //or name is single period
2000 &&(dName[2]==0) //or name is two periods
2007 XPRINTF("USBHDFSD: E: file name not exist or not valid!");
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
) {
2020 unsigned int bufSize
;
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
) {
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)
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
;
2081 XPRINTF("USBHDFSD: fileCluster = %i, clusterPos= %i clusterSkip=%i, sectorSkip=%i dataSkip=%i \n",
2082 fileCluster
, clusterPos
, clusterSkip
, sectorSkip
, dataSkip
);
2084 if (fileCluster
< 2) {
2088 bufSize
= mass_device
->sectorSize
;
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
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
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
);
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
);
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
);
2144 bufSize
= mass_device
->sectorSize
;
2151 return bufferPos
; //return number of bytes already written
2155 //---------------------------------------------------------------------------
2156 int fat_allocSector(fat_driver
* fatd
, unsigned int sector
, unsigned char** buf
) {
2158 mass_dev
* mass_device
= fatd
->dev
;
2159 unsigned char* sbuf
= NULL
; //sector buffer
2161 ret
= ALLOC_SECTOR(fatd
->dev
, sector
, sbuf
);
2163 printf("USBHDFSD: Alloc sector failed ! sector=%i\n", sector
);
2167 return mass_device
->sectorSize
;
2170 //---------------------------------------------------------------------------
2171 int fat_writeSector(fat_driver
* fatd
, unsigned int sector
) {
2173 mass_dev
* mass_device
= fatd
->dev
;
2175 ret
= WRITE_SECTOR(fatd
->dev
, sector
);
2177 printf("USBHDFSD: Write sector failed ! sector=%i\n", sector
);
2180 return mass_device
->sectorSize
;
2183 //---------------------------------------------------------------------------
2184 int fat_flushSectors(fat_driver
* fatd
)
2186 FLUSH_SECTORS(fatd
->dev
);
2189 //---------------------------------------------------------------------------
2190 //End of file: fat_write.c
2191 //---------------------------------------------------------------------------