OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [bootloaders/] [orpmon/] [common/] [dosfs.c] - Blame information for rev 709

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 389 tac2
/*
2
        DOSFS Embedded FAT-Compatible Filesystem
3
        (C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com)
4
 
5
        You are permitted to modify and/or use this code in your own projects without
6
        payment of royalty, regardless of the license(s) you choose for those projects.
7
 
8
        You cannot re-copyright or restrict use of the code as released by Lewin Edwards.
9 406 julius
*/
10
 
11 389 tac2
/*
12
  @2010, adam.edvardsson@orsoc.se
13
  Added local copy of the functions,
14
   div_t, memcmp2,strcpy2,strcmp2. The one from the string library is not comatible
15
 
16 406 julius
*/
17
 
18 389 tac2
 
19
//#include <string.h>
20
//#include <stdlib.h>
21
//#include "or32_utils.h"
22
#include "dosfs.h"
23
#include "sdc.h"
24 406 julius
 
25 389 tac2
#include "common.h"
26
#include "support.h"
27
#include "uart.h"
28 406 julius
 
29
 
30
 
31
unsigned long int init_fat(VOLINFO * vis)
32
{
33
 
34
 
35
 
36
 
37
unsigned char sector[SECTOR_SIZE];
38
 
39
unsigned long int pstart, psize, i, fisz;
40
 
41
unsigned char pactive, ptype;
42
 
43
VOLINFO vi;
44
 
45
 
46 389 tac2
 
47 406 julius
            //uart_init(DEFAULT_UART);
48
            printf("FAT INIT START\n");
49
 
50
memCardInit();
51
 
52
 
53
 
54
pstart = DFS_GetPtnStart(0, sector, 0, &pactive, &ptype, &psize);
55
 
56
if (pstart == 0xffffffff) {
57
 
58
printf("Cannot find first partition\n");
59
 
60
return -1;
61
 
62
}
63
 
64
 
65
printf
66
            ("Partition 0 start sector 0x%-08.8lX active %-02.2hX type %-02.2hX size %-08.8lX\n",
67
             pstart, pactive, ptype, psize);
68
 
69
 
70
if (DFS_GetVolInfo(0, sector, pstart, &vi)) {
71
 
72
printf("Error getting volume information\n");
73
 
74
return -1;
75
 
76
}
77
 
78
 
79
 
80
 
81
 
82
*vis = vi;
83
 
84
 
85
 
86
 
87
}
88
 
89
 
90
 
91
 
92
unsigned long int DFS_ReadSector(unsigned char unit, unsigned char *buffer,
93
                                    unsigned long int sector,
94
                                    unsigned long int count)
95
{
96
 
97
 
98
unsigned long int block_add = 0;
99
 
100
int i;
101
 
102
 
103
 
104
 
105
for (i = 0; i < count; i++) {
106
 
107
block_add = sector + i;
108
 
109
DBGA("\n readSector %u, block_addr %u \n", sector, block_add);
110
 
111
setup_bd_transfer(READ_OP, block_add, buffer);
112
 
113
if (finnish_bd_transfer() == FALSE)
114
 
115
return 0xff;
116
 
117
 
118
}
119
 
120
 
121
return 0;
122
 
123
 
124
}
125
 
126
 
127
 
128
 
129
unsigned long int DFS_WriteSector(unsigned char unit, unsigned char *buffer,
130
                                     unsigned long int sector,
131
                                     unsigned long int count)
132
{
133
 
134
 
135
 
136
unsigned long int block_add = 0;
137
 
138
unsigned char scr[SECTOR_SIZE];
139
 
140
 
141
block_add = sector;
142
 
143
DBGA("\n writeSector %u, block_addr2 %u \n", sector, block_add);
144
 
145
setup_bd_transfer(WRITE_OP, block_add, buffer);
146
 
147
 
148
if (finnish_bd_transfer() == FALSE) {
149
 
150
printf("TRANSACTION FAILED, Buffer %x \n", buffer);
151
 
152 389 tac2
 
153 406 julius
                    //reset_card();  
154
                    // sd_wait_rsp();
155
                    // SD_REG(SD_SOFTWARE_RST)=1; 
156
 
157
                    //SD_REG(SD_SOFTWARE_RST)=0; 
158
 
159
 
160
DBGA("FREE BD TX/RX: 0x%x \n", SD_REG(BD_STATUS));
161
 
162
 
163
 
164
DBGA("TRY READ SECTOR \n");
165
 
166
setup_bd_transfer(READ_OP, 526571008, scr);
167
 
168
finnish_bd_transfer();
169
 
170
DBGA("PRINT test wreite to 526571008 \n");
171
 
172
setup_bd_transfer(WRITE_OP, 526571008, scr);
173
 
174
finnish_bd_transfer();
175
 
176
 
177
setup_bd_transfer(WRITE_OP, block_add, buffer);
178
 
179
if (finnish_bd_transfer() == FALSE) {
180
 
181
printf("TRANSACTION FAILED AGAIN!, Buffer %x \n",
182
                                buffer);
183
 
184
return 0xff;
185
 
186
}
187
 
188
 
189
}
190
 
191
 
192
 
193
return 0;
194
 
195
 
196
}
197
 
198
 
199 389 tac2
 
200
/*
201
        Get starting sector# of specified partition on drive #unit
202
        NOTE: This code ASSUMES an MBR on the disk.
203
        scratchsector should point to a SECTOR_SIZE scratch area
204
        Returns 0xffffffff for any error.
205
        If pactive is non-NULL, this function also returns the partition active flag.
206
        If pptype is non-NULL, this function also returns the partition type.
207
        If psize is non-NULL, this function also returns the partition size.
208 406 julius
*/
209
 
210
 
211
unsigned long int DFS_GetPtnStart(unsigned char unit,
212
                                    unsigned char *scratchsector,
213
                                    unsigned char pnum, unsigned char *pactive,
214
                                    unsigned char *pptype,
215
                                    unsigned long int *psize)
216
{
217
 
218
unsigned long int result;
219
 
220
PMBR mbr = (PMBR) scratchsector;
221
 
222 389 tac2
 
223 406 julius
            // DOS ptable supports maximum 4 partitions
224
            if (pnum > 3)
225
 
226
return DFS_ERRMISC;
227
 
228 389 tac2
 
229 406 julius
            // Read MBR from target media
230
            if (DFS_ReadSector(unit, scratchsector, 0, 1)) {
231
 
232
return DFS_ERRMISC;
233
 
234
}
235
 
236
 
237
result = (unsigned long int)mbr->ptable[pnum].start_0 |
238
            (((unsigned long int)mbr->ptable[pnum].start_1) << 8) |
239
            (((unsigned long int)mbr->ptable[pnum].start_2) << 16) |
240
            (((unsigned long int)mbr->ptable[pnum].start_3) << 24);
241
 
242
 
243 389 tac2
 
244 406 julius
            //unsigned char              active;                 // 0x80 if partition active
245
            //unsigned char         start_h;                // starting head
246
            //unsigned char         start_cs_l;             // starting cylinder and sector (low byte)
247
            //unsigned char         start_cs_h;             // starting cylinder and sector (high byte)
248
 
249
printf("active 0:%x 1:%x 2:%x 3:%x \n", mbr->ptable[pnum].active,
250
                    mbr->ptable[pnum].start_h, mbr->ptable[pnum].start_cs_l,
251
                    mbr->ptable[pnum].start_cs_h);
252
 
253
 
254
printf("start 0:%x 1:%x 2:%x 3:%x \n", mbr->ptable[pnum].start_0,
255
                 mbr->ptable[pnum].start_1, mbr->ptable[pnum].start_2,
256
                 mbr->ptable[pnum].start_3);
257
 
258
if (pactive)
259
 
260
*pactive = mbr->ptable[pnum].active;
261
 
262
 
263
if (pptype)
264
 
265
*pptype = mbr->ptable[pnum].type;
266
 
267
 
268
if (psize) {
269
 
270
*psize = (unsigned long int)mbr->ptable[pnum].size_0 |
271
                    (((unsigned long int)mbr->ptable[pnum].size_1) << 8) |
272
                    (((unsigned long int)mbr->ptable[pnum].size_2) << 16) |
273
                    (((unsigned long int)mbr->ptable[pnum].size_3) << 24);
274
 
275
printf("size 0:%x 1:%x 2:%x 3:%x \n", mbr->ptable[pnum].size_0,
276
                        mbr->ptable[pnum].size_1, mbr->ptable[pnum].size_2,
277
                        mbr->ptable[pnum].size_3);
278
 
279
}
280
 
281
 
282
return result;
283
 
284
}
285
 
286
 
287
 
288
 
289
 
290
ldiv_t ldiv(long int numer, long int denom)
291
{
292
 
293
ldiv_t result;
294
 
295
 
296
result.quot = numer / denom;
297
 
298
result.rem = numer % denom;
299
 
300 389 tac2
 
301 406 julius
            /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
302
               NUMER / DENOM is to be computed in infinite precision.  In
303
               other words, we should always truncate the quotient towards
304
               zero, never -infinity.  Machine division and remainer may
305
               work either way when one or both of NUMER or DENOM is
306
               negative.  If only one is negative and QUOT has been
307
               truncated towards -infinity, REM will have the same sign as
308
               DENOM and the opposite sign of NUMER; if both are negative
309
               and QUOT has been truncated towards -infinity, REM will be
310
               positive (will have the opposite sign of NUMER).  These are
311
               considered `wrong'.  If both are NUM and DENOM are positive,
312
               RESULT will always be positive.  This all boils down to: if
313
               NUMER >= 0, but REM < 0, we got the wrong answer.  In that
314
               case, to get the right answer, add 1 to QUOT and subtract
315
               DENOM from REM.  */
316
 
317
if (numer >= 0 && result.rem < 0)
318
 
319
 {
320
 
321
++result.quot;
322
 
323
result.rem -= denom;
324
 
325
}
326
 
327
 
328
return result;
329
 
330
}
331
 
332
 
333
 
334
div_t div(int numer, int denom)
335
{
336
 
337
div_t result;
338
 
339
 
340
result.quot = numer / denom;
341
 
342
result.rem = numer % denom;
343
 
344 389 tac2
 
345 406 julius
            /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
346
               NUMER / DENOM is to be computed in infinite precision.  In
347
               other words, we should always truncate the quotient towards
348
               zero, never -infinity.  Machine division and remainer may
349
               work either way when one or both of NUMER or DENOM is
350
               negative.  If only one is negative and QUOT has been
351
               truncated towards -infinity, REM will have the same sign as
352
               DENOM and the opposite sign of NUMER; if both are negative
353
               and QUOT has been truncated towards -infinity, REM will be
354
               positive (will have the opposite sign of NUMER).  These are
355
               considered `wrong'.  If both are NUM and DENOM are positive,
356
               RESULT will always be positive.  This all boils down to: if
357
               NUMER >= 0, but REM < 0, we got the wrong answer.  In that
358
               case, to get the right answer, add 1 to QUOT and subtract
359
               DENOM from REM.  */
360
 
361
if (numer >= 0 && result.rem < 0)
362
 
363
 {
364
 
365
++result.quot;
366
 
367
result.rem -= denom;
368
 
369
}
370
 
371
 
372
return result;
373
 
374
}
375
 
376 389 tac2
 
377
/*
378
        Retrieve volume info from BPB and store it in a VOLINFO structure
379
        You must provide the unit and starting sector of the filesystem, and
380
        a pointer to a sector buffer for scratch
381
        Attempts to read BPB and glean information about the FS from that.
382
        Returns 0 OK, nonzero for any error.
383 406 julius
*/
384
unsigned long int DFS_GetVolInfo(unsigned char unit,
385
                                 unsigned char *scratchsector,
386
                                 unsigned long int startsector,
387
                                 PVOLINFO volinfo)
388
{
389
 
390
PLBR lbr = (PLBR) scratchsector;
391
 
392
volinfo->unit = unit;
393
 
394
volinfo->startsector = startsector;
395
 
396
 
397
if (DFS_ReadSector(unit, scratchsector, startsector, 1))
398
 
399
return DFS_ERRMISC;
400
 
401 389 tac2
 
402
// tag: OEMID, refer dosfs.h
403 406 julius
//      strncpy(volinfo->oemid, lbr->oemid, 8);
404
//      volinfo->oemid[8] = 0;
405
 
406
volinfo->secperclus = lbr->bpb.secperclus;
407
 
408
volinfo->reservedsecs = (unsigned short)lbr->bpb.reserved_l |
409
            (((unsigned short)lbr->bpb.reserved_h) << 8);
410
 
411
 
412
volinfo->numsecs = (unsigned short)lbr->bpb.sectors_s_l |
413
            (((unsigned short)lbr->bpb.sectors_s_h) << 8);
414
 
415
 
416
if (!volinfo->numsecs)
417
 
418
volinfo->numsecs = (unsigned long int)lbr->bpb.sectors_l_0 |
419
                    (((unsigned long int)lbr->bpb.sectors_l_1) << 8) |
420
                    (((unsigned long int)lbr->bpb.sectors_l_2) << 16) |
421
                    (((unsigned long int)lbr->bpb.sectors_l_3) << 24);
422
 
423 389 tac2
 
424 406 julius
            // If secperfat is 0, we must be in a FAT32 volume; get secperfat
425
            // from the FAT32 EBPB. The volume label and system ID string are also
426
            // in different locations for FAT12/16 vs FAT32.
427
            volinfo->secperfat = (unsigned short)lbr->bpb.secperfat_l |
428
            (((unsigned short)lbr->bpb.secperfat_h) << 8);
429
 
430
if (!volinfo->secperfat) {
431
 
432
volinfo->secperfat =
433
                    (unsigned long int)lbr->ebpb.ebpb32.
434
                    fatsize_0 |
435
 
436
(((unsigned long int)lbr->ebpb.ebpb32.
437
                       fatsize_1) << 8) |
438
(((unsigned long int)lbr->ebpb.
439
                                             ebpb32.
440
                                             fatsize_2) << 16) |
441
(((unsigned
442
                                                                     long int)
443
                                                                    lbr->ebpb.
444
                                                                    ebpb32.
445
                                                                    fatsize_3)
446
                                                                   << 24);
447
 
448
 
449
memcpy(volinfo->label, lbr->ebpb.ebpb32.label, 11);
450
 
451
volinfo->label[11] = 0;
452
 
453 389 tac2
 
454
// tag: OEMID, refer dosfs.h
455 406 julius
//              memcpy(volinfo->system, lbr->ebpb.ebpb32.system, 8);
456
//              volinfo->system[8] = 0; 
457
        }
458 389 tac2
 
459 406 julius
        else {
460
 
461
memcpy(volinfo->label, lbr->ebpb.ebpb.label, 11);
462
 
463
volinfo->label[11] = 0;
464
 
465
 
466 389 tac2
// tag: OEMID, refer dosfs.h
467 406 julius
//              memcpy(volinfo->system, lbr->ebpb.ebpb.system, 8);
468
//              volinfo->system[8] = 0; 
469
        }
470
 
471 389 tac2
 
472 406 julius
            // note: if rootentries is 0, we must be in a FAT32 volume.
473
            volinfo->rootentries = (unsigned short)lbr->bpb.rootentries_l |
474
            (((unsigned short)lbr->bpb.rootentries_h) << 8);
475
 
476 389 tac2
 
477 406 julius
            // after extracting raw info we perform some useful precalculations
478
            volinfo->fat1 = startsector + volinfo->reservedsecs;
479
 
480 389 tac2
 
481 406 julius
            // The calculation below is designed to round up the root directory size for FAT12/16
482
            // and to simply ignore the root directory for FAT32, since it's a normal, expandable
483
            // file in that situation.
484
            if (volinfo->rootentries) {
485
 
486
volinfo->rootdir = volinfo->fat1 + (volinfo->secperfat * 2);
487
 
488
volinfo->dataarea =
489
                    volinfo->rootdir +
490
                    (((volinfo->rootentries * 32) +
491
                      (SECTOR_SIZE - 1)) / SECTOR_SIZE);
492
 
493
}
494
 
495
        else {
496
 
497
volinfo->dataarea = volinfo->fat1 + (volinfo->secperfat * 2);
498
 
499
volinfo->rootdir =
500
                    (unsigned long int)lbr->ebpb.ebpb32.
501
                    root_0 |
502
(((unsigned long int)lbr->ebpb.ebpb32.root_1) <<
503
                               8) |
504
(((unsigned long int)lbr->ebpb.ebpb32.
505
                                       root_2) << 16) |
506
(((unsigned long int)
507
                                                           lbr->ebpb.ebpb32.
508
                                                           root_3) << 24);
509
 
510
}
511 389 tac2
 
512 406 julius
            // Calculate number of clusters in data area and infer FAT type from this information.
513
            volinfo->numclusters =
514
            (volinfo->numsecs - volinfo->dataarea) / volinfo->secperclus;
515
 
516
if (volinfo->numclusters < 4085)
517
 
518
volinfo->filesystem = FAT12;
519
 
520
        else if (volinfo->numclusters < 65525)
521
 
522
volinfo->filesystem = FAT16;
523
 
524
        else
525
 
526
volinfo->filesystem = FAT32;
527
 
528
 
529
return DFS_OK;
530
 
531
}
532
 
533
 
534 389 tac2
 
535
/*
536
        Fetch FAT entry for specified cluster number
537
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
538
        Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
539
        FAT entry.
540
        scratchcache should point to a UINT32. This variable caches the physical sector number
541
        last read into the scratch buffer for performance enhancement reasons.
542 406 julius
*/
543
unsigned long int DFS_GetFAT(PVOLINFO volinfo, unsigned char *scratch,
544
                             unsigned long int *scratchcache,
545
                             unsigned long int cluster)
546
{
547
 
548
unsigned long int offset, sector, result;
549
 
550
 
551
if (volinfo->filesystem == FAT12) {
552
 
553
offset = cluster + (cluster / 2);
554
 
555
}
556
 
557
        else if (volinfo->filesystem == FAT16) {
558
 
559
offset = cluster * 2;
560
 
561
}
562
 
563
        else if (volinfo->filesystem == FAT32) {
564
 
565
offset = cluster * 4;
566
 
567
}
568
 
569
        else
570
 
571
return 0x0ffffff7;      // FAT32 bad cluster    
572
 
573
            // at this point, offset is the BYTE offset of the desired sector from the start
574
            // of the FAT. Calculate the physical sector containing this FAT entry.
575
            sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
576
 
577 389 tac2
 
578 406 julius
            // If this is not the same sector we last read, then read it into RAM
579
            if (sector != *scratchcache) {
580
 
581
if (DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
582
 
583
                            // avoid anyone assuming that this cache value is still valid, which
584
                            // might cause disk corruption
585
                            *scratchcache = 0;
586
 
587
return 0x0ffffff7;      // FAT32 bad cluster    
588
                }
589
 
590
*scratchcache = sector;
591
 
592
}
593
 
594 389 tac2
 
595 406 julius
            // At this point, we "merely" need to extract the relevant entry.
596
            // This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
597
            // may span a sector boundary. The normal way around this is always to read two
598
            // FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
599
            offset = ldiv(offset, SECTOR_SIZE).rem;
600
 
601
 
602
if (volinfo->filesystem == FAT12) {
603
 
604
                    // Special case for sector boundary - Store last byte of current sector.
605
                    // Then read in the next sector and put the first byte of that sector into
606
                    // the high byte of result.
607
                    if (offset == SECTOR_SIZE - 1) {
608
 
609
result = (unsigned long int)scratch[offset];
610
 
611
sector++;
612
 
613
if (DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
614
 
615
                                    // avoid anyone assuming that this cache value is still valid, which
616
                                    // might cause disk corruption
617
                                    *scratchcache = 0;
618
 
619
return 0x0ffffff7;      // FAT32 bad cluster    
620
                        }
621
 
622
*scratchcache = sector;
623
 
624
                            // Thanks to Claudio Leonel for pointing out this missing line.
625
                            result |= ((unsigned long int)scratch[0]) << 8;
626
 
627
}
628
 
629
                else {
630
 
631
result = (unsigned long int)scratch[offset] |
632
                            ((unsigned long int)scratch[offset + 1]) << 8;
633
 
634
}
635
if (cluster & 1)
636
 
637
result = result >> 4;
638
 
639
                else
640
 
641
result = result & 0xfff;
642
 
643
}
644
 
645
        else if (volinfo->filesystem == FAT16) {
646
 
647
result = (unsigned long int)scratch[offset] |
648
                    ((unsigned long int)scratch[offset + 1]) << 8;
649
 
650
}
651
 
652
        else if (volinfo->filesystem == FAT32) {
653
 
654
result = ((unsigned long int)scratch[offset] |
655
                           ((unsigned long int)scratch[offset + 1]) << 8 |
656
                           ((unsigned long int)scratch[offset + 2]) << 16 |
657
                           ((unsigned long int)scratch[offset + 3]) << 24) &
658
                    0x0fffffff;
659
 
660
}
661
 
662
        else
663
 
664
result = 0x0ffffff7;    // FAT32 bad cluster    
665
        return result;
666
 
667
}
668
 
669
 
670
 
671 389 tac2
 
672
/*
673
        Set FAT entry for specified cluster number
674
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
675
        Returns DFS_ERRMISC for any error, otherwise DFS_OK
676
        scratchcache should point to a UINT32. This variable caches the physical sector number
677
        last read into the scratch buffer for performance enhancement reasons.
678
 
679
        NOTE: This code is HIGHLY WRITE-INEFFICIENT, particularly for flash media. Considerable
680
        performance gains can be realized by caching the sector. However this is difficult to
681
        achieve on FAT12 without requiring 2 sector buffers of scratch space, and it is a design
682
        requirement of this code to operate on a single 512-byte scratch.
683
 
684
        If you are operating DOSFS over flash, you are strongly advised to implement a writeback
685
        cache in your physical I/O driver. This will speed up your code significantly and will
686
        also conserve power and flash write life.
687 406 julius
*/
688
unsigned long int DFS_SetFAT(PVOLINFO volinfo, unsigned char *scratch,
689
                             unsigned long int *scratchcache,
690
                             unsigned long int cluster,
691
                             unsigned long int new_contents)
692
{
693
 
694
unsigned long int offset, sector, result;
695
 
696
if (volinfo->filesystem == FAT12) {
697
 
698
offset = cluster + (cluster / 2);
699
 
700
new_contents &= 0xfff;
701
 
702
}
703
 
704
        else if (volinfo->filesystem == FAT16) {
705
 
706
offset = cluster * 2;
707
 
708
new_contents &= 0xffff;
709
 
710
}
711
 
712
        else if (volinfo->filesystem == FAT32) {
713
 
714
offset = cluster * 4;
715
 
716
new_contents &= 0x0fffffff;     // FAT32 is really "FAT28"
717
        }
718
 
719
        else
720
 
721
return DFS_ERRMISC;
722
 
723 389 tac2
 
724 406 julius
            // at this point, offset is the BYTE offset of the desired sector from the start
725
            // of the FAT. Calculate the physical sector containing this FAT entry.
726
            sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
727
 
728 389 tac2
 
729 406 julius
            // If this is not the same sector we last read, then read it into RAM
730
            if (sector != *scratchcache) {
731
 
732
if (DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
733
 
734
                            // avoid anyone assuming that this cache value is still valid, which
735
                            // might cause disk corruption
736
                            *scratchcache = 0;
737
 
738
return DFS_ERRMISC;
739
 
740
}
741
 
742
*scratchcache = sector;
743
 
744
}
745
 
746 389 tac2
 
747 406 julius
            // At this point, we "merely" need to extract the relevant entry.
748
            // This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
749
            // may span a sector boundary. The normal way around this is always to read two
750
            // FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
751
            offset = ldiv(offset, SECTOR_SIZE).rem;
752
 
753
 
754
if (volinfo->filesystem == FAT12) {
755
 
756 389 tac2
 
757 406 julius
                    // If this is an odd cluster, pre-shift the desired new contents 4 bits to
758
                    // make the calculations below simpler
759
                    if (cluster & 1)
760
 
761
new_contents = new_contents << 4;
762
 
763 389 tac2
 
764 406 julius
                    // Special case for sector boundary
765
                    if (offset == SECTOR_SIZE - 1) {
766
 
767 389 tac2
 
768 406 julius
                            // Odd cluster: High 12 bits being set
769
                            if (cluster & 1) {
770
 
771
scratch[offset] =
772
                                    (scratch[offset] & 0x0f) | new_contents &
773
                                    0xf0;
774
 
775
}
776
 
777
                            // Even cluster: Low 12 bits being set
778
                            else {
779
 
780
scratch[offset] = new_contents & 0xff;
781
 
782
}
783
 
784
result =
785
                            DFS_WriteSector(volinfo->unit, scratch,
786
                                            *scratchcache, 1);
787
 
788
                            // mirror the FAT into copy 2
789
                            if (DFS_OK == result)
790
 
791
result =
792
                                    DFS_WriteSector(volinfo->unit, scratch,
793
                                                    (*scratchcache) +
794
                                                    volinfo->secperfat, 1);
795
 
796 389 tac2
 
797 406 julius
                            // If we wrote that sector OK, then read in the subsequent sector
798
                            // and poke the first byte with the remainder of this FAT entry.
799
                            if (DFS_OK == result) {
800
 
801
*scratchcache++;
802
 
803
result =
804
                                    DFS_ReadSector(volinfo->unit, scratch,
805
                                                   *scratchcache, 1);
806
 
807
if (DFS_OK == result) {
808
 
809
                                            // Odd cluster: High 12 bits being set
810
                                            if (cluster & 1) {
811
 
812
scratch[0] =
813
                                                    new_contents & 0xff00;
814
 
815
}
816
 
817
                                            // Even cluster: Low 12 bits being set
818
                                            else {
819
 
820
scratch[0] =
821
                                                    (scratch[0] & 0xf0) |
822
                                                    new_contents & 0x0f;
823
 
824
}
825
 
826
result =
827
                                            DFS_WriteSector(volinfo->unit,
828
                                                            scratch,
829
                                                            *scratchcache, 1);
830
 
831
                                            // mirror the FAT into copy 2
832
                                            if (DFS_OK == result)
833
 
834
result =
835
                                                    DFS_WriteSector(volinfo->
836
                                                                    unit,
837
                                                                    scratch,
838
                                                                    (*scratchcache)
839
                                                                    +
840
                                                                    volinfo->
841
                                                                    secperfat,
842
                                                                    1);
843
 
844
}
845
 
846
                                else {
847
 
848
                                            // avoid anyone assuming that this cache value is still valid, which
849
                                            // might cause disk corruption
850
                                            *scratchcache = 0;
851
 
852
}
853
 
854
}
855
 
856
}               // if (offset == SECTOR_SIZE - 1)
857
 
858
                    // Not a sector boundary. But we still have to worry about if it's an odd
859
                    // or even cluster number.
860
                    else {
861
 
862
                            // Odd cluster: High 12 bits being set
863
                            if (cluster & 1) {
864
 
865
scratch[offset] =
866
                                    (scratch[offset] & 0x0f) | new_contents &
867
                                    0xf0;
868
 
869
scratch[offset + 1] = new_contents & 0xff00;
870
 
871
}
872
 
873
                            // Even cluster: Low 12 bits being set
874
                            else {
875
 
876
scratch[offset] = new_contents & 0xff;
877
 
878
scratch[offset + 1] =
879
                                    (scratch[offset + 1] & 0xf0) | new_contents
880
                                    & 0x0f;
881
 
882
}
883
 
884
result =
885
                            DFS_WriteSector(volinfo->unit, scratch,
886
                                            *scratchcache, 1);
887
 
888
                            // mirror the FAT into copy 2
889
                            if (DFS_OK == result)
890
 
891
result =
892
                                    DFS_WriteSector(volinfo->unit, scratch,
893
                                                    (*scratchcache) +
894
                                                    volinfo->secperfat, 1);
895
 
896
}
897
 
898
}
899
 
900
        else if (volinfo->filesystem == FAT16) {
901
 
902
scratch[offset] = (new_contents & 0xff);
903
 
904
scratch[offset + 1] = (new_contents & 0xff00) >> 8;
905
 
906
result =
907
                    DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
908
 
909
                    // mirror the FAT into copy 2
910
                    if (DFS_OK == result)
911
 
912
result =
913
                            DFS_WriteSector(volinfo->unit, scratch,
914
                                            (*scratchcache) +
915
                                            volinfo->secperfat, 1);
916
 
917
}
918
 
919
        else if (volinfo->filesystem == FAT32) {
920
 
921
scratch[offset] = (new_contents & 0xff);
922
 
923
scratch[offset + 1] = (new_contents & 0xff00) >> 8;
924
 
925
scratch[offset + 2] = (new_contents & 0xff0000) >> 16;
926
 
927
scratch[offset + 3] =
928
                    (scratch[offset + 3] & 0xf0) | ((new_contents & 0x0f000000)
929
                                                    >> 24);
930
 
931
                    // Note well from the above: Per Microsoft's guidelines we preserve the upper
932
                    // 4 bits of the FAT32 cluster value. It's unclear what these bits will be used
933
                    // for; in every example I've encountered they are always zero.
934
                    result =
935
                    DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
936
 
937
                    // mirror the FAT into copy 2
938
                    if (DFS_OK == result)
939
 
940
result =
941
                            DFS_WriteSector(volinfo->unit, scratch,
942
                                            (*scratchcache) +
943
                                            volinfo->secperfat, 1);
944
 
945
}
946
 
947
        else
948
 
949
result = DFS_ERRMISC;
950
 
951
 
952
return result;
953
 
954
}
955
 
956
 
957 389 tac2
 
958
/*
959
        Convert a filename element from canonical (8.3) to directory entry (11) form
960
        src must point to the first non-separator character.
961
        dest must point to a 12-byte buffer.
962 406 julius
*/
963
unsigned char *DFS_CanonicalToDir(unsigned char *dest, unsigned char *src)
964
{
965
 
966
unsigned char *destptr = dest;
967
 
968
 
969
memset(dest, ' ', 11);
970
 
971
dest[11] = 0;
972
 
973
 
974
while (*src && (*src != DIR_SEPARATOR) && (destptr - dest < 11)) {
975
 
976
if (*src >= 'a' && *src <= 'z') {
977
 
978
*destptr++ = (*src - 'a') + 'A';
979
 
980
src++;
981
 
982
}
983
 
984
                else if (*src == '.') {
985
 
986
src++;
987
 
988
destptr = dest + 8;
989
 
990
}
991
 
992
                else {
993
 
994
*destptr++ = *src++;
995
 
996
}
997
 
998
}
999
 
1000
 
1001
return dest;
1002
 
1003
}
1004
 
1005
 
1006 389 tac2
 
1007
/*
1008
        Find the first unused FAT entry
1009
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
1010
        Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
1011
        FAT entry.
1012
        Returns FAT32 bad_sector (0x0ffffff7) if there is no free cluster available
1013 406 julius
*/
1014
unsigned long int DFS_GetFreeFAT(PVOLINFO volinfo, unsigned char *scratch)
1015
{
1016
 
1017
unsigned long int i, result = 0xffffffff, scratchcache = 0;
1018
 
1019 389 tac2
 
1020 406 julius
            // Search starts at cluster 2, which is the first usable cluster
1021
            // NOTE: This search can't terminate at a bad cluster, because there might
1022
            // legitimately be bad clusters on the disk.
1023
            for (i = 2; i < volinfo->numclusters; i++) {
1024
 
1025
result = DFS_GetFAT(volinfo, scratch, &scratchcache, i);
1026
 
1027
if (!result) {
1028
 
1029
return i;
1030
 
1031
}
1032
 
1033
}
1034
 
1035
return 0x0ffffff7;      // Can't find a free cluster
1036
}
1037
 
1038
 
1039
 
1040 389 tac2
 
1041
/*
1042
        Open a directory for enumeration by DFS_GetNextDirEnt
1043
        You must supply a populated VOLINFO (see DFS_GetVolInfo)
1044
        The empty string or a string containing only the directory separator are
1045
        considered to be the root directory.
1046
        Returns 0 OK, nonzero for any error.
1047 406 julius
*/
1048
unsigned long int DFS_OpenDir(PVOLINFO volinfo, unsigned char *dirname,
1049
                              PDIRINFO dirinfo)
1050
{
1051
 
1052
            // Default behavior is a regular search for existing entries
1053
            dirinfo->flags = 0;
1054
 
1055
 
1056
if (!strlen((char *)dirname)
1057
              || (strlen((char *)dirname) == 1
1058
                  && dirname[0] == DIR_SEPARATOR)) {
1059
 
1060
if (volinfo->filesystem == FAT32) {
1061
 
1062
dirinfo->currentcluster = volinfo->rootdir;
1063
 
1064
dirinfo->currentsector = 0;
1065
 
1066
dirinfo->currententry = 0;
1067
 
1068 389 tac2
 
1069 406 julius
                            // read first sector of directory
1070
                            return DFS_ReadSector(volinfo->unit,
1071
                                                  dirinfo->scratch,
1072
                                                  volinfo->dataarea +
1073
                                                  ((volinfo->rootdir -
1074
                                                    2) * volinfo->secperclus),
1075
                                                  1);
1076
 
1077
}
1078
 
1079
                else {
1080
 
1081
dirinfo->currentcluster = 0;
1082
 
1083
dirinfo->currentsector = 0;
1084
 
1085
dirinfo->currententry = 0;
1086
 
1087 389 tac2
 
1088 406 julius
                            // read first sector of directory
1089
                            return DFS_ReadSector(volinfo->unit,
1090
                                                  dirinfo->scratch,
1091
                                                  volinfo->rootdir, 1);
1092
 
1093
}
1094
 
1095
}
1096
 
1097 389 tac2
 
1098 406 julius
            // This is not the root directory. We need to find the start of this subdirectory.
1099
            // We do this by devious means, using our own companion function DFS_GetNext.
1100
            else {
1101
 
1102
unsigned char tmpfn[12];
1103
 
1104
unsigned char *ptr = dirname;
1105
 
1106
unsigned long int result;
1107
 
1108
DIRENT de;
1109
 
1110
 
1111
if (volinfo->filesystem == FAT32) {
1112
 
1113
dirinfo->currentcluster = volinfo->rootdir;
1114
 
1115
dirinfo->currentsector = 0;
1116
 
1117
dirinfo->currententry = 0;
1118
 
1119 389 tac2
 
1120 406 julius
                            // read first sector of directory
1121
                            if (DFS_ReadSector
1122
                                (volinfo->unit, dirinfo->scratch,
1123
                                 volinfo->dataarea +
1124
                                 ((volinfo->rootdir - 2) * volinfo->secperclus),
1125
                                 1))
1126
 
1127
return DFS_ERRMISC;
1128
 
1129
}
1130
 
1131
                else {
1132
 
1133
dirinfo->currentcluster = 0;
1134
 
1135
dirinfo->currentsector = 0;
1136
 
1137
dirinfo->currententry = 0;
1138
 
1139 389 tac2
 
1140 406 julius
                            // read first sector of directory
1141
                            if (DFS_ReadSector
1142
                                (volinfo->unit, dirinfo->scratch,
1143
                                 volinfo->rootdir, 1))
1144
 
1145
return DFS_ERRMISC;
1146
 
1147
}
1148
 
1149 389 tac2
 
1150 406 julius
                    // skip leading path separators
1151
                    while (*ptr == DIR_SEPARATOR && *ptr)
1152
 
1153
ptr++;
1154
 
1155 389 tac2
 
1156 406 julius
                    // Scan the path from left to right, finding the start cluster of each entry
1157
                    // Observe that this code is inelegant, but obviates the need for recursion.
1158
                    while (*ptr) {
1159
 
1160
DFS_CanonicalToDir(tmpfn, ptr);
1161
 
1162
 
1163
de.name[0] = 0;
1164
 
1165 389 tac2
 
1166 406 julius
                        do {
1167
 
1168
result = DFS_GetNext(volinfo, dirinfo, &de);
1169
 
1170
} while (!result && memcmp2(de.name, tmpfn, 11));
1171
 
1172
 
1173
if (!memcmp2(de.name, tmpfn, 11)
1174
                              && ((de.attr & ATTR_DIRECTORY) ==
1175
                                  ATTR_DIRECTORY)) {
1176
 
1177
if (volinfo->filesystem == FAT32) {
1178
 
1179
dirinfo->currentcluster =
1180
                                            (unsigned long int)de.
1181
                                            startclus_l_l |
1182
 
1183
((unsigned long int)de.
1184
                                              startclus_l_h) << 8 |
1185
((unsigned
1186
                                                                       long int)
1187
                                                                      de.
1188
                                                                      startclus_h_l)
1189
                                            << 16 |
1190
((unsigned long int)de.
1191
                                                      startclus_h_h) << 24;
1192
 
1193
}
1194
 
1195
                                else {
1196
 
1197
dirinfo->currentcluster =
1198
                                            (unsigned long int)de.
1199
                                            startclus_l_l |
1200
 
1201
((unsigned long int)de.
1202
                                              startclus_l_h) << 8;
1203
 
1204
}
1205
dirinfo->currentsector = 0;
1206
 
1207
dirinfo->currententry = 0;
1208
 
1209
 
1210
if (DFS_ReadSector
1211
                                      (volinfo->unit, dirinfo->scratch,
1212
                                       volinfo->dataarea +
1213
                                       ((dirinfo->currentcluster -
1214
                                         2) * volinfo->secperclus), 1))
1215
 
1216
return DFS_ERRMISC;
1217
 
1218
}
1219
 
1220
                        else if (!memcmp2(de.name, tmpfn, 11)
1221
                                 && !(de.attr & ATTR_DIRECTORY))
1222
 
1223
return DFS_NOTFOUND;
1224
 
1225 389 tac2
 
1226 406 julius
                            // seek to next item in list
1227
                            while (*ptr != DIR_SEPARATOR && *ptr)
1228
 
1229
ptr++;
1230
 
1231
if (*ptr == DIR_SEPARATOR)
1232
 
1233
ptr++;
1234
 
1235
}
1236
 
1237
 
1238
if (!dirinfo->currentcluster)
1239
 
1240
return DFS_NOTFOUND;
1241
 
1242
}
1243
 
1244
return DFS_OK;
1245
 
1246
}
1247
 
1248
 
1249 389 tac2
 
1250
/*
1251
        Get next entry in opened directory structure. Copies fields into the dirent
1252
        structure, updates dirinfo. Note that it is the _caller's_ responsibility to
1253
        handle the '.' and '..' entries.
1254
        A deleted file will be returned as a NULL entry (first char of filename=0)
1255
        by this code. Filenames beginning with 0x05 will be translated to 0xE5
1256
        automatically. Long file name entries will be returned as NULL.
1257
        returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
1258
        or DFS_ERRMISC for a media error
1259 406 julius
*/
1260
unsigned long int DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo,
1261
                              PDIRENT dirent)
1262
{
1263
 
1264
unsigned long int tempint;      // required by DFS_GetFAT
1265
 
1266
            // Do we need to read the next sector of the directory?
1267
            if (dirinfo->currententry >= SECTOR_SIZE / sizeof(DIRENT)) {
1268
 
1269
dirinfo->currententry = 0;
1270
 
1271
dirinfo->currentsector++;
1272
 
1273 389 tac2
 
1274 406 julius
                    // Root directory; special case handling 
1275
                    // Note that currentcluster will only ever be zero if both:
1276
                    // (a) this is the root directory, and
1277
                    // (b) we are on a FAT12/16 volume, where the root dir can't be expanded
1278
                    if (dirinfo->currentcluster == 0) {
1279
 
1280
                            // Trying to read past end of root directory?
1281
                            if (dirinfo->currentsector *
1282
                                (SECTOR_SIZE / sizeof(DIRENT)) >=
1283
                                volinfo->rootentries)
1284
 
1285
return DFS_EOF;
1286
 
1287 389 tac2
 
1288 406 julius
                            // Otherwise try to read the next sector
1289
                            if (DFS_ReadSector
1290
                                (volinfo->unit, dirinfo->scratch,
1291
                                 volinfo->rootdir + dirinfo->currentsector, 1))
1292
 
1293
return DFS_ERRMISC;
1294
 
1295
}
1296
 
1297 389 tac2
 
1298 406 julius
                    // Normal handling
1299
                    else {
1300
 
1301
if (dirinfo->currentsector >= volinfo->secperclus) {
1302
 
1303
dirinfo->currentsector = 0;
1304
 
1305
if ((dirinfo->currentcluster >= 0xff7
1306
                                      && volinfo->filesystem == FAT12)
1307
                                     ||
1308
(dirinfo->currentcluster >= 0xfff7
1309
                                          && volinfo->filesystem == FAT16)
1310
                                     ||
1311
(dirinfo->currentcluster >= 0x0ffffff7
1312
                                          && volinfo->filesystem == FAT32)) {
1313
 
1314 389 tac2
 
1315 406 julius
                                            // We are at the end of the directory chain. If this is a normal
1316
                                            // find operation, we should indicate that there is nothing more
1317
                                            // to see.
1318
                                            if (!
1319
                                                (dirinfo->
1320
                                                 flags & DFS_DI_BLANKENT))
1321
 
1322
return DFS_EOF;
1323
 
1324 389 tac2
 
1325 406 julius
                                            // On the other hand, if this is a "find free entry" search,
1326
                                            // we need to tell the caller to allocate a new cluster
1327
                                            else
1328
 
1329
return DFS_ALLOCNEW;
1330
 
1331
}
1332
 
1333
dirinfo->currentcluster =
1334
                                    DFS_GetFAT(volinfo, dirinfo->scratch,
1335
                                               &tempint,
1336
                                               dirinfo->currentcluster);
1337
 
1338
}
1339
 
1340
if (DFS_ReadSector
1341
                             (volinfo->unit, dirinfo->scratch,
1342
                              volinfo->dataarea +
1343
                              ((dirinfo->currentcluster -
1344
                                2) * volinfo->secperclus) +
1345
                              dirinfo->currentsector, 1))
1346
 
1347
return DFS_ERRMISC;
1348
 
1349
}
1350
 
1351
}
1352
 
1353
 
1354
memcpy(dirent, &(((PDIRENT) dirinfo->scratch)[dirinfo->currententry]),
1355
                 sizeof(DIRENT));
1356
 
1357
 
1358
if (dirent->name[0] == 0) {       // no more files in this directory
1359 389 tac2
                // If this is a "find blank" then we can reuse this name.
1360 406 julius
                if (dirinfo->flags & DFS_DI_BLANKENT)
1361
 
1362
return DFS_OK;
1363
 
1364
                else
1365
 
1366
return DFS_EOF;
1367
 
1368
}
1369
 
1370
 
1371
if (dirent->name[0] == 0xe5)     // handle deleted file entries
1372
                dirent->name[0] = 0;
1373
 
1374
        else if ((dirent->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)
1375
 
1376
dirent->name[0] = 0;
1377
 
1378 389 tac2
        else if (dirent->name[0] == 0x05)        // handle kanji filenames beginning with 0xE5
1379 406 julius
                dirent->name[0] = 0xe5;
1380
 
1381
 
1382
dirinfo->currententry++;
1383
 
1384
 
1385
return DFS_OK;
1386
 
1387
}
1388
 
1389
 
1390 389 tac2
 
1391
/*
1392
        INTERNAL
1393
        Find a free directory entry in the directory specified by path
1394
        This function MAY cause a disk write if it is necessary to extend the directory
1395
        size.
1396
        Note - di.scratch must be preinitialized to point to a sector scratch buffer
1397
        de is a scratch structure
1398
        Returns DFS_ERRMISC if a new entry could not be located or created
1399
        de is updated with the same return information you would expect from DFS_GetNext
1400 406 julius
*/
1401
unsigned long int DFS_GetFreeDirEnt(PVOLINFO volinfo, unsigned char *path,
1402
                                    PDIRINFO di, PDIRENT de)
1403
{
1404
 
1405
unsigned long int tempclus, i;
1406
 
1407
 
1408
if (DFS_OpenDir(volinfo, path, di))
1409
 
1410
return DFS_NOTFOUND;
1411
 
1412 389 tac2
 
1413 406 julius
            // Set "search for empty" flag so DFS_GetNext knows what we're doing
1414
            di->flags |= DFS_DI_BLANKENT;
1415
 
1416 389 tac2
 
1417 406 julius
            // We seek through the directory looking for an empty entry
1418
            // Note we are reusing tempclus as a temporary result holder.
1419
            tempclus = 0;
1420
 
1421
        do {
1422
 
1423
tempclus = DFS_GetNext(volinfo, di, de);
1424
 
1425 389 tac2
 
1426 406 julius
                    // Empty entry found
1427
                    if (tempclus == DFS_OK && (!de->name[0])) {
1428
 
1429
return DFS_OK;
1430
 
1431
}
1432
 
1433 389 tac2
 
1434 406 julius
                    // End of root directory reached
1435
                    else if (tempclus == DFS_EOF)
1436
 
1437
return DFS_ERRMISC;
1438
 
1439 389 tac2
 
1440 406 julius
                else if (tempclus == DFS_ALLOCNEW) {
1441
 
1442
tempclus = DFS_GetFreeFAT(volinfo, di->scratch);
1443
 
1444
if (tempclus == 0x0ffffff7)
1445
 
1446
return DFS_ERRMISC;
1447
 
1448
 
1449
                            // write out zeroed sectors to the new cluster
1450
                            memset(di->scratch, 0, SECTOR_SIZE);
1451
 
1452
for (i = 0; i < volinfo->secperclus; i++) {
1453
 
1454
if (DFS_WriteSector
1455
                                     (volinfo->unit, di->scratch,
1456
                                      volinfo->dataarea +
1457
                                      ((tempclus - 2) * volinfo->secperclus) +
1458
                                      i, 1))
1459
 
1460
return DFS_ERRMISC;
1461
 
1462
}
1463 389 tac2
 
1464 406 julius
                            // Point old end cluster to newly allocated cluster
1465
                            i = 0;
1466
 
1467
DFS_SetFAT(volinfo, di->scratch, &i,
1468
                                    di->currentcluster, tempclus);
1469
 
1470 389 tac2
 
1471 406 julius
                            // Update DIRINFO so caller knows where to place the new file                   
1472
                            di->currentcluster = tempclus;
1473
 
1474
di->currentsector = 0;
1475
 
1476
di->currententry = 1;   // since the code coming after this expects to subtract 1
1477 389 tac2
 
1478 406 julius
                            // Mark newly allocated cluster as end of chain                 
1479
                            switch (volinfo->filesystem) {
1480
 
1481
case FAT12:
1482
                                tempclus = 0xff8;
1483
                                break;
1484
 
1485
case FAT16:
1486
                                tempclus = 0xfff8;
1487
                                break;
1488
 
1489
case FAT32:
1490
                                tempclus = 0x0ffffff8;
1491
                                break;
1492
 
1493
default:
1494
                                return DFS_ERRMISC;
1495
 
1496
}
1497
 
1498
DFS_SetFAT(volinfo, di->scratch, &i,
1499
                                    di->currentcluster, tempclus);
1500
 
1501
}
1502
 
1503
} while (!tempclus);
1504
 
1505 389 tac2
 
1506 406 julius
            // We shouldn't get here
1507
            return DFS_ERRMISC;
1508
 
1509
}
1510
 
1511
 
1512 389 tac2
 
1513
/*
1514
        Open a file for reading or writing. You supply populated VOLINFO, a path to the file,
1515
        mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to
1516
        provide a pointer to a sector-sized scratch buffer.
1517
        Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used
1518
        to access the file from this point on.
1519 406 julius
*/
1520
unsigned long int DFS_OpenFile(PVOLINFO volinfo, unsigned char *path,
1521
                               unsigned char mode, unsigned char *scratch,
1522
                               PFILEINFO fileinfo)
1523
{
1524
 
1525
unsigned char tmppath[MAX_PATH];
1526
 
1527
unsigned char filename[12];
1528
 
1529
unsigned char *p;
1530
 
1531
DIRINFO di;
1532
 
1533
DIRENT de;
1534
 
1535 389 tac2
 
1536 406 julius
            // larwe 2006-09-16 +1 zero out file structure
1537
            memset(fileinfo, 0, sizeof(FILEINFO));
1538
 
1539 389 tac2
 
1540 406 julius
            // save access mode
1541
            fileinfo->mode = mode;
1542
 
1543 389 tac2
 
1544 406 julius
            // Get a local copy of the path. If it's longer than MAX_PATH, abort.
1545
            strcpy2((char *)tmppath, (char *)path);
1546
 
1547
tmppath[MAX_PATH - 1] = 0;
1548
 
1549
if (strcmp2((char *)path, (char *)tmppath)) {
1550
 
1551
return DFS_PATHLEN;
1552
 
1553
}
1554
 
1555
 
1556 389 tac2
 
1557 406 julius
            // strip leading path separators
1558
            while (tmppath[0] == DIR_SEPARATOR)
1559
 
1560
strcpy2((char *)tmppath, (char *)tmppath + 1);
1561
 
1562 389 tac2
 
1563 406 julius
            // Parse filename off the end of the supplied path
1564
            p = tmppath;
1565
 
1566
while (*(p++)) ;
1567
 
1568
 
1569
p--;
1570
 
1571
while (p > tmppath && *p != DIR_SEPARATOR)      // larwe 9/16/06 ">=" to ">" bugfix
1572
                p--;
1573
 
1574
if (*p == DIR_SEPARATOR)
1575
 
1576
p++;
1577
 
1578
 
1579
DFS_CanonicalToDir(filename, p);
1580
 
1581
 
1582
if (p > tmppath)
1583
 
1584
p--;
1585
 
1586
if (*p == DIR_SEPARATOR || p == tmppath)        // larwe 9/16/06 +"|| p == tmppath" bugfix
1587
                *p = 0;
1588
 
1589 389 tac2
 
1590 406 julius
            // At this point, if our path was MYDIR/MYDIR2/FILE.EXT, filename = "FILE    EXT" and
1591
            // tmppath = "MYDIR/MYDIR2".
1592
            di.scratch = scratch;
1593
 
1594
if (DFS_OpenDir(volinfo, tmppath, &di))
1595
 
1596
return DFS_NOTFOUND;
1597
 
1598
 
1599
while (!DFS_GetNext(volinfo, &di, &de)) {
1600
 
1601
 
1602
if (!memcmp2(de.name, filename, 11)) {
1603
 
1604
                            // You can't use this function call to open a directory.
1605
                            if (de.attr & ATTR_DIRECTORY)
1606
 
1607
return DFS_NOTFOUND;
1608
 
1609
printf("get enxt \n");
1610
 
1611
fileinfo->volinfo = volinfo;
1612
 
1613
fileinfo->pointer = 0;
1614
 
1615
                            // The reason we store this extra info about the file is so that we can
1616
                            // speedily update the file size, modification date, etc. on a file that is
1617
                            // opened for writing.
1618
                            if (di.currentcluster == 0)
1619
 
1620
fileinfo->dirsector =
1621
                                    volinfo->rootdir + di.currentsector;
1622
 
1623
                        else
1624
 
1625
fileinfo->dirsector =
1626
                                    volinfo->dataarea +
1627
                                    ((di.currentcluster -
1628
                                      2) * volinfo->secperclus) +
1629
                                    di.currentsector;
1630
 
1631
fileinfo->diroffset = di.currententry - 1;
1632
 
1633
if (volinfo->filesystem == FAT32) {
1634
 
1635
fileinfo->cluster =
1636
                                    (unsigned long int)de.
1637
                                    startclus_l_l |
1638
((unsigned long int)de.
1639
                                                      startclus_l_h) << 8 |
1640
 
1641
((unsigned long int)de.
1642
                                      startclus_h_l) << 16 |
1643
((unsigned long
1644
                                                                int)de.
1645
                                                               startclus_h_h) <<
1646
                                    24;
1647
 
1648
}
1649
 
1650
                        else {
1651
 
1652
fileinfo->cluster =
1653
                                    (unsigned long int)de.
1654
                                    startclus_l_l |
1655
((unsigned long int)de.
1656
                                                      startclus_l_h) << 8;
1657
 
1658
}
1659
fileinfo->firstcluster = fileinfo->cluster;
1660
 
1661
fileinfo->filelen =
1662
                            (unsigned long int)de.
1663
                            filesize_0 |
1664
((unsigned long int)de.
1665
                                           filesize_1) << 8 |
1666
((unsigned long
1667
                                                                 int)de.
1668
                                                                filesize_2) <<
1669
                            16 |
1670
((unsigned long int)de.filesize_3) << 24;
1671
 
1672
 
1673
return DFS_OK;
1674
 
1675
}
1676
 
1677
}
1678
 
1679 389 tac2
 
1680 406 julius
            // At this point, we KNOW the file does not exist. If the file was opened
1681
            // with write access, we can create it.
1682
            if (mode & DFS_WRITE) {
1683
 
1684
unsigned long int cluster, temp;
1685
 
1686 389 tac2
 
1687 406 julius
                    // Locate or create a directory entry for this file
1688
                    if (DFS_OK != DFS_GetFreeDirEnt(volinfo, tmppath, &di, &de))
1689
 
1690
return DFS_ERRMISC;
1691
 
1692 389 tac2
 
1693 406 julius
                    // put sane values in the directory entry
1694
                    memset(&de, 0, sizeof(de));
1695
 
1696
memcpy(de.name, filename, 11);
1697
 
1698
de.crttime_l = 0x20;    // 01:01:00am, Jan 1, 2006.
1699
                de.crttime_h = 0x08;
1700
 
1701
de.crtdate_l = 0x11;
1702
 
1703
de.crtdate_h = 0x34;
1704
 
1705
de.lstaccdate_l = 0x11;
1706
 
1707
de.lstaccdate_h = 0x34;
1708
 
1709
de.wrttime_l = 0x20;
1710
 
1711
de.wrttime_h = 0x08;
1712
 
1713
de.wrtdate_l = 0x11;
1714
 
1715
de.wrtdate_h = 0x34;
1716
 
1717 389 tac2
 
1718 406 julius
                    // allocate a starting cluster for the directory entry
1719
                    cluster = DFS_GetFreeFAT(volinfo, scratch);
1720
 
1721
 
1722
de.startclus_l_l = cluster & 0xff;
1723
 
1724
de.startclus_l_h = (cluster & 0xff00) >> 8;
1725
 
1726
de.startclus_h_l = (cluster & 0xff0000) >> 16;
1727
 
1728
de.startclus_h_h = (cluster & 0xff000000) >> 24;
1729
 
1730 389 tac2
 
1731 406 julius
                    // update FILEINFO for our caller's sake
1732
                    fileinfo->volinfo = volinfo;
1733
 
1734
fileinfo->pointer = 0;
1735 389 tac2
 
1736 406 julius
                    // The reason we store this extra info about the file is so that we can
1737
                    // speedily update the file size, modification date, etc. on a file that is
1738
                    // opened for writing.
1739
                    if (di.currentcluster == 0)
1740
 
1741
fileinfo->dirsector =
1742
                            volinfo->rootdir + di.currentsector;
1743
 
1744
                else
1745
 
1746
fileinfo->dirsector =
1747
                            volinfo->dataarea +
1748
                            ((di.currentcluster - 2) * volinfo->secperclus) +
1749
                            di.currentsector;
1750
 
1751
fileinfo->diroffset = di.currententry - 1;
1752
 
1753
fileinfo->cluster = cluster;
1754
 
1755
fileinfo->firstcluster = cluster;
1756
 
1757
fileinfo->filelen = 0;
1758
 
1759 389 tac2
 
1760 406 julius
                    // write the directory entry
1761
                    // note that we no longer have the sector containing the directory entry,
1762
                    // tragically, so we have to re-read it
1763
                    if (DFS_ReadSector
1764
                        (volinfo->unit, scratch, fileinfo->dirsector, 1))
1765
 
1766
return DFS_ERRMISC;
1767
 
1768
memcpy(&(((PDIRENT) scratch)[di.currententry - 1]), &de,
1769
                        sizeof(DIRENT));
1770
 
1771
if (DFS_WriteSector
1772
                     (volinfo->unit, scratch, fileinfo->dirsector, 1))
1773
 
1774
return DFS_ERRMISC;
1775
 
1776 389 tac2
 
1777 406 julius
                    // Mark newly allocated cluster as end of chain                 
1778
                    switch (volinfo->filesystem) {
1779
 
1780
case FAT12:
1781
                        cluster = 0xff8;
1782
                        break;
1783
 
1784
case FAT16:
1785
                        cluster = 0xfff8;
1786
                        break;
1787
 
1788
case FAT32:
1789
                        cluster = 0x0ffffff8;
1790
                        break;
1791
 
1792
default:
1793
                        return DFS_ERRMISC;
1794
 
1795
}
1796
 
1797
temp = 0;
1798
 
1799
DFS_SetFAT(volinfo, scratch, &temp, fileinfo->cluster,
1800
                            cluster);
1801
 
1802
 
1803
return DFS_OK;
1804
 
1805
}
1806
 
1807
 
1808
return DFS_NOTFOUND;
1809
 
1810
}
1811
 
1812
 
1813 389 tac2
 
1814
/*
1815
        Read an open file
1816
        You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
1817
        pointer to a SECTOR_SIZE scratch buffer.
1818
        Note that returning DFS_EOF is not an error condition. This function updates the
1819
        successcount field with the number of bytes actually read.
1820 406 julius
*/
1821
unsigned long int DFS_ReadFile(PFILEINFO fileinfo, unsigned char *scratch,
1822
                               unsigned char *buffer,
1823
                               unsigned long int *successcount,
1824
                               unsigned long int len)
1825
{
1826
 
1827
unsigned long int remain;
1828
 
1829
unsigned long int result = DFS_OK;
1830
 
1831
unsigned long int sector;
1832
 
1833
unsigned long int bytesread;
1834
 
1835 389 tac2
 
1836 406 julius
            // Don't try to read past EOF
1837
            if (len > fileinfo->filelen - fileinfo->pointer)
1838
 
1839
len = fileinfo->filelen - fileinfo->pointer;
1840
 
1841
 
1842
remain = len;
1843
 
1844
*successcount = 0;
1845
 
1846
 
1847
while (remain && result == DFS_OK) {
1848
 
1849
                    // This is a bit complicated. The sector we want to read is addressed at a cluster
1850
                    // granularity by the fileinfo->cluster member. The file pointer tells us how many
1851
                    // extra sectors to add to that number.
1852
                    sector = fileinfo->volinfo->dataarea +
1853
                    ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
1854
 
1855
div(div
1856
                         (fileinfo->pointer,
1857
                          fileinfo->volinfo->secperclus * SECTOR_SIZE).rem,
1858
                         SECTOR_SIZE).quot;
1859
 
1860 389 tac2
 
1861 406 julius
                    // Case 1 - File pointer is not on a sector boundary
1862
                    if (div(fileinfo->pointer, SECTOR_SIZE).rem) {
1863
 
1864
 
1865
unsigned short tempreadsize;
1866
 
1867
 
1868 389 tac2
 
1869 406 julius
                            // We always have to go through scratch in this case
1870
                            result =
1871
                            DFS_ReadSector(fileinfo->volinfo->unit, scratch,
1872
                                           sector, 1);
1873
 
1874 389 tac2
 
1875 406 julius
                            // This is the number of bytes that we actually care about in the sector
1876
                            // just read.
1877
 
1878
tempreadsize =
1879
                            SECTOR_SIZE -
1880
                            (div(fileinfo->pointer, SECTOR_SIZE).rem);
1881
 
1882
 
1883
 
1884
                            // Case 1A - We want the entire remainder of the sector. After this
1885
                            // point, all passes through the read loop will be aligned on a sector
1886
                            // boundary, which allows us to go through the optimal path 2A below.
1887
                            if (remain >= tempreadsize) {
1888
 
1889
memcpy(buffer,
1890
                                        scratch + (SECTOR_SIZE - tempreadsize),
1891
                                        tempreadsize);
1892
 
1893
bytesread = tempreadsize;
1894
 
1895
buffer += tempreadsize;
1896
 
1897
fileinfo->pointer += tempreadsize;
1898
 
1899
remain -= tempreadsize;
1900
 
1901
}
1902 389 tac2
 
1903 406 julius
                            // Case 1B - This read concludes the file read operation
1904
                            else {
1905
 
1906
memcpy(buffer,
1907
                                        scratch + (SECTOR_SIZE - tempreadsize),
1908
                                        remain);
1909
 
1910
 
1911
buffer += remain;
1912
 
1913
fileinfo->pointer += remain;
1914
 
1915
bytesread = remain;
1916
 
1917
remain = 0;
1918
 
1919
}
1920
 
1921
}
1922
 
1923
                    // Case 2 - File pointer is on sector boundary
1924
                    else {
1925
 
1926 389 tac2
 
1927 406 julius
                            // Case 2A - We have at least one more full sector to read and don't have
1928
                            // to go through the scratch buffer. You could insert optimizations here to
1929
                            // read multiple sectors at a time, if you were thus inclined (note that
1930
                            // the maximum multi-read you could perform is a single cluster, so it would
1931
                            // be advantageous to have code similar to case 1A above that would round the
1932
                            // pointer to a cluster boundary the first pass through, so all subsequent
1933
                            // [large] read requests would be able to go a cluster at a time).
1934
                            if (remain >= SECTOR_SIZE) {
1935
 
1936
 
1937
result =
1938
                                    DFS_ReadSector(fileinfo->volinfo->unit,
1939
                                                   buffer, sector, 1);
1940
 
1941
 
1942
remain -= SECTOR_SIZE;
1943
 
1944
 
1945
buffer += SECTOR_SIZE;
1946
 
1947
 
1948
fileinfo->pointer += SECTOR_SIZE;
1949
 
1950
 
1951
bytesread = SECTOR_SIZE;
1952
 
1953
 
1954
}
1955 389 tac2
 
1956 406 julius
                            // Case 2B - We are only reading a partial sector
1957
                            else {
1958
 
1959
 
1960
result =
1961
                                    DFS_ReadSector(fileinfo->volinfo->unit,
1962
                                                   scratch, sector, 1);
1963
 
1964
memcpy(buffer, scratch, remain);
1965
 
1966
buffer += remain;
1967
 
1968
fileinfo->pointer += remain;
1969
 
1970
bytesread = remain;
1971
 
1972
remain = 0;
1973
 
1974
}
1975
 
1976
}
1977
 
1978
 
1979
*successcount += bytesread;
1980
 
1981
 
1982 389 tac2
 
1983 406 julius
                    // check to see if we stepped over a cluster boundary
1984
                    if (div
1985
                        (fileinfo->pointer - bytesread,
1986
                         fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
1987
 
1988
div(fileinfo->pointer,
1989
                             fileinfo->volinfo->secperclus *
1990
                             SECTOR_SIZE).quot) {
1991 389 tac2
 
1992 406 julius
                            // An act of minor evil - we use bytesread as a scratch integer, knowing that
1993
                            // its value is not used after updating *successcount above
1994
 
1995
bytesread = 0;
1996
 
1997
 
1998
if (((fileinfo->volinfo->filesystem == FAT12)
1999
                               && (fileinfo->cluster >= 0xff8))
2000
                              ||
2001
((fileinfo->volinfo->filesystem == FAT16)
2002
                                   && (fileinfo->cluster >= 0xfff8))
2003
                              ||
2004
((fileinfo->volinfo->filesystem == FAT32)
2005
                                   && (fileinfo->cluster >= 0x0ffffff8)))
2006
 
2007
result = DFS_EOF;
2008
 
2009
                        else
2010
 
2011
fileinfo->cluster =
2012
                                    DFS_GetFAT(fileinfo->volinfo, scratch,
2013
                                               &bytesread, fileinfo->cluster);
2014
 
2015
}
2016
 
2017
}
2018
 
2019
 
2020
 
2021
return result;
2022
 
2023
}
2024
 
2025
 
2026 389 tac2
 
2027
/*
2028
        Seek file pointer to a given position
2029
        This function does not return status - refer to the fileinfo->pointer value
2030
        to see where the pointer wound up.
2031
        Requires a SECTOR_SIZE scratch buffer
2032 406 julius
*/
2033
void DFS_Seek(PFILEINFO fileinfo, unsigned long int offset,
2034
              unsigned char *scratch)
2035
{
2036
 
2037
unsigned long int tempint;
2038
 
2039 389 tac2
 
2040 406 julius
            // larwe 9/16/06 bugfix split case 0a/0b and changed fallthrough handling
2041
            // Case 0a - Return immediately for degenerate case
2042
            if (offset == fileinfo->pointer) {
2043
 
2044
return;
2045
 
2046
}
2047
 
2048 389 tac2
 
2049 406 julius
            // Case 0b - Don't allow the user to seek past the end of the file
2050
            if (offset > fileinfo->filelen) {
2051
 
2052
offset = fileinfo->filelen;
2053
 
2054
                    // NOTE NO RETURN HERE!
2055
        }
2056
 
2057 389 tac2
 
2058 406 julius
            // Case 1 - Simple rewind to start
2059
            // Note _intentional_ fallthrough from Case 0b above
2060
            if (offset == 0) {
2061
 
2062
fileinfo->cluster = fileinfo->firstcluster;
2063
 
2064
fileinfo->pointer = 0;
2065
 
2066
return; // larwe 9/16/06 +1 bugfix
2067
        }
2068
 
2069
            // Case 2 - Seeking backwards. Need to reset and seek forwards
2070
            else if (offset < fileinfo->pointer) {
2071
 
2072
fileinfo->cluster = fileinfo->firstcluster;
2073
 
2074
fileinfo->pointer = 0;
2075
 
2076
                    // NOTE NO RETURN HERE!
2077
        }
2078
 
2079 389 tac2
 
2080 406 julius
            // Case 3 - Seeking forwards
2081
            // Note _intentional_ fallthrough from Case 2 above
2082
 
2083
            // Case 3a - Seek size does not cross cluster boundary - 
2084
            // very simple case
2085
            // larwe 9/16/06 changed .rem to .quot in both div calls, bugfix
2086
            if (div
2087
                (fileinfo->pointer,
2088
                 fileinfo->volinfo->secperclus * SECTOR_SIZE).quot ==
2089
 
2090
div(fileinfo->pointer + offset,
2091
                     fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
2092
 
2093
fileinfo->pointer = offset;
2094
 
2095
}
2096
 
2097
            // Case 3b - Seeking across cluster boundary(ies)
2098
            else {
2099
 
2100
                    // round file pointer down to cluster boundary
2101
                    fileinfo->pointer =
2102
                    div(fileinfo->pointer,
2103
                        fileinfo->volinfo->secperclus * SECTOR_SIZE).quot *
2104
 
2105
fileinfo->volinfo->secperclus * SECTOR_SIZE;
2106
 
2107 389 tac2
 
2108 406 julius
                    // seek by clusters
2109
                    // larwe 9/30/06 bugfix changed .rem to .quot in both div calls
2110
                    while (div
2111
                           (fileinfo->pointer,
2112
                            fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
2113
 
2114
div(fileinfo->pointer + offset,
2115
                                fileinfo->volinfo->secperclus *
2116
                                SECTOR_SIZE).quot) {
2117
 
2118
 
2119
fileinfo->cluster =
2120
                            DFS_GetFAT(fileinfo->volinfo, scratch, &tempint,
2121
                                       fileinfo->cluster);
2122
 
2123
                            // Abort if there was an error
2124
                            if (fileinfo->cluster == 0x0ffffff7) {
2125
 
2126
fileinfo->pointer = 0;
2127
 
2128
fileinfo->cluster = fileinfo->firstcluster;
2129
 
2130
return;
2131
 
2132
}
2133
 
2134
fileinfo->pointer +=
2135
                            SECTOR_SIZE * fileinfo->volinfo->secperclus;
2136
 
2137
}
2138
 
2139 389 tac2
 
2140 406 julius
                    // since we know the cluster is right, we have no more work to do
2141
                    fileinfo->pointer = offset;
2142
 
2143
}
2144
 
2145
}
2146
 
2147
 
2148 389 tac2
 
2149
/*
2150
        Delete a file
2151
        scratch must point to a sector-sized buffer
2152 406 julius
*/
2153
unsigned long int DFS_UnlinkFile(PVOLINFO volinfo, unsigned char *path,
2154
                                 unsigned char *scratch)
2155
{
2156
 
2157
PDIRENT de = (PDIRENT) scratch;
2158
 
2159
FILEINFO fi;
2160
 
2161
unsigned long int cache = 0;
2162
 
2163
unsigned long int tempclus;
2164
 
2165 389 tac2
 
2166 406 julius
            // DFS_OpenFile gives us all the information we need to delete it
2167
            if (DFS_OK != DFS_OpenFile(volinfo, path, DFS_READ, scratch, &fi))
2168
 
2169
return DFS_NOTFOUND;
2170
 
2171 389 tac2
 
2172 406 julius
            // First, read the directory sector and delete that entry
2173
            if (DFS_ReadSector(volinfo->unit, scratch, fi.dirsector, 1))
2174
 
2175
return DFS_ERRMISC;
2176
 
2177
((PDIRENT) scratch)[fi.diroffset].name[0] = 0xe5;
2178
 
2179
if (DFS_WriteSector(volinfo->unit, scratch, fi.dirsector, 1))
2180
 
2181
return DFS_ERRMISC;
2182
 
2183 389 tac2
 
2184 406 julius
            // Now follow the cluster chain to free the file space
2185
            while (!
2186
                   ((volinfo->filesystem == FAT12 && fi.firstcluster >= 0x0ff7)
2187
                    ||
2188
(volinfo->filesystem == FAT16
2189
                         && fi.firstcluster >= 0xfff7)
2190
                    ||
2191
(volinfo->filesystem == FAT32
2192
                         && fi.firstcluster >= 0x0ffffff7))) {
2193
 
2194
tempclus = fi.firstcluster;
2195
 
2196
 
2197
fi.firstcluster =
2198
                    DFS_GetFAT(volinfo, scratch, &cache, fi.firstcluster);
2199
 
2200
DFS_SetFAT(volinfo, scratch, &cache, tempclus, 0);
2201
 
2202
 
2203
}
2204
 
2205
return DFS_OK;
2206
 
2207
}
2208
 
2209
 
2210
 
2211 389 tac2
 
2212
/*
2213
        Write an open file
2214
        You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
2215
        pointer to a SECTOR_SIZE scratch buffer.
2216
        This function updates the successcount field with the number of bytes actually written.
2217 406 julius
*/
2218
unsigned long int DFS_WriteFile(PFILEINFO fileinfo, unsigned char *scratch,
2219
                                unsigned char *buffer,
2220
                                unsigned long int *successcount,
2221
                                unsigned long int len)
2222
{
2223
 
2224
unsigned long int remain;
2225
 
2226
unsigned long int result = DFS_OK;
2227
 
2228
unsigned long int sector;
2229
 
2230
unsigned long int byteswritten;
2231
 
2232 389 tac2
 
2233 406 julius
            // Don't allow writes to a file that's open as readonly
2234
            if (!(fileinfo->mode & DFS_WRITE))
2235
 
2236
return DFS_ERRMISC;
2237
 
2238
 
2239
remain = len;
2240
 
2241
*successcount = 0;
2242
 
2243
 
2244
while (remain && result == DFS_OK) {
2245
 
2246
                    // This is a bit complicated. The sector we want to read is addressed at a cluster
2247
                    // granularity by the fileinfo->cluster member. The file pointer tells us how many
2248
                    // extra sectors to add to that number.
2249
                    sector = fileinfo->volinfo->dataarea +
2250
                    ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
2251
 
2252
div(div
2253
                         (fileinfo->pointer,
2254
                          fileinfo->volinfo->secperclus * SECTOR_SIZE).rem,
2255
                         SECTOR_SIZE).quot;
2256
 
2257 389 tac2
 
2258 406 julius
                    // Case 1 - File pointer is not on a sector boundary
2259
                    if (div(fileinfo->pointer, SECTOR_SIZE).rem) {
2260
 
2261
unsigned short tempsize;
2262
 
2263
printf("CASE 1 \n");
2264
 
2265
                            // We always have to go through scratch in this case
2266
                            result =
2267
                            DFS_ReadSector(fileinfo->volinfo->unit, scratch,
2268
                                           sector, 1);
2269
 
2270 389 tac2
 
2271 406 julius
                            // This is the number of bytes that we don't want to molest in the
2272
                            // scratch sector just read.
2273
                            tempsize = div(fileinfo->pointer, SECTOR_SIZE).rem;
2274
 
2275 389 tac2
 
2276 406 julius
                            // Case 1A - We are writing the entire remainder of the sector. After
2277
                            // this point, all passes through the read loop will be aligned on a
2278
                            // sector boundary, which allows us to go through the optimal path
2279
                            // 2A below.
2280
                            if (remain >= SECTOR_SIZE - tempsize) {
2281
 
2282
memcpy(scratch + tempsize, buffer,
2283
                                        SECTOR_SIZE - tempsize);
2284
 
2285
if (!result)
2286
 
2287
result =
2288
                                            DFS_WriteSector(fileinfo->volinfo->
2289
                                                            unit, scratch,
2290
                                                            sector, 1);
2291
 
2292
 
2293
byteswritten = SECTOR_SIZE - tempsize;
2294
 
2295
buffer += SECTOR_SIZE - tempsize;
2296
 
2297
fileinfo->pointer += SECTOR_SIZE - tempsize;
2298
 
2299
if (fileinfo->filelen < fileinfo->pointer) {
2300
 
2301
fileinfo->filelen = fileinfo->pointer;
2302
 
2303
}
2304
 
2305
remain -= SECTOR_SIZE - tempsize;
2306
 
2307
}
2308
 
2309
                            // Case 1B - This concludes the file write operation
2310
                            else {
2311
 
2312
printf("CASE 1B \n");
2313
 
2314
memcpy(scratch + tempsize, buffer, remain);
2315
 
2316
if (!result)
2317
 
2318
result =
2319
                                            DFS_WriteSector(fileinfo->volinfo->
2320
                                                            unit, scratch,
2321
                                                            sector, 1);
2322
 
2323
 
2324
buffer += remain;
2325
 
2326
fileinfo->pointer += remain;
2327
 
2328
if (fileinfo->filelen < fileinfo->pointer) {
2329
 
2330
fileinfo->filelen = fileinfo->pointer;
2331
 
2332
}
2333
 
2334
byteswritten = remain;
2335
 
2336
remain = 0;
2337
 
2338
}
2339
 
2340
}               // case 1
2341 389 tac2
                // Case 2 - File pointer is on sector boundary
2342 406 julius
                else {
2343
 
2344
printf("CASE 2 \n");
2345
 
2346
                            // Case 2A - We have at least one more full sector to write and don't have
2347
                            // to go through the scratch buffer. You could insert optimizations here to
2348
                            // write multiple sectors at a time, if you were thus inclined. Refer to
2349
                            // similar notes in DFS_ReadFile.
2350
                            if (remain >= SECTOR_SIZE) {
2351
 
2352
result =
2353
                                    DFS_WriteSector(fileinfo->volinfo->unit,
2354
                                                    buffer, sector, 1);
2355
 
2356
remain -= SECTOR_SIZE;
2357
 
2358
buffer += SECTOR_SIZE;
2359
 
2360
fileinfo->pointer += SECTOR_SIZE;
2361
 
2362
if (fileinfo->filelen < fileinfo->pointer) {
2363
 
2364
fileinfo->filelen = fileinfo->pointer;
2365
 
2366
}
2367
 
2368
byteswritten = SECTOR_SIZE;
2369
 
2370
}
2371
 
2372
                            // Case 2B - We are only writing a partial sector and potentially need to
2373
                            // go through the scratch buffer.
2374
                            else {
2375
 
2376
printf("CASE 2B \n");
2377
 
2378
                                    // If the current file pointer is not yet at or beyond the file
2379
                                    // length, we are writing somewhere in the middle of the file and
2380
                                    // need to load the original sector to do a read-modify-write.
2381
                                    if (fileinfo->pointer < fileinfo->filelen) {
2382
 
2383
result =
2384
                                            DFS_ReadSector(fileinfo->volinfo->
2385
                                                           unit, scratch,
2386
                                                           sector, 1);
2387
 
2388
if (!result) {
2389
 
2390
memcpy(scratch, buffer,
2391
                                                        remain);
2392
 
2393
result =
2394
                                                    DFS_WriteSector(fileinfo->
2395
                                                                    volinfo->
2396
                                                                    unit,
2397
                                                                    scratch,
2398
                                                                    sector, 1);
2399
 
2400
}
2401
 
2402
}
2403
 
2404
                                else {
2405
 
2406
result =
2407
                                            DFS_WriteSector(fileinfo->volinfo->
2408
                                                            unit, buffer,
2409
                                                            sector, 1);
2410
 
2411
}
2412
 
2413
 
2414
buffer += remain;
2415
 
2416
fileinfo->pointer += remain;
2417
 
2418
if (fileinfo->filelen < fileinfo->pointer) {
2419
 
2420
fileinfo->filelen = fileinfo->pointer;
2421
 
2422
}
2423
 
2424
byteswritten = remain;
2425
 
2426
remain = 0;
2427
 
2428
}
2429
 
2430
}
2431
 
2432
 
2433
*successcount += byteswritten;
2434
 
2435
printf("Writen byte %d \n", *successcount);
2436
 
2437
                    // check to see if we stepped over a cluster boundary
2438
                    if (div
2439
                        (fileinfo->pointer - byteswritten,
2440
                         fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
2441
 
2442
div(fileinfo->pointer,
2443
                             fileinfo->volinfo->secperclus *
2444
                             SECTOR_SIZE).quot) {
2445
 
2446
unsigned long int lastcluster;
2447
 
2448 389 tac2
 
2449 406 julius
                            // We've transgressed into another cluster. If we were already at EOF,
2450
                            // we need to allocate a new cluster.
2451
                            // An act of minor evil - we use byteswritten as a scratch integer, knowing
2452
                            // that its value is not used after updating *successcount above
2453
                            byteswritten = 0;
2454
 
2455
 
2456
lastcluster = fileinfo->cluster;
2457
 
2458
fileinfo->cluster =
2459
                            DFS_GetFAT(fileinfo->volinfo, scratch,
2460
                                       &byteswritten, fileinfo->cluster);
2461
 
2462 389 tac2
 
2463 406 julius
                            // Allocate a new cluster?
2464
                            if (((fileinfo->volinfo->filesystem == FAT12)
2465
                                 && (fileinfo->cluster >= 0xff8))
2466
                                ||
2467
((fileinfo->volinfo->filesystem == FAT16)
2468
                                     && (fileinfo->cluster >= 0xfff8))
2469
                                ||
2470
((fileinfo->volinfo->filesystem == FAT32)
2471
                                     && (fileinfo->cluster >= 0x0ffffff8))) {
2472
 
2473
unsigned long int tempclus;
2474
 
2475
 
2476
tempclus =
2477
                                    DFS_GetFreeFAT(fileinfo->volinfo, scratch);
2478
 
2479
byteswritten = 0;        // invalidate cache
2480
                                if (tempclus == 0x0ffffff7)
2481
 
2482
return DFS_ERRMISC;
2483
 
2484 389 tac2
 
2485 406 julius
                                    // Link new cluster onto file
2486
                                    DFS_SetFAT(fileinfo->volinfo, scratch,
2487
                                               &byteswritten, lastcluster,
2488
                                               tempclus);
2489
 
2490
fileinfo->cluster = tempclus;
2491
 
2492 389 tac2
 
2493 406 julius
                                    // Mark newly allocated cluster as end of chain                 
2494
                                    switch (fileinfo->volinfo->filesystem) {
2495
 
2496
case FAT12:
2497
                                        tempclus = 0xff8;
2498
                                        break;
2499
 
2500
case FAT16:
2501
                                        tempclus = 0xfff8;
2502
                                        break;
2503
 
2504
case FAT32:
2505
                                        tempclus = 0x0ffffff8;
2506
                                        break;
2507
 
2508
default:
2509
                                        return DFS_ERRMISC;
2510
 
2511
}
2512
 
2513
DFS_SetFAT(fileinfo->volinfo, scratch,
2514
                                            &byteswritten, fileinfo->cluster,
2515
                                            tempclus);
2516
 
2517
 
2518
result = DFS_OK;
2519
 
2520
}
2521 389 tac2
 
2522 406 julius
                            // No else clause is required.
2523
                }
2524
 
2525
}
2526
 
2527 389 tac2
 
2528 406 julius
            // Update directory entry
2529
            if (DFS_ReadSector
2530
                (fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1))
2531
 
2532
return DFS_ERRMISC;
2533
 
2534
((PDIRENT) scratch)[fileinfo->diroffset].filesize_0 =
2535
            fileinfo->filelen & 0xff;
2536
 
2537
((PDIRENT) scratch)[fileinfo->diroffset].filesize_1 =
2538
            (fileinfo->filelen & 0xff00) >> 8;
2539
 
2540
((PDIRENT) scratch)[fileinfo->diroffset].filesize_2 =
2541
            (fileinfo->filelen & 0xff0000) >> 16;
2542
 
2543
((PDIRENT) scratch)[fileinfo->diroffset].filesize_3 =
2544
            (fileinfo->filelen & 0xff000000) >> 24;
2545
 
2546
if (DFS_WriteSector
2547
             (fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1))
2548
 
2549
return DFS_ERRMISC;
2550
 
2551
return result;
2552
 
2553
}
2554
 
2555
 
2556
 
2557
int memcmp2(const void *s1, const void *s2, size_t n)
2558
{
2559
 
2560
const unsigned char *p1 = s1, *p2 = s2;
2561
 
2562
while (n--)
2563
 
2564
if (*p1 != *p2)
2565
 
2566
return *p1 - *p2;
2567 389 tac2
 
2568 406 julius
                else
2569
 
2570
*p1++, *p2++;
2571
 
2572
return 0;
2573
 
2574
}
2575
 
2576
 
2577
 
2578
char *strcpy2(char *dest, char *src)
2579
{
2580
 
2581
char *ret = dest;
2582
 
2583
while (*dest++ = *src++)
2584
 
2585
;
2586
 
2587
return ret;
2588
 
2589
}
2590
 
2591
 
2592
 
2593
int strcmp2(const char *s1, const char *s2)
2594
{
2595
 
2596
while (*s1 && (*s1 == *s2))
2597
 
2598
s1++, s2++;
2599
 
2600
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
2601
 
2602
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.