PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
fat_write.c
1//---------------------------------------------------------------------------
2// File name: fat_write.c
3//---------------------------------------------------------------------------
4/*
5 * fat_driver.c - USB Mass storage driver for PS2
6 *
7 * (C) 2005, Marek Olejnik (ole00@post.cz)
8 *
9 * FAT filesystem layer - write functions
10 *
11 * See the file LICENSE included with this distribution for licensing terms.
12 */
13//---------------------------------------------------------------------------
14#include <stdio.h>
15#include <errno.h>
16
17#ifdef WIN32
18#include <memory.h>
19#include <string.h>
20#include <stdlib.h>
21#else
22#include <cdvdman.h>
23#include <sysclib.h>
24#endif
25
26#ifdef BUILDING_USBHDFSD
27#include <usbhdfsd.h>
28#endif /* BUILDING_USBHDFSD */
29#ifdef BUILDING_IEEE1394_DISK
30#include <usbhdfsd-common.h>
31#endif /* BUILDING_IEEE1394_DISK */
32#include "usbhd_common.h"
33#include "fat_driver.h"
34#include "fat.h"
35#include "scache.h"
36#ifdef BUILDING_USBHDFSD
37#include "mass_stor.h"
38#endif /* BUILDING_USBHDFSD */
39#ifdef BUILDING_IEEE1394_DISK
40#include "sbp2_disk.h"
41#endif /* BUILDING_IEEE1394_DISK */
42
43// #define DEBUG //comment out this line when not debugging
44
45#include "mass_debug.h"
46
47#define DATE_CREATE 1
48#define DATE_MODIFY 2
49
50#define READ_SECTOR(d, a, b) scache_readSector((d)->cache, (a), (void **)&b)
51#define ALLOC_SECTOR(d, a, b) scache_readSector((d)->cache, (a), (void **)&b) // Cannot allocate a block as the cluster might not necessarily be aligned with the cache block; may result in corruption of the adjacent cluster.
52#define WRITE_SECTOR(d, a) scache_writeSector((d)->cache, (a))
53#define FLUSH_SECTORS(d) scache_flushSectors((d)->cache)
54#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
55#define DEV_ACCESSOR(d) (d)
56#else
57#define DEV_ACCESSOR(d) ((d)->dev)
58#endif
59#ifdef BUILDING_USBHDFSD
60#define WRITE_SECTORS_RAW(d, a, c, b) mass_stor_writeSector((d), a, b, c);
61#define INVALIDATE_SECTORS(d, s, c) scache_invalidate((d)->cache, s, c)
62#endif /* BUILDING_USBHDFSD */
63
64//---------------------------------------------------------------------------
65/*
66 reorder (swap) the cluster stack records
67*/
68static void swapClStack(fat_driver *fatd, int startIndex, int endIndex)
69{
70 int i;
71 int size;
72
73 size = endIndex - startIndex;
74 if (size < 2) {
75 return;
76 }
77
78 size /= 2;
79 for (i = 0; i < size; i++) {
80 int offset1, offset2;
81 unsigned int tmp;
82
83 offset1 = startIndex + i;
84 offset2 = endIndex - 1 - i;
85 tmp = fatd->clStack[offset1];
86 fatd->clStack[offset1] = fatd->clStack[offset2];
87 fatd->clStack[offset2] = tmp;
88 }
89}
90
91//---------------------------------------------------------------------------
92/*
93 scan FAT12 for free clusters and store them to the cluster stack
94*/
95
96static int fat_readEmptyClusters12(fat_driver *fatd)
97{
98 int ret;
99 int lastFatSector;
100 unsigned int cluster;
101 unsigned int clusterValue;
102 unsigned char xbuf[4];
103 int oldClStackIndex;
104 unsigned char *sbuf = NULL; // sector buffer
105
106 oldClStackIndex = fatd->clStackIndex;
107
108 lastFatSector = -1;
109 cluster = fatd->clStackLast;
110
111 while (fatd->clStackIndex < MAX_CLUSTER_STACK) {
112 int recordOffset;
113 int sectorSpan;
114 int fatSector;
115
116 recordOffset = (cluster * 3) / 2; // offset of the cluster record (in bytes) from the FAT start
117 fatSector = recordOffset / fatd->partBpb.sectorSize;
118 sectorSpan = 0;
119 if ((recordOffset % fatd->partBpb.sectorSize) == (fatd->partBpb.sectorSize - 1)) {
120 sectorSpan = 1;
121 }
122 if (lastFatSector != fatSector || sectorSpan) {
123 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector, sbuf);
124 if (ret < 0) {
125 XPRINTF("Read fat12 sector failed! sector=%u! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector);
126 return -EIO;
127 }
128 lastFatSector = fatSector;
129
130 if (sectorSpan) {
131 xbuf[0] = sbuf[fatd->partBpb.sectorSize - 2];
132 xbuf[1] = sbuf[fatd->partBpb.sectorSize - 1];
133 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1, sbuf);
134 if (ret < 0) {
135 XPRINTF("Read fat12 sector failed sector=%u! \n", fatd->partBpb.partStart + fatd->partBpb.resSectors + fatSector + 1);
136 return -EIO;
137 }
138 xbuf[2] = sbuf[0];
139 xbuf[3] = sbuf[1];
140 }
141 }
142 if (sectorSpan) { // use xbuf as source buffer
143 clusterValue = fat_getClusterRecord12(xbuf + (recordOffset % fatd->partBpb.sectorSize) - (fatd->partBpb.sectorSize - 2), cluster % 2);
144 } else { // use sector buffer as source buffer
145 clusterValue = fat_getClusterRecord12(sbuf + (recordOffset % fatd->partBpb.sectorSize), cluster % 2);
146 }
147 if (clusterValue == 0) {
148 fatd->clStackLast = cluster;
149 fatd->clStack[fatd->clStackIndex] = cluster;
150 fatd->clStackIndex++;
151 }
152 cluster++; // read next cluster record in the sequence
153 }
154 // the stack operates as LIFO but we put in the clusters as FIFO
155 // we should reverse the cluster order - not necessary
156 // but it will retain the natural (increasing) order of
157 // the cluster chain
158 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
159 return fatd->clStackIndex;
160}
161
162
163//---------------------------------------------------------------------------
164/*
165 scan FAT32 for free clusters and store them to the cluster stack
166*/
167static int fat_readEmptyClusters32(fat_driver *fatd)
168{
169 unsigned int i, j;
170 unsigned int indexCount;
171 unsigned int fatStartSector;
172 unsigned int cluster;
173 unsigned int clusterValue;
174 int oldClStackIndex;
175 int sectorSkip;
176 int recordSkip;
177
178 oldClStackIndex = fatd->clStackIndex;
179
180 // indexCount = numer of cluster indices per sector
181 indexCount = fatd->partBpb.sectorSize / 4; // FAT16->2, FAT32->4
182 // skip areas we have already searched through
183 sectorSkip = fatd->clStackLast / indexCount;
184 recordSkip = fatd->clStackLast % indexCount;
185
186 fatStartSector = fatd->partBpb.partStart + fatd->partBpb.resSectors;
187
188 for (i = sectorSkip; i < fatd->partBpb.fatSize && fatd->clStackIndex < MAX_CLUSTER_STACK; i++) {
189 int ret;
190
191 unsigned char *sbuf = NULL; // sector buffer
192
193 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatStartSector + i, sbuf);
194 if (ret < 0) {
195 XPRINTF("Read fat32 sector failed! sector=%u! \n", fatStartSector + i);
196 return -EIO;
197 }
198 for (j = recordSkip; j < indexCount && fatd->clStackIndex < MAX_CLUSTER_STACK; j++) {
199 cluster = getUI32(sbuf + (j * 4));
200 if (cluster == 0) { // the cluster is free
201 clusterValue = (i * indexCount) + j;
202 if (clusterValue < 0xFFFFFF7) {
203 fatd->clStackLast = clusterValue;
204 fatd->clStack[fatd->clStackIndex] = clusterValue;
205 fatd->clStackIndex++;
206 }
207 }
208 }
209 recordSkip = 0;
210 }
211 // the stack operates as LIFO but we put in the clusters as FIFO
212 // we should reverse the cluster order - not necessary
213 // but it will retain the natural (increasing) order of
214 // the cluster chain
215 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
216 return fatd->clStackIndex;
217}
218
219//---------------------------------------------------------------------------
220/*
221 scan FAT16 for free clusters and store them to the cluster stack
222*/
223static int fat_readEmptyClusters16(fat_driver *fatd)
224{
225 unsigned int i, j;
226 unsigned int indexCount;
227 unsigned int fatStartSector;
228 unsigned int cluster;
229 int oldClStackIndex;
230 int sectorSkip;
231 int recordSkip;
232
233 oldClStackIndex = fatd->clStackIndex;
234 // XPRINTF("#### Read empty clusters16: clStackIndex=%d MAX=%d\n", clStackIndex, MAX_CLUSTER_STACK);
235
236 // indexCount = numer of cluster indices per sector
237 indexCount = fatd->partBpb.sectorSize / 2; // FAT16->2, FAT32->4
238
239 // skip areas we have already searched through
240 sectorSkip = fatd->clStackLast / indexCount;
241 recordSkip = fatd->clStackLast % indexCount;
242
243 fatStartSector = fatd->partBpb.partStart + fatd->partBpb.resSectors;
244
245 for (i = sectorSkip; i < fatd->partBpb.fatSize && fatd->clStackIndex < MAX_CLUSTER_STACK; i++) {
246 int ret;
247
248 unsigned char *sbuf = NULL; // sector buffer
249
250 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatStartSector + i, sbuf);
251 if (ret < 0) {
252 XPRINTF("Read fat16 sector failed! sector=%u! \n", fatStartSector + i);
253 return -EIO;
254 }
255 for (j = recordSkip; j < indexCount && fatd->clStackIndex < MAX_CLUSTER_STACK; j++) {
256 cluster = getUI16(sbuf + (j * 2));
257 if (cluster == 0) { // the cluster is free
258 fatd->clStackLast = (i * indexCount) + j;
259 fatd->clStack[fatd->clStackIndex] = fatd->clStackLast;
260 XPRINTF("%u ", fatd->clStack[fatd->clStackIndex]);
261 fatd->clStackIndex++;
262 }
263 }
264 recordSkip = 0;
265 }
266 XPRINTF("\n");
267 // the stack operates as LIFO but we put in the clusters as FIFO
268 // we should reverse the cluster order - not necessary
269 // but it will retain the natural (increasing) order of
270 // the cluster chain
271 swapClStack(fatd, oldClStackIndex, fatd->clStackIndex);
272 return fatd->clStackIndex;
273}
274
275//---------------------------------------------------------------------------
276/*
277 scan FAT for free clusters and store them to the cluster stack
278*/
279static int fat_readEmptyClusters(fat_driver *fatd)
280{
281 switch (fatd->partBpb.fatType) {
282 case FAT12:
283 return fat_readEmptyClusters12(fatd);
284 case FAT16:
285 return fat_readEmptyClusters16(fatd);
286 case FAT32:
287 return fat_readEmptyClusters32(fatd);
288 }
289
290 return (-1);
291}
292
293
294//---------------------------------------------------------------------------
295/*
296 set sinlge cluster record (FAT12)into buffer
297
298 0x321, 0xABC
299
300 byte0|byte1|byte2|
301 +--+--+--+--+--+--+
302 |2 |1 |C |3 |A |B |
303 +--+--+--+--+--+--+
304
305*/
306static void fat_setClusterRecord12(unsigned char *buf, unsigned int cluster, int type)
307{
308
309 if (type) { // type 1
310 buf[0] = (buf[0] & 0x0F) + ((cluster & 0x0F) << 4);
311 buf[1] = (cluster & 0xFF0) >> 4;
312 } else { // type 0
313 buf[0] = (cluster & 0xFF);
314 buf[1] = (buf[1] & 0xF0) + ((cluster & 0xF00) >> 8);
315 }
316}
317
318//---------------------------------------------------------------------------
319static void fat_setClusterRecord12part1(unsigned char *buf, unsigned int cluster, int type)
320{
321 if (type) { // type 1
322 buf[0] = (buf[0] & 0x0F) + ((cluster & 0x0F) << 4);
323 } else { // type 0
324 buf[0] = (cluster & 0xFF);
325 }
326}
327
328//---------------------------------------------------------------------------
329static void fat_setClusterRecord12part2(unsigned char *buf, unsigned int cluster, int type)
330{
331 if (type) { // type 1
332 buf[0] = (cluster & 0xFF0) >> 4;
333 } else { // type 0
334 buf[0] = (buf[0] & 0xF0) + ((cluster & 0xF00) >> 8);
335 }
336}
337
338//---------------------------------------------------------------------------
339/*
340 save value at the cluster record in FAT 12
341*/
342static int fat_saveClusterRecord12(fat_driver *fatd, unsigned int currentCluster, unsigned int value)
343{
344 int ret;
345 int recordOffset;
346 int fatNumber;
347
348 ret = -1;
349 // recordOffset is byte offset of the record from the start of the fat table
350 recordOffset = (currentCluster * 3) / 2;
351
352 // save both fat tables
353 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
354 int sectorSpan;
355 int recordType;
356 unsigned int fatSector;
357
358 unsigned char *sbuf = NULL; // sector buffer
359
360 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
361 fatSector += recordOffset / fatd->partBpb.sectorSize;
362 sectorSpan = fatd->partBpb.sectorSize - (recordOffset % fatd->partBpb.sectorSize);
363 if (sectorSpan > 1) {
364 sectorSpan = 0;
365 }
366 recordType = currentCluster % 2;
367
368 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatSector, sbuf);
369 if (ret < 0) {
370 XPRINTF("Read fat16 sector failed! sector=%u! \n", fatSector);
371 return -EIO;
372 }
373 if (!sectorSpan) { // not sector span - the record is copmact and fits in single sector
374 fat_setClusterRecord12(sbuf + (recordOffset % fatd->partBpb.sectorSize), value, recordType);
375 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), fatSector);
376 if (ret < 0) {
377 XPRINTF("Write fat12 sector failed! sector=%u! \n", fatSector);
378 return -EIO;
379 }
380 } else { // sector span - the record is broken in 2 pieces - each one on different sector
381 // modify one last byte of the sector buffer
382 fat_setClusterRecord12part1(sbuf + (recordOffset % fatd->partBpb.sectorSize), value, recordType);
383 // save current sector
384 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), fatSector);
385 if (ret < 0) {
386 XPRINTF("Write fat12 sector failed! sector=%u! \n", fatSector);
387 return -EIO;
388 }
389 // read next sector from the fat
390 fatSector++;
391 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatSector, sbuf);
392 if (ret < 0) {
393 XPRINTF("Read fat16 sector failed! sector=%u! \n", fatSector);
394 return -EIO;
395 }
396 // modify first byte of the sector buffer
397 fat_setClusterRecord12part2(sbuf, value, recordType);
398 // save current sector
399 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), fatSector);
400 if (ret < 0) {
401 XPRINTF("Write fat12 sector failed! sector=%u! \n", fatSector);
402 return -EIO;
403 }
404 }
405 } // end for
406 return ret;
407}
408
409//---------------------------------------------------------------------------
410/*
411 save value at the cluster record in FAT 32
412*/
413static int fat_saveClusterRecord16(fat_driver *fatd, unsigned int currentCluster, unsigned int value)
414{
415 int ret;
416 int indexCount;
417 int fatNumber;
418
419 ret = -1;
420 // indexCount is numer of cluster indices per sector
421 indexCount = fatd->partBpb.sectorSize / 2; // FAT16->2, FAT32->4
422
423 // save both fat tables
424 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
425 int i;
426 unsigned int fatSector;
427
428 unsigned char *sbuf = NULL; // sector buffer
429
430 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
431 fatSector += currentCluster / indexCount;
432
433 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatSector, sbuf);
434 if (ret < 0) {
435 XPRINTF("Read fat16 sector failed! sector=%u! \n", fatSector);
436 return -EIO;
437 }
438 i = currentCluster % indexCount;
439 i *= 2; // fat16
440 sbuf[i++] = value & 0xFF;
441 sbuf[i] = ((value & 0xFF00) >> 8);
442 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), fatSector);
443 if (ret < 0) {
444 XPRINTF("Write fat16 sector failed! sector=%u! \n", fatSector);
445 return -EIO;
446 }
447 }
448 return ret;
449}
450
451//---------------------------------------------------------------------------
452/*
453 save value at the cluster record in FAT 16
454*/
455static int fat_saveClusterRecord32(fat_driver *fatd, unsigned int currentCluster, unsigned int value)
456{
457 int ret;
458 int indexCount;
459 int fatNumber;
460
461 ret = -1;
462 // indexCount is numer of cluster indices per sector
463 indexCount = fatd->partBpb.sectorSize / 4; // FAT16->2, FAT32->4
464
465 // save both fat tables
466 for (fatNumber = 0; fatNumber < fatd->partBpb.fatCount; fatNumber++) {
467 int i;
468 unsigned int fatSector;
469
470 unsigned char *sbuf = NULL; // sector buffer
471
472 fatSector = fatd->partBpb.partStart + fatd->partBpb.resSectors + (fatNumber * fatd->partBpb.fatSize);
473 fatSector += currentCluster / indexCount;
474
475 ret = READ_SECTOR(DEV_ACCESSOR(fatd), fatSector, sbuf);
476 if (ret < 0) {
477 XPRINTF("Read fat32 sector failed! sector=%u! \n", fatSector);
478 return -EIO;
479 }
480 i = currentCluster % indexCount;
481 i *= 4; // fat32
482 sbuf[i++] = value & 0xFF;
483 sbuf[i++] = ((value & 0xFF00) >> 8);
484 sbuf[i++] = ((value & 0xFF0000) >> 16);
485 sbuf[i] = (sbuf[i] & 0xF0) + ((value >> 24) & 0x0F); // preserve the highest nibble intact
486
487 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), fatSector);
488 if (ret < 0) {
489 XPRINTF("Write fat32 sector failed! sector=%u! \n", fatSector);
490 return -EIO;
491 }
492 }
493 return ret;
494}
495
496
497//---------------------------------------------------------------------------
498/*
499 Append (and write) cluster chain to the FAT table.
500
501 currentCluster - current end cluster record.
502 endCluster - new end cluster record.
503
504 Note: there is no checking wether the currentCluster holds the EOF marker!
505
506 Example
507 current FAT:
508
509 index 09 10 11 12
510 +-----+-----+-----+-----+
511 value + 10 | EOF | 0 | 0 |
512 +-----+-----+-----+-----+
513
514
515 currentcluster = 10, endcluster = 12
516 updated FAT (after the function ends):
517
518 index 09 10 11 12
519 +-----+-----+-----+-----+
520 value + 10 | 12 | 0 | EOF |
521 +-----+-----+-----+-----+
522
523*/
524//---------------------------------------------------------------------------
525static int fat_appendClusterChain(fat_driver *fatd, unsigned int currentCluster, unsigned int endCluster)
526{
527 int ret;
528 ret = -1;
529 switch (fatd->partBpb.fatType) {
530 case FAT12:
531 ret = fat_saveClusterRecord12(fatd, currentCluster, endCluster);
532 if (ret < 0)
533 return ret;
534 ret = fat_saveClusterRecord12(fatd, endCluster, 0xFFF);
535 break;
536
537 case FAT16:
538 XPRINTF("I: appending cluster chain : current=%u end=%u \n", currentCluster, endCluster);
539 ret = fat_saveClusterRecord16(fatd, currentCluster, endCluster);
540 if (ret < 0)
541 return ret;
542 ret = fat_saveClusterRecord16(fatd, endCluster, 0xFFFF);
543 break;
544
545 case FAT32:
546 ret = fat_saveClusterRecord32(fatd, currentCluster, endCluster);
547 if (ret < 0)
548 return ret;
549 ret = fat_saveClusterRecord32(fatd, endCluster, 0xFFFFFFF);
550 break;
551 }
552 return ret;
553}
554
555//---------------------------------------------------------------------------
556/*
557 create new cluster chain (of size 1 cluster) at the cluster index
558*/
559static int fat_createClusterChain(fat_driver *fatd, unsigned int cluster)
560{
561 switch (fatd->partBpb.fatType) {
562 case FAT12:
563 return fat_saveClusterRecord12(fatd, cluster, 0xFFF);
564 case FAT16:
565 return fat_saveClusterRecord16(fatd, cluster, 0xFFFF);
566 case FAT32:
567 return fat_saveClusterRecord32(fatd, cluster, 0xFFFFFFF);
568 }
569 return -EFAULT;
570}
571
572//---------------------------------------------------------------------------
573/*
574 modify the cluster (in FAT table) at the cluster index
575*/
576static int fat_modifyClusterChain(fat_driver *fatd, unsigned int cluster, unsigned int value)
577{
578 switch (fatd->partBpb.fatType) {
579 case FAT12:
580 return fat_saveClusterRecord12(fatd, cluster, value);
581 case FAT16:
582 return fat_saveClusterRecord16(fatd, cluster, value);
583 case FAT32:
584 return fat_saveClusterRecord32(fatd, cluster, value);
585 }
586 return -EFAULT;
587}
588
589//---------------------------------------------------------------------------
590/*
591 delete cluster chain starting at cluster
592*/
593static int fat_deleteClusterChain(fat_driver *fatd, unsigned int cluster)
594{
595 int ret;
596 int cont;
597 int i;
598
599 if (cluster < 2) {
600 return -EFAULT;
601 }
602 XPRINTF("I: delete cluster chain starting at cluster=%u\n", cluster);
603
604 cont = 1;
605
606 while (cont) {
607 int size;
608 int end;
609
610 size = fat_getClusterChain(fatd, cluster, fatd->cbuf, MAX_DIR_CLUSTER, 1);
611
612 end = size - 1; // do not delete last cluster in the chain buffer
613
614 for (i = 0; i < end; i++) {
615 ret = fat_modifyClusterChain(fatd, fatd->cbuf[i], 0);
616 if (ret < 0) {
617 return ret;
618 }
619 }
620 // the cluster chain continues
621 if (size == MAX_DIR_CLUSTER) {
622 cluster = fatd->cbuf[end];
623 } else {
624 // no more cluster entries - delete the last cluster entry
625 ret = fat_modifyClusterChain(fatd, fatd->cbuf[end], 0);
626 if (ret < 0) {
627 return ret;
628 }
629 cont = 0;
630 }
631 fat_invalidateLastChainResult(fatd); // prevent to misuse current (now deleted) fatd->cbuf
632 }
633 return 1;
634}
635
636//---------------------------------------------------------------------------
637/*
638 Get single empty cluster from the clusterStack (cS is small cache of free clusters)
639 Passed currentCluster is updated in the FAT and the new returned cluster index is
640 appended at the end of fat chain!
641*/
642static unsigned int fat_getFreeCluster(fat_driver *fatd, unsigned int currentCluster)
643{
644
645 int ret;
646 unsigned int result;
647
648 // cluster stack is empty - find and fill the cS
649 if (fatd->clStackIndex <= 0) {
650 fatd->clStackIndex = 0;
651 ret = fat_readEmptyClusters(fatd);
652 if (ret <= 0)
653 return 0;
654 fatd->clStackIndex = ret;
655 }
656 // pop from cluster stack
657 fatd->clStackIndex--;
658 result = fatd->clStack[fatd->clStackIndex];
659 // append the cluster chain
660 if (currentCluster) {
661 ret = fat_appendClusterChain(fatd, currentCluster, result);
662 } else { // create new cluster chain
663 ret = fat_createClusterChain(fatd, result);
664 }
665 if (ret < 0)
666 return 0;
667 return result;
668}
669
670//---------------------------------------------------------------------------
671/*
672returns number of direntry positions that the name takes
673//dlanor: Note that this only includes the long_name entries
674*/
675static int getDirentrySize(const char *lname)
676{
677 int len;
678 int result;
679 len = strlen(lname);
680 result = len / 13;
681 if (len % 13 > 0)
682 result++;
683 return result;
684}
685
686//---------------------------------------------------------------------------
687/*
688compute checksum of the short filename
689*/
690static unsigned char computeNameChecksum(const char *sname)
691{
692 unsigned char result;
693 int i;
694
695 result = 0;
696 for (i = 0; i < 11; i++) {
697 result = (0x80 * (0x01 & result)) + (result >> 1); // ROR 1
698 result += sname[i];
699 }
700 return result;
701}
702
703//---------------------------------------------------------------------------
704/*
705 fill the LFN (long filename) direntry
706*/
707static void setLfnEntry(const char *lname, int nameSize, unsigned char chsum, fat_direntry_lfn *dlfn, int part, int maxPart)
708{
709 int i, j;
710 unsigned char name[26]; // unicode name buffer = 13 characters per 2 bytes
711 int nameStart;
712
713 nameStart = 13 * (part - 1);
714 j = nameSize - nameStart;
715 if (j > 13) {
716 j = 13;
717 }
718
719 // fake unicode conversion
720 for (i = 0; i < j; i++) {
721 name[i * 2] = (unsigned char)lname[nameStart + i];
722 name[i * 2 + 1] = 0;
723 }
724
725 // rest of the name is zero terminated and padded with 0xFF
726 for (i = j; i < 13; i++) {
727 if (i == j) {
728 name[i * 2] = 0;
729 name[i * 2 + 1] = 0;
730 } else {
731 name[i * 2] = 0xFF;
732 name[i * 2 + 1] = 0xFF;
733 }
734 }
735
736 dlfn->entrySeq = part;
737 if (maxPart == part)
738 dlfn->entrySeq |= 0x40;
739 dlfn->checksum = chsum;
740 // 1st part of the name
741 for (i = 0; i < 10; i++)
742 dlfn->name1[i] = name[i];
743 // 2nd part of the name
744 for (i = 0; i < 12; i++)
745 dlfn->name2[i] = name[i + 10];
746 // 3rd part of the name
747 for (i = 0; i < 4; i++)
748 dlfn->name3[i] = name[i + 22];
749 dlfn->rshv = 0x0f;
750 dlfn->reserved1 = 0;
751 dlfn->reserved2[0] = 0;
752 dlfn->reserved2[1] = 0;
753}
754
755//---------------------------------------------------------------------------
756/*
757 update the SFN (long filename) direntry - DATE and TIME
758*/
759static void setSfnDate(fat_direntry_sfn *dsfn, int mode)
760{
761 int year, month, day, hour, minute, sec;
762 unsigned char tmpClk[4];
763
764#ifdef WIN32
765 year = 0;
766 month = 0;
767 day = 0;
768 hour = 0;
769 minute = 0;
770 sec = 0;
771#else
772 // ps2 specific routine to get time and date
773 sceCdCLOCK cdtime;
774
775 if (sceCdReadClock(&cdtime) != 0 && cdtime.stat == 0) {
776 sec = btoi(cdtime.second);
777 minute = btoi(cdtime.minute);
778 hour = btoi(cdtime.hour);
779 day = btoi(cdtime.day);
780 month = btoi(cdtime.month & 0x7F); // Ignore century bit (when an old CDVDMAN is used).
781 year = btoi(cdtime.year) + 2000;
782 } else {
783 year = 2005;
784 month = 1;
785 day = 6;
786 hour = 14;
787 minute = 12;
788 sec = 10;
789 }
790#endif
791
792 if (dsfn == NULL || mode == 0) {
793 return;
794 }
795
796 tmpClk[0] = (sec / 2) & 0x1F; // seconds
797 tmpClk[0] += (minute & 0x07) << 5; // minute
798 tmpClk[1] = (minute & 0x38) >> 3; // minute
799 tmpClk[1] += (hour & 0x1F) << 3; // hour
800
801 tmpClk[2] = (day & 0x1F); // day
802 tmpClk[2] += (month & 0x07) << 5; // month
803 tmpClk[3] = (month & 0x08) >> 3; // month
804 tmpClk[3] += ((year - 1980) & 0x7F) << 1; // year
805
806 XPRINTF("year=%d, month=%d, day=%d h=%d m=%d s=%d \n", year, month, day, hour, minute, sec);
807 // set date & time of creation
808 if (mode & DATE_CREATE) {
809 dsfn->timeCreate[0] = tmpClk[0];
810 dsfn->timeCreate[1] = tmpClk[1];
811 dsfn->dateCreate[0] = tmpClk[2];
812 dsfn->dateCreate[1] = tmpClk[3];
813 dsfn->dateAccess[0] = tmpClk[2];
814 dsfn->dateAccess[1] = tmpClk[3];
815 }
816 // set date & time of modification
817 if (mode & DATE_MODIFY) {
818 dsfn->timeWrite[0] = tmpClk[0];
819 dsfn->timeWrite[1] = tmpClk[1];
820 dsfn->dateWrite[0] = tmpClk[2];
821 dsfn->dateWrite[1] = tmpClk[3];
822 }
823}
824
825//---------------------------------------------------------------------------
826/*
827 fill the SFN (short filename) direntry
828*/
829static void setSfnEntry(const char *shortName, char directory, fat_direntry_sfn *dsfn, unsigned int cluster)
830{
831 int i;
832
833 // name + ext
834 for (i = 0; i < 8; i++)
835 dsfn->name[i] = shortName[i];
836 for (i = 0; i < 3; i++)
837 dsfn->ext[i] = shortName[i + 8];
838
839 if (directory > 0) {
840 dsfn->attr = FAT_ATTR_DIRECTORY;
841 } else {
842 dsfn->attr = FAT_ATTR_ARCHIVE;
843 }
844 dsfn->reservedNT = 0;
845 dsfn->clusterH[0] = (cluster & 0xFF0000) >> 16;
846 dsfn->clusterH[1] = (cluster & 0xFF000000) >> 24;
847 dsfn->clusterL[0] = (cluster & 0x00FF);
848 dsfn->clusterL[1] = (cluster & 0xFF00) >> 8;
849
850 // size is zero - because we don't know the filesize yet
851 for (i = 0; i < 4; i++)
852 dsfn->size[i] = 0;
853
854 setSfnDate(dsfn, DATE_CREATE | DATE_MODIFY);
855}
856
857static void setSfnEntryFromOld(const char *shortName, fat_direntry_sfn *dsfn, const fat_direntry_sfn *orig_dsfn)
858{
859 int i;
860
861 memcpy(dsfn, orig_dsfn, sizeof(fat_direntry_sfn));
862
863 // name + ext
864 for (i = 0; i < 8; i++)
865 dsfn->name[i] = shortName[i];
866 for (i = 0; i < 3; i++)
867 dsfn->ext[i] = shortName[i + 8];
868}
869
870//---------------------------------------------------------------------------
871/*
872 Create short name by squeezing long name into the 8.3 name boundaries
873 lname - existing long name
874 sname - buffer where to store short name
875
876 returns: 0 if longname completely fits into the 8.3 boundaries
877 1 if long name have to be truncated (ie. INFORM~1.TXT)
878 <0 if invalid long name detected
879*/
880static int createShortNameMask(char *lname, char *sname)
881{
882 int i;
883 int size;
884 int j;
885 int fit;
886
887 if ((lname[0] == '.') && ((lname[1] == 0) || ((lname[1] == '.') && (lname[2] == 0)))) {
888 return -EINVAL;
889 }
890
891 fit = 0;
892 // clean short name by putting space
893 for (i = 0; i < 11; i++)
894 sname[i] = ' ';
895 XPRINTF("Clear short name ='%s'\n", sname);
896
897 // detect number of dots and space characters in the long name
898 j = 0;
899 for (i = 0; lname[i] != 0; i++) {
900 if (lname[i] == '.')
901 j++;
902 else if (lname[i] == ' ')
903 j += 2;
904 }
905 // long name contains no dot or one dot and no space char
906 if (j <= 1)
907 fit++;
908 // XPRINTF("fit1=%d j=%d\n", fit, j);
909
910 // store name
911 for (i = 0; lname[i] != 0 && lname[i] != '.' && i < 8; i++) {
912 sname[i] = toupper(lname[i]);
913 // short name must not contain spaces - replace space by underscore
914 if (sname[i] == ' ')
915 sname[i] = '_';
916 }
917 // check wether last char is '.' and the name is shorter than 8
918 if (lname[i] == '.' || lname[i] == 0) {
919 fit++;
920 }
921 // XPRINTF("fit2=%d\n", fit);
922
923 // find the last dot "." - filename extension
924 size = strlen(lname);
925 size--;
926
927 for (i = size; i > 0 && lname[i] != '.'; i--)
928 ;
929 if (lname[i] == '.') {
930 i++;
931 for (j = 0; lname[i] != 0 && j < 3; i++, j++) {
932 sname[j + 8] = toupper(lname[i]);
933 }
934 // no more than 3 characters of the extension
935 if (lname[i] == 0)
936 fit++;
937 } else {
938 // no dot detected in the long filename
939 fit++;
940 }
941 // XPRINTF("fit3=%d\n", fit);
942 // XPRINTF("Long name=%s Short name=%s \n", lname, sname);
943
944 // all 3 checks passed - the long name fits in the short name without restrictions
945 if (fit == 3) {
946 XPRINTF("Short name is loseles!\n");
947 return 0;
948 }
949
950 // one of the check failed - the short name have to be 'sequenced'
951 // do not allow spaces in the short name
952 for (i = 0; i < 8; i++) {
953 if (sname[i] == ' ')
954 sname[i] = '_';
955 }
956 return 1;
957}
958
959//---------------------------------------------------------------------------
960/*
961 separate path and filename
962 fname - the source (merged) string (input)
963 path - separated path (output)
964 name - separated filename (output)
965*/
966static int separatePathAndName(const char *fname, char *path, char *name)
967{
968 int path_len;
969 const char *sp, *np;
970
971 if (!(sp = strrchr(fname, '/'))) // if last path separator missing ?
972 np = fname; // name starts at start of fname string
973 else // else last path separator found
974 np = sp + 1; // name starts after separator
975 if (strlen(np) >= FAT_MAX_NAME) // if name is too long
976 return -ENAMETOOLONG; // return error code
977 strcpy(name, np); // copy name from correct part of fname string
978 if ((path_len = (np - fname)) >= FAT_MAX_PATH) // if path is too long
979 return -ENAMETOOLONG; // return error code
980 strncpy(path, fname, path_len); // copy path from start of fname string
981 path[path_len] = 0; // terminate path
982 return 1;
983}
984
985//---------------------------------------------------------------------------
986/*
987 get the sequence number from existing direntry name
988*/
989static int getShortNameSequence(const char *name, const char *ext, const char *sname)
990{
991 int i, j;
992 const char *tmp;
993 char buf[8];
994
995 // at first: compare extensions
996 // if extensions differ then filenames are diffrerent and seq is 0
997 tmp = sname + 8;
998 for (i = 0; i < 3; i++) {
999 if (ext[i] != tmp[i])
1000 return 0;
1001 }
1002
1003 // at second: find tilde '~' character (search backward from the end)
1004 for (i = 7; i > 0 && name[i] != '~'; i--)
1005 ;
1006
1007 if (i == 0)
1008 return 0; // tilde char was not found or is at first character
1009
1010 // now compare the names - up to '~' position
1011 // if names differ then filenames are different;
1012 for (j = 0; j < i; j++) {
1013 if (name[j] != sname[j])
1014 return 0;
1015 }
1016
1017 // if we get to this point we know that extension and name match
1018 // now get the sequence number behind the '~'
1019 for (j = i + 1; j < 8; j++)
1020 buf[j - i - 1] = name[j];
1021 buf[j - i - 1] = 0; // terminate
1022
1023 XPRINTF("found short name sequence number='%s' \n", buf);
1024 return strtol(buf, NULL, 10);
1025}
1026
1027//---------------------------------------------------------------------------
1028/*
1029 set the short name sequence number
1030*/
1031static int setShortNameSequence(fat_driver *fatd, char *sname)
1032{
1033 char number[8];
1034 char *buf;
1035 int i, j;
1036 int seq;
1037
1038 // dlanor: The code below was bugged in several ways, as it treated the high seq
1039 // values stored in long_name records as separate seqs, and also failed to accept
1040 // any valid seq value whose low part (stored in short_name record) was zero.
1041 // I'm now replacing this garbage with a bit-mask oriented scheme
1042
1043 seq = SEQ_MASK_SIZE;
1044 for (i = 0; (i < (SEQ_MASK_SIZE >> 3)); i++) { // for each mask byte
1045 unsigned char mask;
1046
1047 if ((mask = fatd->seq_mask[i]) != 0xFF) { // if mask byte has any bit free
1048 for (j = 0; j < 8; j++, mask >>= 1) { // for each bit in byte
1049 if ((mask & 1) == 0) { // if free bit found
1050 seq = (i << 3) + j; // set seq value
1051 break; // break bit loop
1052 } // ends "if free bit found"
1053 } // ends "for each bit in byte"
1054 break; // break byte loop
1055 } // ends "if mask byte has any bit free"
1056 } // ends "for each mask byte"
1057
1058 memset(number, 0, 8);
1059 sprintf(number, "%d", seq);
1060 j = strlen(number);
1061
1062 buf = sname + 7 - j;
1063 buf[0] = '~';
1064 buf++;
1065 for (i = 0; i < j; i++)
1066 buf[i] = number[i];
1067
1068 return 0;
1069}
1070
1071//---------------------------------------------------------------------------
1072/*
1073 find space where to put the direntry
1074*/
1075static int getDirentryStoreOffset(fat_driver *fatd, int entryCount, int direntrySize)
1076{
1077 int i;
1078 int tightIndex;
1079 int looseIndex;
1080 int cont;
1081 int id;
1082 int slotStart;
1083 int slotSize;
1084 int mask_ix, mask_sh;
1085
1086
1087 // we search for sequence of deleted or empty entries (cleared bits in dir_used_mask)
1088 // 1) search the tight slot (that fits completely. ex: size = 3, and slot space is 3 )
1089 // 2) search the suitable (loose) slot (ex: size = 3, slot space is 5)
1090
1091 slotStart = -1;
1092 slotSize = 0;
1093 tightIndex = -1;
1094 looseIndex = -1;
1095 cont = 1;
1096 // search the entries for entry types
1097 for (i = 0; i < entryCount && cont; i++) {
1098 mask_ix = i >> 3;
1099 mask_sh = i & 7;
1100 id = fatd->dir_used_mask[mask_ix] & (1 << mask_sh);
1101 if (id == 0) { // empty entry
1102 if (slotStart >= 0) {
1103 slotSize++;
1104 } else {
1105 slotStart = i;
1106 slotSize = 1;
1107 XPRINTF("*Start slot at index=%d ", slotStart);
1108 }
1109 } else { // occupied entry
1110 if (tightIndex < 0 && slotSize == direntrySize) {
1111 tightIndex = slotStart;
1112 XPRINTF("!Set tight index= %d\n", tightIndex);
1113 }
1114 if (looseIndex < 0 && slotSize > direntrySize) {
1115 looseIndex = slotStart + slotSize - direntrySize;
1116 XPRINTF("!Set loose index= %d\n", looseIndex);
1117 }
1118 if (tightIndex >= 0 && looseIndex >= 0) {
1119 cont = 0;
1120 }
1121 slotStart = -1;
1122 slotSize = 0;
1123 }
1124 }
1125 XPRINTF("\n");
1126
1127 // tight index - smaller fragmentation of space, the larger blocks
1128 // are left for larger filenames.
1129 // loose index - more fragmentation of direntry space, but the direntry
1130 // name has space for future enlargement (of the name).
1131 // i.e. no need to reposition the direntry and / or
1132 // to allocate additional fat cluster for direntry space.
1133
1134 // we prefere tight slot if available, othervise we use the loose slot.
1135 // if there are no tight and no loose slot then we position new direntry
1136 // at the end of current direntry space
1137 if (tightIndex >= 0) {
1138 return tightIndex;
1139 }
1140 if (looseIndex >= 0) {
1141 return looseIndex;
1142 }
1143 // last entry is (most likely) empty - and if so, use it
1144 mask_ix = (entryCount - 1) >> 3;
1145 mask_sh = (entryCount - 1) & 7;
1146 id = fatd->dir_used_mask[mask_ix] & (1 << mask_sh);
1147 if (id == 0) {
1148 return entryCount - 1;
1149 }
1150
1151 return entryCount;
1152}
1153
1154//---------------------------------------------------------------------------
1155/*
1156 scans current directory entries and fills the info records
1157
1158 lname - long filename (to test wether existing entry match the long name) (input)
1159 sname - short filename ( ditto ^^ ) (input)
1160 startCluster - valid start cluster of the directory or 0 if we scan the root directory (input), first cluster of dirent (output).
1161 directory - Entry type to check against. 0 = file, >0 = directory, <0 = ignore type.
1162
1163 if file/directory already exist (return code 0) then:
1164 retSector - contains sector number of the direntry (output)
1165 retOffset - contains byte offse of the SFN direntry from start of the sector (output)
1166 the reason is to speed up modification of the SFN (size of the file)
1167//dlanor: This function has been rewritten to use global bitmask arrays for output
1168*/
1169static int fat_fillDirentryInfo(fat_driver *fatd, const char *lname, const char *sname,
1170 char directory, unsigned int *startCluster,
1171 unsigned int *retSector, int *retOffset)
1172{
1174 int i, j;
1175 unsigned int startSector, dirSector;
1176 int cont;
1177 int seq;
1178 int mask_ix, mask_sh;
1179#ifdef DEBUG
1180#ifdef BUILDING_USBHDFSD
1181 mass_dev *mass_device = fatd->dev;
1182#endif /* BUILDING_USBHDFSD */
1183#ifdef BUILDING_IEEE1394_DISK
1184 struct SBP2Device *mass_device = fatd->dev;
1185#endif /* BUILDING_IEEE1394_DISK */
1186#endif
1187
1188 memset(fatd->dir_used_mask, 0, DIR_MASK_SIZE / 8);
1189 memset(fatd->seq_mask, 0, SEQ_MASK_SIZE / 8);
1190
1191 cont = 1;
1192 // clear name strings
1193 dir.sname[0] = 0;
1194 dir.name[0] = 0;
1195
1196 j = 0;
1197 if (directory > 0)
1198 directory = FAT_ATTR_DIRECTORY;
1199
1200 fat_getDirentrySectorData(fatd, startCluster, &startSector, &dirSector);
1201
1202 XPRINTF("dirCluster=%u startSector=%u (%u) dirSector=%u \n", *startCluster, startSector, startSector
1203#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
1204 * fatd->bd->sectorSize,
1205#else
1206 * mass_device->sectorSize,
1207#endif
1208 dirSector);
1209
1210 // go through first directory sector till the max number of directory sectors
1211 // or stop when no more direntries detected
1212 for (i = 0; (unsigned int)i < dirSector && cont; i++) {
1213 unsigned int theSector;
1214 int ret;
1215 unsigned int dirPos;
1216
1217 unsigned char *sbuf = NULL; // sector buffer
1218
1219 // At cluster borders, get correct sector from cluster chain buffer
1220 if ((*startCluster != 0) && (i % fatd->partBpb.clusterSize == 0)) {
1221 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)]) - i;
1222 }
1223 theSector = startSector + i;
1224 ret = READ_SECTOR(DEV_ACCESSOR(fatd), theSector, sbuf);
1225 if (ret < 0) {
1226 XPRINTF("read directory sector failed ! sector=%u\n", theSector);
1227 return -EIO;
1228 }
1229 XPRINTF("read sector ok, scanning sector for direntries...\n");
1230 dirPos = 0;
1231
1232 // go through start of the sector till the end of sector
1233 while (cont && (dirPos < fatd->partBpb.sectorSize) && (j < DIR_MASK_SIZE)) {
1234 fat_direntry *dir_entry = (fat_direntry *)(sbuf + dirPos);
1235 cont = fat_getDirentry(fatd->partBpb.fatType, dir_entry, &dir); // get single directory entry from sector buffer
1236 mask_ix = j >> 3;
1237 mask_sh = j & 7;
1238 switch (cont) {
1239 case 1: // short name
1240 fatd->dir_used_mask[mask_ix] |= (1 << mask_sh);
1241 if (!(dir.attr & FAT_ATTR_VOLUME_LABEL)) { // not volume label
1242 if ((strEqual(dir.sname, lname) == 0) || (strEqual(dir.name, lname) == 0)) {
1243 // file we want to create already exist - return the cluster of the file
1244 if ((directory >= 0) && ((dir.attr & FAT_ATTR_DIRECTORY) != directory)) {
1245 // found directory but requested is file (and vice veresa)
1246 if (directory)
1247 return -ENOTDIR;
1248 return -EISDIR;
1249 } // ends "if" clause for mismatched file/folder state
1250 XPRINTF("I: entry found! %s, %s = %s\n", dir.name, dir.sname, lname);
1251 *retSector = theSector;
1252 *retOffset = dirPos;
1253 *startCluster = dir.cluster;
1254 fatd->deSec[fatd->deIdx] = theSector;
1255 fatd->deOfs[fatd->deIdx] = dirPos;
1256 fatd->deIdx++;
1257 return 0;
1258 } // ends "if" clause for matching name
1259 seq = getShortNameSequence((char *)dir_entry->sfn.name, (char *)dir_entry->sfn.ext, sname);
1260 if (seq < SEQ_MASK_SIZE)
1261 fatd->seq_mask[seq >> 3] |= (1 << (seq & 7));
1262 fatd->deIdx = 0;
1263 // clear name strings
1264 dir.sname[0] = 0;
1265 dir.name[0] = 0;
1266 } // ends "if(!(dir.attr & FAT_ATTR_VOLUME_LABEL))"
1267 else { // dlanor: Volume label
1268 fatd->deIdx = 0;
1269 }
1270 break;
1271 case 2: // long name
1272 fatd->dir_used_mask[mask_ix] |= (1 << mask_sh);
1273 fatd->deSec[fatd->deIdx] = theSector;
1274 fatd->deOfs[fatd->deIdx] = dirPos;
1275 fatd->deIdx++;
1276 break;
1277 case 3: // empty
1278 fatd->deIdx = 0;
1279 break;
1280 } // ends "switch"
1281 dirPos += sizeof(fat_direntry);
1282 j++;
1283 }
1284 }
1285 // indicate inconsistency
1286 if (j >= DIR_MASK_SIZE) {
1287 j++;
1288 }
1289 return j;
1290}
1291
1292//---------------------------------------------------------------------------
1293/*
1294 check wether the new direntries (note: one file have at least 2 direntries for 1 SFN and 1..n LFN)
1295 fit into the current directory space.
1296 Enlarges the directory space if needed and possible (note: root dirspace can't be enlarged for fat12 and fat16)
1297
1298 startCluster - valid start cluster of dirpace or 0 for the root directory
1299 entryCount - number of direntries of the filename (at least 2)
1300 entryIndex - index where to store new direntries
1301 direntrySize - number of all direntries in the directory
1302*/
1303
1304static int enlargeDirentryClusterSpace(fat_driver *fatd, unsigned int startCluster, int entryCount, int entryIndex, int direntrySize)
1305{
1306 unsigned int startSector, dirSector;
1307 int i;
1308 int maxSector;
1309 int entriesPerSector;
1310 int chainSize;
1311 unsigned int currentCluster;
1312 unsigned int newCluster;
1313
1314 i = entryIndex + direntrySize;
1315 XPRINTF("cur=%d ecount=%d \n", i, entryCount);
1316 // we don't need to enlarge directory cluster space
1317 if (i <= entryCount)
1318 return 0; // direntry fits into current space
1319
1320 entriesPerSector = fatd->partBpb.sectorSize / 32;
1321 maxSector = i / entriesPerSector;
1322 if (i % entriesPerSector) {
1323 maxSector++;
1324 }
1325
1326 chainSize = fat_getDirentrySectorData(fatd, &startCluster, &startSector, &dirSector);
1327
1328 XPRINTF("maxSector=%u dirSector=%u\n", maxSector, dirSector);
1329
1330 if ((unsigned int)maxSector <= dirSector)
1331 return 0;
1332
1333 // Root directory of FAT12 or FAT16 - space can't be enlarged!
1334 if (startCluster == 0 && fatd->partBpb.fatType < FAT32) {
1335 return -EMLINK; // too many direntries in the root directory
1336 }
1337
1338 // in the fatd->cbuf we have the cluster chain
1339
1340 // get last cluster of the cluster chain
1341 currentCluster = fatd->cbuf[chainSize - 1];
1342 XPRINTF("current (last) cluster=%u \n", currentCluster);
1343
1344 // get 1 cluster from cluster stack and append the chain
1345 newCluster = fat_getFreeCluster(fatd, currentCluster);
1346 XPRINTF("new cluster=%u \n", newCluster);
1347 fat_invalidateLastChainResult(fatd); // prevent to misuse current (now updated) fatd->cbuf
1348 // if new cluster cannot be allocated
1349 if (newCluster == 0) {
1350 return -ENOSPC;
1351 }
1352
1353 // now clean the directory space
1354 startSector = fat_cluster2sector(&fatd->partBpb, newCluster);
1355 for (i = 0; i < fatd->partBpb.clusterSize; i++) {
1356 int ret;
1357
1358 unsigned char *sbuf = NULL; // sector buffer
1359
1360 ret = ALLOC_SECTOR(DEV_ACCESSOR(fatd), startSector + i, sbuf);
1361 if (ret < 0)
1362 return -EIO;
1363 memset(sbuf, 0, fatd->partBpb.sectorSize); // fill whole sector with zeros
1364 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), startSector + i);
1365 if (ret < 0)
1366 return -EIO;
1367 }
1368 return 1; // 1 cluster allocated
1369}
1370
1371//---------------------------------------------------------------------------
1372/*
1373 Create empty directory space with two SFN direntries:
1374 1) current directory "."
1375 2) parent directory ".."
1376
1377*/
1378static int createDirectorySpace(fat_driver *fatd, unsigned int dirCluster, unsigned int parentDirCluster)
1379{
1380 int i, j;
1381 unsigned int startSector;
1382
1383 // we do not mess with root directory
1384 if (dirCluster < 2) {
1385 return -EFAULT;
1386 }
1387
1388 // we create directory space inside one cluster. No need to worry about
1389 // large dir space spread on multiple clusters
1390 startSector = fat_cluster2sector(&fatd->partBpb, dirCluster);
1391 XPRINTF("I: create dir space: cluster=%u sector=%u (%u) \n", dirCluster, startSector, startSector * fatd->partBpb.sectorSize);
1392
1393 // go through all sectors of the cluster
1394 for (i = 0; i < fatd->partBpb.clusterSize; i++) {
1395 int ret;
1396
1397 unsigned char *sbuf = NULL; // sector buffer
1398
1399 ret = ALLOC_SECTOR(DEV_ACCESSOR(fatd), startSector + i, sbuf);
1400 if (ret < 0) {
1401 XPRINTF("alloc directory sector failed ! sector=%u\n", startSector + i);
1402 return -EIO;
1403 }
1404 memset(sbuf, 0, fatd->partBpb.sectorSize); // clean the sector
1405 if (i == 0) {
1406 fat_direntry_sfn *dsfn = (fat_direntry_sfn *)sbuf;
1407 char name[11];
1408 for (j = 1; j < 11; j++)
1409 name[j] = ' ';
1410 name[0] = '.';
1411 setSfnEntry(name, 1, dsfn + 0, dirCluster);
1412 name[1] = '.';
1413 setSfnEntry(name, 1, dsfn + 1, parentDirCluster);
1414 }
1415 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), startSector + i);
1416 if (ret < 0) {
1417 XPRINTF("write directory sector failed ! sector=%u\n", startSector + i);
1418 return -EIO;
1419 }
1420 }
1421
1422 return (0);
1423}
1424
1425/*
1426 Update the parent directory ("..") entry cluster number of the specified SFN direntry.
1427*/
1428static int updateDirectoryParent(fat_driver *fatd, unsigned int dirCluster, unsigned int parentDirCluster)
1429{
1430 int i, j;
1431 unsigned int startSector;
1432
1433 // we do not mess with root directory
1434 if (dirCluster < 2) {
1435 return -EFAULT;
1436 }
1437
1438 // The basic directory space should be within one cluster. No need to worry about
1439 // large dir space spread on multiple clusters
1440 startSector = fat_cluster2sector(&fatd->partBpb, dirCluster);
1441 XPRINTF("I: update dir parent: cluster=%u sector=%u (%u) \n", dirCluster, startSector, startSector * fatd->partBpb.sectorSize);
1442
1443 // go through all sectors of the cluster
1444 for (i = 0; i < fatd->partBpb.clusterSize; i++) {
1445 int ret;
1446
1447 unsigned char *sbuf = NULL; // sector buffer
1448
1449 ret = READ_SECTOR(DEV_ACCESSOR(fatd), startSector + i, sbuf);
1450 if (ret < 0) {
1451 XPRINTF("read directory sector failed ! sector=%u\n", startSector + i);
1452 return -EIO;
1453 }
1454 fat_direntry_sfn *dsfn = (fat_direntry_sfn *)sbuf;
1455 for (j = 0; (unsigned int)j < fatd->partBpb.sectorSize; j += sizeof(fat_direntry_sfn), dsfn++) {
1456 if (memcmp(dsfn->name, ".. ", sizeof(dsfn->name)) == 0) {
1457 dsfn->clusterH[0] = (parentDirCluster & 0xFF0000) >> 16;
1458 dsfn->clusterH[1] = (parentDirCluster & 0xFF000000) >> 24;
1459 dsfn->clusterL[0] = (parentDirCluster & 0x00FF);
1460 dsfn->clusterL[1] = (parentDirCluster & 0xFF00) >> 8;
1461
1462 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), startSector + i);
1463 if (ret < 0) {
1464 XPRINTF("write directory sector failed ! sector=%u\n", startSector + i);
1465 return -EIO;
1466 }
1467
1468 return 0;
1469 }
1470 }
1471 }
1472
1473 return -1;
1474}
1475
1476//---------------------------------------------------------------------------
1477/*
1478 Save direntries of the long and short filename to the directory space on the disk
1479
1480 startCluster - start cluster of the directory space
1481 lname : long name
1482 sname : short name
1483 directory : 0-file, 1-directory
1484 cluster : start cluster of the file/directory
1485
1486 entrySize - number of direntries to store
1487 entryIndex - index of the direntry start in the directory space
1488
1489 retSector - contains sector number of the direntry (output)
1490 retOffset - contains byte offse of the SFN direntry from start of the sector (output)
1491 the reason is to speed up modification of the SFN (size of the file)
1492
1493 note: the filesize set in the direntry is 0 (for both directory and file)
1494*/
1495static int saveDirentry(fat_driver *fatd, unsigned int startCluster,
1496 const char *lname, const char *sname, char directory, unsigned int cluster,
1497 int entrySize, int entryIndex, unsigned int *retSector, int *retOffset, const fat_direntry_sfn *orig_dsfn)
1498{
1499 int i, j;
1500 unsigned int dirSector;
1501 unsigned int startSector;
1502 int cont;
1503 int entryEndIndex;
1504#ifdef DEBUG
1505#ifdef BUILDING_USBHDFSD
1506 mass_dev *mass_device = fatd->dev;
1507#endif /* BUILDING_USBHDFSD */
1508#ifdef BUILDING_IEEE1394_DISK
1509 struct SBP2Device *mass_device = fatd->dev;
1510#endif /* BUILDING_IEEE1394_DISK */
1511#endif
1512 int part = entrySize - 1;
1513 int nameSize;
1514 unsigned char chsum;
1515
1516 chsum = computeNameChecksum(sname);
1517 nameSize = strlen(lname);
1518
1519 cont = 1;
1520 // clear name strings
1521 entryEndIndex = entryIndex + entrySize;
1522
1523 j = 0;
1524
1525 fat_getDirentrySectorData(fatd, &startCluster, &startSector, &dirSector);
1526
1527 XPRINTF("dirCluster=%u startSector=%u (%u) dirSector=%u \n", startCluster, startSector, startSector
1528#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
1529 * fatd->bd->sectorSize,
1530#else
1531 * mass_device->sectorSize,
1532#endif
1533 dirSector);
1534
1535 // go through first directory sector till the max number of directory sectors
1536 // or stop when no more direntries detected
1537 for (i = 0; (unsigned int)i < dirSector && cont; i++) {
1538 unsigned int theSector;
1539 int ret;
1540 unsigned int dirPos;
1541 int writeFlag;
1542
1543 unsigned char *sbuf = NULL; // sector buffer
1544
1545 // At cluster borders, get correct sector from cluster chain buffer
1546 if ((startCluster != 0) && (i % fatd->partBpb.clusterSize == 0)) {
1547 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[(i / fatd->partBpb.clusterSize)]) - i;
1548 }
1549 theSector = startSector + i;
1550 ret = READ_SECTOR(DEV_ACCESSOR(fatd), theSector, sbuf);
1551 if (ret < 0) {
1552 XPRINTF("read directory sector failed ! sector=%u\n", theSector);
1553 return -EIO;
1554 }
1555 XPRINTF("read sector ok, scanning sector for direntries...\n");
1556 dirPos = 0;
1557 writeFlag = 0;
1558 // go through start of the sector till the end of sector
1559 while (dirPos < fatd->partBpb.sectorSize) {
1560 if (j >= entryIndex && j < entryEndIndex) {
1561 fat_direntry *dir_entry = (fat_direntry *)(sbuf + dirPos);
1562 if (part == 0) {
1563 if (orig_dsfn == NULL)
1564 setSfnEntry(sname, directory, &dir_entry->sfn, cluster);
1565 else
1566 setSfnEntryFromOld(sname, &dir_entry->sfn, orig_dsfn);
1567 } else
1568 setLfnEntry(lname, nameSize, chsum, &dir_entry->lfn, part, entrySize - 1);
1569 part--;
1570 writeFlag++;
1571 // SFN is stored
1572 if (j == entryEndIndex - 1) {
1573 *retSector = theSector;
1574 *retOffset = dirPos;
1575 }
1576 }
1577 // sbuf + dirPos
1578 dirPos += sizeof(fat_direntry);
1579 j++;
1580 } // ends "while"
1581 // store modified sector
1582 if (writeFlag) {
1583 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), theSector);
1584 if (ret < 0) {
1585 XPRINTF("write directory sector failed ! sector=%u\n", theSector);
1586 return -EIO;
1587 }
1588 }
1589 if (j >= entryEndIndex) {
1590 cont = 0; // do not continue
1591 }
1592 }
1593 return j;
1594}
1595
1596//---------------------------------------------------------------------------
1597/*
1598 - create/convert long name to short name
1599 - analyse directory space
1600 - enlarge directory space
1601 - save direntries
1602
1603 lname - long name
1604 directory - 0-> create file 1->create directory
1605 escapeNoExist - 0->allways create file 1->early exit if file doesn't exist
1606 startCluster - directory space start cluster (set to zero for root directory) (input), first cluster of dirent (output)
1607 retSector - SFN sector - sector of the SFN direntry (output)
1608 retOffset - byte offset of the SFN direntry counting from the start of the sector (output)
1609 orig_dsfn - Dirent SFN entry, to use as the new dirent.
1610*/
1611static int fat_modifyDirSpace(fat_driver *fatd, char *lname, char directory, char escapeNotExist, unsigned int *startCluster, unsigned int *retSector, int *retOffset, const fat_direntry_sfn *orig_dsfn)
1612{
1613 char sname[12]; // short name 8+3 + terminator
1614 unsigned int newCluster, parentDirCluster;
1615 int ret, entryCount, compressShortName, entryIndex, direntrySize;
1616
1617 // dlanor: Since each filename may need up to 11 directory entries (MAX_FAT_NAME==128)
1618 // dlanor: I've rewritten the methods of this function to use global bitmasks as this
1619 // dlanor: allows more effective entry handling than most other methods
1620 //
1621 // memo buffer for each direntry - up to 1024 entries in directory
1622 // 7 6 5 4 3 2 | 1 0
1623 // ------------+-----
1624 // SEQ HI/LO | ID
1625 // ------------------
1626 // ID : 0 - entry is empty or deleted
1627 // 1 - sfn entry
1628 // 2 - lfn entry
1629 // 3 - other entry (volume label etc.)
1630 // SEQ: sequence number of the short filename.
1631 // if our long filename is "Quitelongname.txt" then
1632 // seq for existing entry:
1633 // ABCD.TXT seq = 0 (no sequence number in name and name doesn't match)
1634 // ABCDEF~1.TXT seq = 0 (because the short names doesn't match)
1635 // QUITELON.TXT seq = 0 (again the short name doesn't match)
1636 // QUITEL~1.JPG seq = 0 (name match but extension desn't match)
1637 // QUITEL~1.TXT seq = 1 (both name and extension match - sequence number 1)
1638 // QUITE~85.TXT seq = 85 ( dtto. ^^^^)
1639
1640 // If the sfn has sequence it means the filename should be long
1641 // and preceeding entry should be lfn. In this case the preceeding (lfn)
1642 // entry seq holds the high 6 bites of the whole sequence. If preceding
1643 // entry is another sfn direntry then we report error (even if it might be
1644 // (in some rare occasions) correct directory structure).
1645
1646
1647 sname[11] = 0;
1648
1649 // create short name from long name
1650 ret = createShortNameMask(lname, sname);
1651 if (ret < 0) {
1652 XPRINTF("E: short name invalid!\n");
1653 return ret;
1654 }
1655 compressShortName = ret;
1656
1657 // get information about existing direntries (palcement of the empty/reusable direntries)
1658 // and sequence numbers of the short filenames
1659 parentDirCluster = *startCluster;
1660 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1661 startCluster, retSector, retOffset);
1662 if (ret < 0) {
1663 XPRINTF("E: direntry data invalid!\n");
1664 return ret;
1665 }
1666 // ret 0 means that exact filename/directory already exist
1667 if (ret == 0) {
1668 return ret;
1669 }
1670
1671 // exact filename not exist and we want to report it
1672 if (escapeNotExist) {
1673 return -ENOENT;
1674 }
1675
1676 if (ret > DIR_MASK_SIZE) {
1677 XPRINTF("W: Direntry count is larger than number of records!\n");
1678 ret = DIR_MASK_SIZE;
1679 }
1680 entryCount = ret;
1681 XPRINTF("I: direntry count=%d\n", entryCount);
1682
1683 if (compressShortName) {
1684 setShortNameSequence(fatd, sname);
1685 }
1686 XPRINTF("I: new short name='%s' \n", sname);
1687
1688 // direntry size for long name + 1 additional direntry for short name
1689 direntrySize = getDirentrySize(lname) + 1;
1690 XPRINTF("Direntry size=%d\n", direntrySize);
1691
1692 // find the offset (index) of the direntry space where to put this direntry
1693 entryIndex = getDirentryStoreOffset(fatd, entryCount, direntrySize);
1694 XPRINTF("I: direntry store offset=%d\n", entryIndex);
1695
1696 // if the direntry offset excede current space of directory clusters
1697 // we have to add one cluster to directory space
1698 ret = enlargeDirentryClusterSpace(fatd, parentDirCluster, entryCount, entryIndex, direntrySize);
1699 XPRINTF("I: enlarge direntry cluster space ret=%d\n", ret);
1700 if (ret < 0) {
1701 return ret;
1702 }
1703
1704 if (orig_dsfn == NULL) {
1705 // get new cluster for file/directory
1706 newCluster = fat_getFreeCluster(fatd, 0);
1707 if (newCluster == 0) {
1708 return -ENOSPC;
1709 }
1710 XPRINTF("I: new file/dir cluster=%u\n", newCluster);
1711 *startCluster = newCluster;
1712 } else {
1713 *startCluster = (fatd->partBpb.fatType == FAT32) ? getUI32_2(orig_dsfn->clusterL, orig_dsfn->clusterH) : getUI16(orig_dsfn->clusterL);
1714 newCluster = 0;
1715 }
1716
1717 // now store direntries into the directory space
1718 ret = saveDirentry(fatd, parentDirCluster, lname, sname, directory, newCluster, direntrySize, entryIndex, retSector, retOffset, orig_dsfn);
1719 XPRINTF("I: save direntry ret=%d\n", ret);
1720 if (ret < 0) {
1721 return ret;
1722 }
1723
1724 // create empty directory structure
1725 if ((orig_dsfn == NULL) && directory) {
1726 ret = createDirectorySpace(fatd, newCluster, parentDirCluster);
1727 XPRINTF("I: create directory space ret=%d\n", ret);
1728 if (ret < 0) {
1729 return ret;
1730 }
1731 }
1732
1733 return 1;
1734}
1735
1736//---------------------------------------------------------------------------
1737/*
1738 Check whether directory space contain any file or directory
1739
1740 startCluster - start cluster of the directory space
1741
1742 returns: 0 - false - directory space contains files or directories (except '.' and '..')
1743 1 - true - directory space is empty or contains deleted entries
1744 -X - error
1745*/
1746static int checkDirspaceEmpty(fat_driver *fatd, unsigned int startCluster)
1747{
1748 int ret;
1749 int i;
1750 char sname[12]; // short name 8+3 + terminator
1751 int entryCount;
1752
1753 unsigned int retSector;
1754 int retOffset;
1755
1756 XPRINTF("I: checkDirspaceEmpty directory cluster=%u \n", startCluster);
1757 if (startCluster < 2) { // do not check root directory!
1758 return -EFAULT;
1759 }
1760
1761 sname[0] = 0;
1762
1763
1764 ret = fat_fillDirentryInfo(fatd, sname, sname, 1,
1765 &startCluster, &retSector, &retOffset);
1766 if (ret > DIR_MASK_SIZE) {
1767 XPRINTF("W: Direntry count is larger than number of records! directory space cluster =%u maxRecords=%u\n", startCluster, DIR_MASK_SIZE);
1768 ret = DIR_MASK_SIZE;
1769 }
1770 entryCount = ret;
1771 // first two records should be '.' & '..', which don't count as real content
1772 if ((fatd->dir_used_mask[0] & 0xFC) != 0)
1773 goto non_empty;
1774 for (i = 1; i < (entryCount / 8); i++) {
1775 if (fatd->dir_used_mask[i] != 0) {
1776 non_empty:
1777 XPRINTF("I: directory not empty!\n");
1778 return 0;
1779 } // ends "if"
1780 } // ends "for"
1781 XPRINTF("I: directory is empty.\n");
1782 return 1;
1783}
1784
1785//---------------------------------------------------------------------------
1786static int fat_wipeDirEntries(fat_driver *fatd)
1787{
1788 int ret;
1789 unsigned int i, theSector;
1790 unsigned char *sbuf = NULL;
1791
1792 // now mark direntries as deleted
1793 theSector = 0;
1794 ret = 0;
1795 for (i = 0; i < (u32)(fatd->deIdx); i++) {
1796 if (fatd->deSec[i] != theSector) {
1797 if (theSector > 0) {
1798 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), theSector);
1799 if (ret < 0) {
1800 XPRINTF("write directory sector failed ! sector=%u\n", theSector);
1801 ret = -EIO;
1802 break;
1803 }
1804 }
1805 theSector = fatd->deSec[i];
1806 ret = READ_SECTOR(DEV_ACCESSOR(fatd), theSector, sbuf);
1807 if (ret < 0) {
1808 XPRINTF("read directory sector failed ! sector=%u\n", theSector);
1809 ret = -EIO;
1810 break;
1811 }
1812 }
1813 sbuf[fatd->deOfs[i]] = 0xE5; // delete marker
1814 }
1815 if (theSector > 0) {
1816 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), theSector);
1817 if (ret < 0) {
1818 XPRINTF("write directory sector failed ! sector=%u\n", theSector);
1819 ret = -EIO;
1820 }
1821 }
1822
1823 return ret;
1824}
1825
1826
1827/*
1828 Remove the name (direntries of the file or directory) from the directory space.
1829
1830 lname - long name (without the path)
1831 directory - 0->delete file 1-delete directory
1832 startCluster - start cluster of the directory space
1833*/
1834
1835static int fat_clearDirSpace(fat_driver *fatd, char *lname, char directory, unsigned int *startCluster)
1836{
1837 int ret;
1838 char sname[12]; // short name 8+3 + terminator
1839 unsigned int dirCluster;
1840 unsigned int sfnSector;
1841 int sfnOffset;
1842
1843 sname[0] = 0;
1844
1845
1846 dirCluster = *startCluster;
1847 // get information about existing direntries (palcement of the empty/reusable direntries)
1848 // and find the lname in the directory
1849 // also fill up the dsSec and dsOfs information
1850 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1851 startCluster, &sfnSector, &sfnOffset);
1852 if (ret != 0) {
1853 XPRINTF("E: direntry not found!\n");
1854 return -ENOENT;
1855 }
1856 XPRINTF("clear dir space: dir found at cluster=%u \n ", *startCluster);
1857
1858 // Check wether any file or directory exist in te target directory space.
1859 // We should not delete the directory if files/directories exist
1860 // because just clearing the dir doesn't free the fat clusters
1861 // occupied by files.
1862 if (directory) {
1863 // check wether sub-directory is empty
1864 // startCluster now points to subdirectory start cluster
1865 ret = checkDirspaceEmpty(fatd, *startCluster);
1866 if (ret == 0) { // directorty contains some files
1867 return -ENOTEMPTY;
1868 }
1869 // read the direntry info again, because we lost it during subdir check
1870 *startCluster = dirCluster;
1871
1872 ret = fat_fillDirentryInfo(fatd, lname, sname, directory,
1873 startCluster, &sfnSector, &sfnOffset);
1874 if (ret != 0) {
1875 XPRINTF("E: direntry not found!\n");
1876 return -ENOENT;
1877 }
1878 }
1879
1880 // now mark direntries as deleted
1881 ret = fat_wipeDirEntries(fatd);
1882 if (ret < 0) {
1883 XPRINTF("E: wipe direntries failed!\n");
1884 return ret;
1885 }
1886
1887 // now delete whole cluster chain starting at the file's first cluster
1888 ret = fat_deleteClusterChain(fatd, *startCluster);
1889 if (ret < 0) {
1890 XPRINTF("E: delete cluster chain failed!\n");
1891 return ret;
1892 }
1893 return 1;
1894}
1895
1896
1897
1898/* ===================================================================== */
1899
1900/*
1901 cluster - start cluster of the file
1902 sfnSector - short filename entry sector
1903 sfnOffset - short filename entry offset from the sector start
1904*/
1905int fat_truncateFile(fat_driver *fatd, unsigned int cluster, unsigned int sfnSector, int sfnOffset)
1906{
1907 int ret;
1908 fat_direntry_sfn *dsfn;
1909 unsigned char *sbuf = NULL; // sector buffer
1910
1911 if (cluster == 0 || sfnSector == 0) {
1912 return -EFAULT;
1913 }
1914
1915 // now delete whole cluster chain starting at the file's first cluster
1916 ret = fat_deleteClusterChain(fatd, cluster);
1917 if (ret < 0) {
1918 XPRINTF("E: delete cluster chain failed!\n");
1919 return ret;
1920 }
1921
1922 // terminate cluster
1923 ret = fat_createClusterChain(fatd, cluster);
1924 if (ret < 0) {
1925 XPRINTF("E: truncate cluster chain failed!\n");
1926 return ret;
1927 }
1928
1929 ret = READ_SECTOR(DEV_ACCESSOR(fatd), sfnSector, sbuf);
1930 if (ret < 0) {
1931 XPRINTF("read direntry sector failed ! sector=%u\n", sfnSector);
1932 return -EIO;
1933 }
1934 dsfn = (fat_direntry_sfn *)(sbuf + sfnOffset);
1935 dsfn->size[0] = 0;
1936 dsfn->size[1] = 0;
1937 dsfn->size[2] = 0;
1938 dsfn->size[3] = 0;
1939
1940 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), sfnSector);
1941 if (ret < 0) {
1942 XPRINTF("write directory sector failed ! sector=%u\n", sfnSector);
1943 return -EIO;
1944 }
1945 return 1;
1946}
1947
1948
1949//---------------------------------------------------------------------------
1950/*
1951 Update size of the SFN entry
1952
1953 cluster - start cluster of the file
1954 sfnSector - short filename entry sector
1955 sfnOffset - short filename entry offset from the sector start
1956*/
1957int fat_updateSfn(fat_driver *fatd, int size, unsigned int sfnSector, int sfnOffset)
1958{
1959 int ret;
1960 fat_direntry_sfn *dsfn;
1961 unsigned char *sbuf = NULL; // sector buffer
1962
1963 if (sfnSector == 0) {
1964 return -EFAULT;
1965 }
1966
1967
1968 ret = READ_SECTOR(DEV_ACCESSOR(fatd), sfnSector, sbuf);
1969 if (ret < 0) {
1970 XPRINTF("read direntry sector failed ! sector=%u\n", sfnSector);
1971 return -EIO;
1972 }
1973 dsfn = (fat_direntry_sfn *)(sbuf + sfnOffset);
1974 dsfn->size[0] = size & 0xFF;
1975 dsfn->size[1] = (size & 0xFF00) >> 8;
1976 dsfn->size[2] = (size & 0xFF0000) >> 16;
1977 dsfn->size[3] = (size & 0xFF000000) >> 24;
1978
1979 setSfnDate(dsfn, DATE_MODIFY);
1980
1981 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), sfnSector);
1982 if (ret < 0) {
1983 XPRINTF("write directory sector failed ! sector=%u\n", sfnSector);
1984 return -EIO;
1985 }
1986 XPRINTF("I: sfn updated, file size=%d \n", size);
1987 return 1;
1988}
1989
1990
1991//---------------------------------------------------------------------------
1992/*
1993 create file or directory
1994
1995 fname - path and filename
1996 directory - set to 0 to create file, 1 to create directory
1997 escapeNotExist - set to 1 if you want to report error if file not exist.
1998 Otherwise set to 0 and file/dir will be created.
1999 cluster - start cluster of the directory space - default is 0 -> root directory (input), first cluster of dirent (output).
2000 sfnSector - sector of the SFN entry (output) - helps to modify direntry (size, date, time)
2001 sfnOffset - offset (in bytes) of the SFN entry (output)
2002*/
2003int fat_createFile(fat_driver *fatd, const char *fname, char directory, char escapeNotExist, unsigned int *cluster, unsigned int *sfnSector, int *sfnOffset)
2004{
2005 int ret;
2006 unsigned int startCluster;
2007 unsigned int directoryCluster;
2008 char lname[FAT_MAX_NAME], pathToDirent[FAT_MAX_PATH];
2009 fat_dir fatdir;
2010
2011 ret = separatePathAndName(fname, pathToDirent, lname);
2012 if ((ret < 0) // if name invalid to separation routine
2013 || ((lname[0] == 0) // or name is empty string
2014 || ((lname[0] == '.') && ((lname[1] == 0) // or name is single period
2015 || ((lname[1] == '.') && (lname[2] == 0) // or name is two periods
2016 ))))) {
2017 XPRINTF("E: file name not exist or not valid!");
2018 return -ENOENT;
2019 }
2020
2021 XPRINTF("Calling fat_getFileStartCluster from fat_createFile\n");
2022 // get start cluster of the last sub-directory of the path
2023 startCluster = 0;
2024 ret = fat_getFileStartCluster(fatd, pathToDirent, &startCluster, &fatdir);
2025 if (ret < 0) {
2026 XPRINTF("E: directory not found! \n");
2027 return ret;
2028 }
2029
2030 if (!(fatdir.attr & FAT_ATTR_DIRECTORY)) {
2031 XPRINTF("E: directory not found! \n");
2032 return -ENOENT;
2033 }
2034
2035 XPRINTF("directory=%s name=%s cluster=%u \n", pathToDirent, lname, startCluster);
2036
2037 if (fatdir.attr & FAT_ATTR_READONLY)
2038 return -EACCES;
2039
2040 // modify directory space of the path (cread direntries)
2041 // and/or create new (empty) directory space if directory creation requested
2042 directoryCluster = startCluster;
2043 ret = fat_modifyDirSpace(fatd, lname, directory, escapeNotExist, &startCluster, sfnSector, sfnOffset, NULL);
2044 if (ret < 0) {
2045 XPRINTF("E: modifyDirSpace failed!\n");
2046 return ret;
2047 }
2048 XPRINTF("I: SFN info: sector=%u (%u) offset=%u (%u) startCluster=%u\n", *sfnSector, *sfnSector * fatd->partBpb.sectorSize, *sfnOffset, *sfnOffset + (*sfnSector * fatd->partBpb.sectorSize), startCluster);
2049 *cluster = startCluster;
2050 // dlanor: I've repatched the stuff below to improve functionality
2051 // The simple test below was bugged for the case of creating a folder in root
2052 // if (startCluster != directoryCluster) {
2053 // That test (on the line above) fails in root because created folders never
2054 // get a startCluster of 0. That is reserved for root only.
2055 // The test below replaces this with a more complex test that takes all of this
2056 // stuff into proper account, but behaves like the old test for other cases.
2057 // That's mainly because I can't tell how consistent name conflict flagging is
2058 // for those other cases, and it's not really worth the trouble of finding out :)
2059 if ((ret == 0) // if we have a directly flagged name conflict
2060 || ((directoryCluster || !directory) // OR working in non_root, or making a file
2061 && (startCluster != directoryCluster) // AND we get an unexpected startCluster
2062 )) {
2063 XPRINTF("I: file already exists at cluster=%u\n", startCluster);
2064 return EEXIST;
2065 }
2066 return 0;
2067}
2068
2069
2070//---------------------------------------------------------------------------
2071int fat_deleteFile(fat_driver *fatd, const char *fname, char directory)
2072{
2073 int ret;
2074 unsigned int startCluster;
2075 unsigned int directoryCluster;
2076 char lname[FAT_MAX_NAME], pathToDirent[FAT_MAX_PATH];
2077 fat_dir fatdir;
2078
2079 ret = separatePathAndName(fname, pathToDirent, lname);
2080 if ((ret < 0) // if name invalid to separation routine
2081 || ((lname[0] == 0) // or name is empty string
2082 || ((lname[0] == '.') && ((lname[1] == 0) // or name is single period
2083 || ((lname[1] == '.') && (lname[2] == 0) // or name is two periods
2084 ))))) {
2085 XPRINTF("E: file name not exist or not valid!");
2086 return -ENOENT;
2087 }
2088
2089 XPRINTF("Calling fat_getFileStartCluster from fat_deleteFile\n");
2090 // get start cluster of the last sub-directory of the path
2091 startCluster = 0;
2092 ret = fat_getFileStartCluster(fatd, pathToDirent, &startCluster, &fatdir);
2093 if (ret < 0) {
2094 XPRINTF("E: directory not found! \n");
2095 return ret;
2096 }
2097
2098 if (!(fatdir.attr & FAT_ATTR_DIRECTORY)) {
2099 XPRINTF("E: directory not found! \n");
2100 return -ENOENT;
2101 }
2102
2103 XPRINTF("directory=%s name=%s cluster=%u \n", pathToDirent, lname, startCluster);
2104
2105 if (fatdir.attr & FAT_ATTR_READONLY) {
2106 XPRINTF("E: directory read only! \n");
2107 return -EACCES;
2108 }
2109
2110 // delete direntries and modify fat
2111 directoryCluster = startCluster;
2112 ret = fat_clearDirSpace(fatd, lname, directory, &startCluster);
2113 if (ret < 0) {
2114 XPRINTF("E: cleanDirSpace failed!\n");
2115 return ret;
2116 }
2117 if (startCluster != directoryCluster) {
2118 XPRINTF("I: file/dir removed from cluster=%u\n", startCluster);
2119 }
2120 return 0;
2121}
2122
2123//---------------------------------------------------------------------------
2124// Create a new record that points to the file/directory, before deleting the original one.
2125
2126int fat_renameFile(fat_driver *fatd, fat_dir *fatdir, const char *fname)
2127{
2128 int ret;
2129 unsigned int sDirCluster;
2130 unsigned int dDirCluster, dParentDirCluster;
2131 char lname[FAT_MAX_NAME], pathToDirent[FAT_MAX_PATH];
2132 unsigned int sfnSector, new_sfnSector, startCluster;
2133 int sfnOffset, new_sfnOffset;
2134 char sname[12]; // short name 8+3 + terminator
2135 unsigned char *sbuf = NULL;
2136 unsigned char srcIsDirectory;
2137 fat_direntry_sfn OriginalSFN;
2138
2139 ret = separatePathAndName(fname, pathToDirent, lname);
2140 if ((ret < 0) // if name invalid to separation routine
2141 || ((lname[0] == 0) // or name is empty string
2142 || ((lname[0] == '.') && ((lname[1] == 0) // or name is single period
2143 || ((lname[1] == '.') && (lname[2] == 0) // or name is two periods
2144 ))))) {
2145 XPRINTF("E: destination file name not exist or not valid!");
2146 return -ENOENT;
2147 }
2148
2149 // Check if the source file exists, and that the new filename is not in use.
2150 sDirCluster = fatdir->parentDirCluster;
2151 dDirCluster = 0;
2152 XPRINTF("Calling fat_getFileStartCluster from fat_renameFile\n");
2153
2154 ret = fat_getFileStartCluster(fatd, pathToDirent, &dDirCluster, NULL);
2155 if (ret < 0) {
2156 XPRINTF("E: destination directory not found! \n");
2157 return ret;
2158 }
2159 dParentDirCluster = dDirCluster; // Backup dDirCluster, as every call to fat_filleDirentryInfo will update it to point to the scanned file's first cluster.
2160
2161 // Get the SFN sector number and offset, so that the SFN record can be read.
2162 sname[0] = 0;
2163 ret = fat_fillDirentryInfo(fatd, fatdir->name, sname, -1, &sDirCluster, &sfnSector, &sfnOffset);
2164 if (ret != 0) {
2165 XPRINTF("E: direntry not found! %d\n", ret);
2166 return -ENOENT;
2167 }
2168
2169 XPRINTF("fat_renameFile: dir found at cluster=%u \n ", sDirCluster);
2170
2171 // Preserve the original SFN entry.
2172 if ((ret = READ_SECTOR(DEV_ACCESSOR(fatd), sfnSector, sbuf)) < 0) {
2173 XPRINTF("E: I/O error! %d\n", ret);
2174 return ret;
2175 }
2176 memcpy(&OriginalSFN, (fat_direntry_sfn *)(sbuf + sfnOffset), sizeof(fat_direntry_sfn));
2177 srcIsDirectory = ((fat_direntry_sfn *)(sbuf + sfnOffset))->attr & FAT_ATTR_DIRECTORY;
2178
2179 ret = fat_fillDirentryInfo(fatd, lname, sname, srcIsDirectory, &dDirCluster, &new_sfnSector, &new_sfnOffset);
2180 if (ret == 0) {
2181 // Entry is found and the type is the same as the original (both are either directories or files).
2182 if (srcIsDirectory) {
2183 // If directory, the rename can still take place if the directory can be deleted (is empty).
2184 dDirCluster = dParentDirCluster;
2185 if ((ret = fat_clearDirSpace(fatd, lname, 1, &dDirCluster)) < 0)
2186 return ret;
2187 } else {
2188 // Do not allow a file to be renamed to an existing file.
2189 return -EEXIST;
2190 }
2191 }
2192
2193 // Insert a new record.
2194 startCluster = dParentDirCluster;
2195 if ((ret = fat_modifyDirSpace(fatd, lname, srcIsDirectory, 0, &startCluster, &sfnSector, &sfnOffset, &OriginalSFN)) < 0) {
2196 XPRINTF("E: fat_modifyDirSpace failed! %d\n", ret);
2197 return ret;
2198 }
2199
2200 // If it is a directory, update the parent directory record.
2201 if (srcIsDirectory) {
2202 dDirCluster = (fatd->partBpb.fatType == FAT32) ? getUI32_2(OriginalSFN.clusterL, OriginalSFN.clusterH) : getUI16(OriginalSFN.clusterL);
2203 if ((ret = updateDirectoryParent(fatd, dDirCluster, dParentDirCluster)) != 0) {
2204 XPRINTF("E: could not update \"..\" entry! %d\n", ret);
2205 return ret;
2206 }
2207 }
2208
2209 // Wipe the original entry.
2210 // Fill fatd with a list of the original directory entry records, which can be deleted.
2211 sDirCluster = fatdir->parentDirCluster;
2212 ret = fat_fillDirentryInfo(fatd, fatdir->name, sname, -1, &sDirCluster, &sfnSector, &sfnOffset);
2213 if (ret != 0) {
2214 XPRINTF("E: direntry not found! %d\n", ret);
2215 return -ENOENT;
2216 }
2217
2218 // now mark the original direntries as deleted
2219 ret = fat_wipeDirEntries(fatd);
2220 if (ret < 0) {
2221 XPRINTF("E: wipe direntries failed!\n");
2222 return ret;
2223 }
2224
2225 fatdir->parentDirCluster = dParentDirCluster;
2226 strcpy(fatdir->name, lname);
2227
2228 return 0;
2229} // ends fat_renameFile
2230
2231//---------------------------------------------------------------------------
2232#ifdef BUILDING_USBHDFSD
2233static int fat_writeSingleSector(mass_dev *dev, unsigned int sector, const void *buffer, int size, int dataSkip)
2234{
2235 unsigned char *sbuf = NULL; // sector buffer
2236 int ret;
2237
2238 if ((dataSkip > 0) || ((unsigned int)size < dev->sectorSize) || (((int)buffer & 3) != 0)) {
2239 // Handle the partially-filled sector.
2240 ret = READ_SECTOR(dev, sector, sbuf);
2241 if (ret < 0) {
2242 XPRINTF("Read sector failed ! sector=%u\n", sector);
2243 return 0;
2244 }
2245
2246 memcpy(sbuf + dataSkip, buffer, size);
2247
2248 ret = WRITE_SECTOR(dev, sector);
2249 if (ret < 0) {
2250 printf("USBHDFSD: Write sector failed ! sector=%u\n", sector);
2251 return 0; // return number of bytes already written
2252 }
2253 } else {
2254 // Invalidate the block that the sector belongs to, in case it crosses another cluster.
2255 INVALIDATE_SECTORS(dev, sector, 1);
2256
2257 ret = WRITE_SECTORS_RAW(dev, sector, 1, buffer);
2258 if (ret != 0) {
2259 XPRINTF("Write sector failed ! sector=%u\n", sector);
2260 return 0;
2261 }
2262 }
2263
2264 return 1;
2265}
2266#endif /* BUILDING_USBHDFSD */
2267
2268int fat_writeFile(fat_driver *fatd, fat_dir *fatDir, int *updateClusterIndices, unsigned int filePos, unsigned char *buffer, unsigned int size)
2269{
2270 int ret;
2271 int i, j;
2272 int nextChain;
2273 unsigned int bufSize;
2274 int sectorSkip;
2275 int clusterSkip;
2276 int dataSkip;
2277
2278 unsigned int bufferPos;
2279 unsigned int fileCluster;
2280 unsigned int clusterPos;
2281 unsigned int endPosFile;
2282 unsigned int endPosCluster;
2283
2284 int clusterChainStart;
2285
2286#ifdef BUILDING_USBHDFSD
2287 // cppcheck-suppress unreadVariable
2288 mass_dev *mass_device = fatd->dev;
2289#endif /* BUILDING_USBHDFSD */
2290#ifdef BUILDING_IEEE1394_DISK
2291 struct SBP2Device *mass_device = fatd->dev;
2292#endif /* BUILDING_IEEE1394_DISK */
2293
2294 // check wether we have enough clusters allocated
2295 i = fatd->partBpb.clusterSize * fatd->partBpb.sectorSize; // the size (in bytes) of the one cluster
2296 j = fatDir->size / i;
2297 if (fatDir->size % i) {
2298 j++;
2299 }
2300 if (j == 0)
2301 j = 1; // the file have allways at least one cluster allocated
2302
2303 endPosCluster = j * i;
2304 endPosFile = filePos + size;
2305
2306 *updateClusterIndices = 0;
2307
2308 // allocate additional cluster(s)
2309 if (endPosFile > endPosCluster) {
2310 unsigned int lastCluster;
2311
2312 ret = endPosFile - endPosCluster; // additional space needed in bytes
2313 j = ret / i; // additional space needed (given in number of clusters)
2314 if (ret % i) {
2315 j++;
2316 }
2317 lastCluster = fatDir->lastCluster;
2318 XPRINTF("I: writeFile: last cluster= %u \n", lastCluster);
2319
2320 if (lastCluster == 0)
2321 return -ENOSPC; // no more free clusters or data invalid
2322 for (i = 0; i < j; i++) {
2323 lastCluster = fat_getFreeCluster(fatd, lastCluster);
2324 if (lastCluster == 0)
2325 return -ENOSPC; // no more free clusters
2326 }
2327 fatDir->lastCluster = lastCluster;
2328 *updateClusterIndices = j;
2329 fat_invalidateLastChainResult(fatd); // prevent to misuse current (now deleted) fatd->cbuf
2330
2331 XPRINTF("I: writeFile: new clusters allocated = %u new lastCluster=%u \n", j, lastCluster);
2332 }
2333 XPRINTF("I: write file: filePos=%d dataSize=%d \n", filePos, size);
2334
2335
2336 fat_getClusterAtFilePos(fatd, fatDir, filePos, &fileCluster, &clusterPos);
2337 sectorSkip = (filePos - clusterPos) / fatd->partBpb.sectorSize;
2338 clusterSkip = sectorSkip / fatd->partBpb.clusterSize;
2339 sectorSkip %= fatd->partBpb.clusterSize;
2340 dataSkip = filePos % fatd->partBpb.sectorSize;
2341 bufferPos = 0;
2342
2343
2344 XPRINTF("fileCluster = %u, clusterPos= %u clusterSkip=%u, sectorSkip=%u dataSkip=%u \n",
2345 fileCluster, clusterPos, clusterSkip, sectorSkip, dataSkip);
2346
2347 if (fileCluster < 2) {
2348 return -EFAULT;
2349 }
2350
2351#if !defined(BUILDING_IEEE1394_DISK) && !defined(BUILDING_USBHDFSD)
2352 bufSize = fatd->bd->sectorSize;
2353#else
2354 bufSize = mass_device->sectorSize;
2355#endif
2356 nextChain = 1;
2357 clusterChainStart = 1;
2358
2359 while (nextChain && size > 0) {
2360 int chainSize;
2361
2362 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
2363 clusterChainStart = 0;
2364 if (chainSize >= MAX_DIR_CLUSTER) { // the chain is full, but more chain parts exist
2365 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
2366 } else { // chain fits in the chain buffer completely - no next chain needed
2367 nextChain = 0;
2368 }
2369 while (clusterSkip >= MAX_DIR_CLUSTER) {
2370 chainSize = fat_getClusterChain(fatd, fileCluster, fatd->cbuf, MAX_DIR_CLUSTER, clusterChainStart);
2371 clusterChainStart = 0;
2372 if (chainSize >= MAX_DIR_CLUSTER) { // the chain is full, but more chain parts exist
2373 fileCluster = fatd->cbuf[MAX_DIR_CLUSTER - 1];
2374 } else { // chain fits in the chain buffer completely - no next chain needed
2375 nextChain = 0;
2376 }
2377 clusterSkip -= MAX_DIR_CLUSTER;
2378 }
2379
2380 // process the cluster chain (fatd->cbuf) and skip leading clusters if needed
2381 for (i = 0 + clusterSkip; i < chainSize && size > 0; i++) {
2382 int startSector;
2383
2384 // read cluster and save cluster content
2385 startSector = fat_cluster2sector(&fatd->partBpb, fatd->cbuf[i]);
2386
2387#ifdef BUILDING_USBHDFSD
2388 /* Workaround for the PlayStation 2 OHCI USB controller errata:
2389 Do not do transfers via the bulk out pipe, with an unaligned buffer.
2390 The alternative is to open the pipe with sceUsbdOpenPipe(), which will
2391 limit split 63 or 64-byte frames to 62-bytes. However, not all devices
2392 are compatible with that workaround. */
2393 if (((u32)(buffer + bufferPos) & 3) == 0) {
2394 int toWrite;
2395
2396 // Calculate how long we can continuously write for.
2397 j = (size + dataSkip) / fatd->partBpb.sectorSize + sectorSkip;
2398 toWrite = 0;
2399 while (1) {
2400 if (j >= fatd->partBpb.clusterSize) {
2401 toWrite += fatd->partBpb.clusterSize;
2402 j -= fatd->partBpb.clusterSize;
2403 } else {
2404 toWrite += j;
2405 j = 0;
2406 }
2407
2408 // Check that the next cluster is adjacent to this one, so we can write across.
2409 if ((i >= chainSize - 1) || (fatd->cbuf[i] != (fatd->cbuf[i + 1] - 1)))
2410 break;
2411 if (j == 0)
2412 break;
2413 i++; // Advance to the next cluster.
2414 }
2415
2416 // Consider the number of sectors within the cluster to skip.
2417 startSector += sectorSkip;
2418 toWrite -= sectorSkip;
2419
2420 // process all sectors of the cluster (and skip leading sectors if needed)
2421 if (dataSkip > 0) {
2422 bufSize = mass_device->sectorSize - dataSkip;
2423 if (size < bufSize)
2424 bufSize = size;
2425
2426 ret = fat_writeSingleSector(fatd->dev, startSector, buffer + bufferPos, bufSize, dataSkip);
2427 if (ret != 1) {
2428 return bufferPos;
2429 }
2430
2431 if (size + dataSkip >= mass_device->sectorSize)
2432 toWrite--;
2433
2434 size -= bufSize;
2435 bufferPos += bufSize;
2436 dataSkip = 0;
2437 startSector++;
2438 }
2439
2440 if (toWrite > 0) {
2441 INVALIDATE_SECTORS(DEV_ACCESSOR(fatd), startSector, toWrite);
2442 ret = WRITE_SECTORS_RAW(DEV_ACCESSOR(fatd), startSector, toWrite, buffer + bufferPos);
2443 if (ret != 0) {
2444 XPRINTF("Write sectors failed ! sector=%u (%u)\n", startSector, toWrite);
2445 return bufferPos; // return number of bytes already written
2446 }
2447
2448 bufSize = toWrite * mass_device->sectorSize;
2449 size -= bufSize;
2450 bufferPos += bufSize;
2451 startSector += toWrite;
2452 }
2453
2454 if (size > 0 && size <= mass_device->sectorSize) {
2455 ret = fat_writeSingleSector(fatd->dev, startSector, buffer + bufferPos, size, 0);
2456 if (ret != 1) {
2457 return bufferPos;
2458 }
2459
2460 bufSize = size;
2461 size -= bufSize;
2462 bufferPos += bufSize;
2463 }
2464 } else {
2465 // Handle writes from an unaligned address.
2466 // process all sectors of the cluster (and skip leading sectors if needed)
2467 for (j = 0 + sectorSkip; j < fatd->partBpb.clusterSize && size > 0; j++) {
2468 // compute exact size of transfered bytes
2469 if (size < bufSize) {
2470 bufSize = size;
2471 }
2472 if (bufSize > mass_device->sectorSize - dataSkip) {
2473 bufSize = mass_device->sectorSize - dataSkip;
2474 }
2475
2476 ret = fat_writeSingleSector(fatd->dev, startSector + j, buffer + bufferPos, bufSize, dataSkip);
2477 if (ret != 1) {
2478 return bufferPos;
2479 }
2480
2481 size -= bufSize;
2482 bufferPos += bufSize;
2483 dataSkip = 0;
2484 bufSize = mass_device->sectorSize;
2485 }
2486 }
2487#else
2488 // process all sectors of the cluster (and skip leading sectors if needed)
2489 for (j = 0 + sectorSkip; j < fatd->partBpb.clusterSize && size > 0; j++) {
2490 unsigned char *sbuf = NULL; // sector buffer
2491
2492 // compute exact size of transfered bytes
2493 if (size < bufSize) {
2494 bufSize = size + dataSkip;
2495 }
2496#ifdef BUILDING_IEEE1394_DISK
2497 if (bufSize > mass_device->sectorSize) {
2498 bufSize = mass_device->sectorSize;
2499 }
2500#else
2501 if (bufSize > fatd->bd->sectorSize) {
2502 bufSize = fatd->bd->sectorSize;
2503 }
2504#endif
2505
2506 ret = READ_SECTOR(DEV_ACCESSOR(fatd), startSector + j, sbuf);
2507 if (ret < 0) {
2508 M_DEBUG("Read sector failed ! sector=%u\n", startSector + j);
2509 return bufferPos; // return number of bytes already written
2510 }
2511
2512 M_DEBUG("memcopy dst=%u, src=%u, size=%u bufSize=%u \n", dataSkip, bufferPos, bufSize - dataSkip, bufSize);
2513 memcpy(sbuf + dataSkip, buffer + bufferPos, bufSize - dataSkip);
2514 ret = WRITE_SECTOR(DEV_ACCESSOR(fatd), startSector + j);
2515 if (ret < 0) {
2516 M_DEBUG("Write sector failed ! sector=%u\n", startSector + j);
2517 return bufferPos; // return number of bytes already written
2518 }
2519
2520 size -= (bufSize - dataSkip);
2521 bufferPos += (bufSize - dataSkip);
2522 dataSkip = 0;
2523#ifdef BUILDING_IEEE1394_DISK
2524 bufSize = mass_device->sectorSize;
2525#else
2526 bufSize = fatd->bd->sectorSize;
2527#endif
2528 }
2529#endif /* BUILDING_USBHDFSD */
2530 sectorSkip = 0;
2531 }
2532 clusterSkip = 0;
2533 }
2534
2535 return bufferPos; // return number of bytes already written
2536}
2537
2538//---------------------------------------------------------------------------
2539int fat_flushSectors(fat_driver *fatd)
2540{
2541 FLUSH_SECTORS(DEV_ACCESSOR(fatd));
2542 return (0);
2543}
2544//---------------------------------------------------------------------------
2545// End of file: fat_write.c
2546//---------------------------------------------------------------------------
#define ENOENT
Definition errno.h:23
#define ENOSPC
Definition errno.h:75
#define EEXIST
Definition errno.h:53
#define EINVAL
Definition errno.h:63
#define EFAULT
Definition errno.h:47
#define ENAMETOOLONG
Definition errno.h:191
#define EIO
Definition errno.h:29
#define ENOTDIR
Definition errno.h:59
#define EMLINK
Definition errno.h:81
#define ENOTEMPTY
Definition errno.h:189
#define EACCES
Definition errno.h:45
#define EISDIR
Definition errno.h:61
int sceCdReadClock(sceCdCLOCK *clock)
Definition cdvdman.c:5821