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

Subversion Repositories openrisc

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

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
*/
10
 
11
/*
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
*/
17
 
18
 
19
//#include <string.h>
20
//#include <stdlib.h>
21
//#include "or32_utils.h"
22
#include "dosfs.h"
23
#include "sdc.h"
24
 
25
#include "common.h"
26
#include "support.h"
27
#include "uart.h"
28
 
29
 
30
 
31
unsigned long int init_fat(VOLINFO *vis){
32
 
33
 
34
 
35
    unsigned char sector[SECTOR_SIZE];
36
    unsigned long int pstart,psize, i,fisz;
37
    unsigned char pactive, ptype;
38
    VOLINFO vi;
39
 
40
 
41
    //uart_init(DEFAULT_UART);
42
    printf("FAT INIT START\n");
43
    memCardInit();
44
 
45
 
46
        pstart = DFS_GetPtnStart(0, sector, 0, &pactive, &ptype, &psize);
47
        if (pstart == 0xffffffff) {
48
                printf("Cannot find first partition\n");
49
                return -1;
50
        }
51
 
52
        printf("Partition 0 start sector 0x%-08.8lX active %-02.2hX type %-02.2hX size %-08.8lX\n", pstart, pactive, ptype, psize);
53
 
54
        if (DFS_GetVolInfo(0, sector, pstart, &vi)) {
55
                printf("Error getting volume information\n");
56
                return -1;
57
        }
58
 
59
 
60
 
61
 
62
        *vis=vi;
63
 
64
 
65
 
66
}
67
 
68
 
69
unsigned long int DFS_ReadSector(unsigned char unit, unsigned char *buffer, unsigned long int sector, unsigned long int  count)
70
{
71
 
72
    unsigned long int block_add = 0;
73
        int i ;
74
 
75
 
76
 
77
    for (i=0; i<count; i++){
78
        block_add=sector+i;
79
        DBGA("\n readSector %u, block_addr %u \n",sector,block_add);
80
        setup_bd_transfer(READ_OP, block_add , buffer);
81
        if (finnish_bd_transfer() == FALSE)
82
            return 0xff;
83
 
84
    }
85
 
86
    return 0;
87
 
88
}
89
 
90
 
91
unsigned long int DFS_WriteSector(unsigned char unit, unsigned char *buffer, unsigned long int sector, unsigned long int  count)
92
{
93
 
94
 
95
    unsigned long int block_add = 0;
96
    unsigned char scr[SECTOR_SIZE];
97
 
98
            block_add=sector;
99
            DBGA("\n writeSector %u, block_addr2 %u \n",sector,block_add);
100
            setup_bd_transfer(WRITE_OP, block_add , buffer);
101
 
102
            if (finnish_bd_transfer() == FALSE){
103
                printf("TRANSACTION FAILED, Buffer %x \n", buffer);
104
 
105
                //reset_card();  
106
               // sd_wait_rsp();
107
               // SD_REG(SD_SOFTWARE_RST)=1; 
108
 
109
                //SD_REG(SD_SOFTWARE_RST)=0; 
110
 
111
 
112
                DBGA("FREE BD TX/RX: 0x%x \n", SD_REG(BD_STATUS) );
113
 
114
 
115
                DBGA("TRY READ SECTOR \n");
116
                setup_bd_transfer(READ_OP, 526571008 , scr);
117
                finnish_bd_transfer();
118
               DBGA("PRINT test wreite to 526571008 \n");
119
               setup_bd_transfer(WRITE_OP, 526571008 , scr);
120
              finnish_bd_transfer();
121
 
122
                setup_bd_transfer(WRITE_OP, block_add , buffer);
123
                if (finnish_bd_transfer() == FALSE){
124
                   printf("TRANSACTION FAILED AGAIN!, Buffer %x \n", buffer);
125
                      return 0xff;
126
                }
127
 
128
            }
129
 
130
 
131
    return 0;
132
 
133
}
134
 
135
/*
136
        Get starting sector# of specified partition on drive #unit
137
        NOTE: This code ASSUMES an MBR on the disk.
138
        scratchsector should point to a SECTOR_SIZE scratch area
139
        Returns 0xffffffff for any error.
140
        If pactive is non-NULL, this function also returns the partition active flag.
141
        If pptype is non-NULL, this function also returns the partition type.
142
        If psize is non-NULL, this function also returns the partition size.
143
*/
144
 
145
 
146
unsigned long int DFS_GetPtnStart(unsigned char unit, unsigned char *scratchsector, unsigned char pnum, unsigned char *pactive, unsigned char *pptype, unsigned long int *psize)
147
{
148
        unsigned long int result;
149
        PMBR mbr = (PMBR) scratchsector;
150
 
151
        // DOS ptable supports maximum 4 partitions
152
        if (pnum > 3)
153
                return DFS_ERRMISC;
154
 
155
        // Read MBR from target media
156
        if (DFS_ReadSector(unit,scratchsector,0,1)) {
157
                return DFS_ERRMISC;
158
        }
159
 
160
        result = (unsigned long int) mbr->ptable[pnum].start_0 |
161
          (((unsigned long int) mbr->ptable[pnum].start_1) << 8) |
162
          (((unsigned long int) mbr->ptable[pnum].start_2) << 16) |
163
          (((unsigned long int) mbr->ptable[pnum].start_3) << 24);
164
 
165
 
166
   //unsigned char              active;                 // 0x80 if partition active
167
        //unsigned char         start_h;                // starting head
168
        //unsigned char         start_cs_l;             // starting cylinder and sector (low byte)
169
        //unsigned char         start_cs_h;             // starting cylinder and sector (high byte)
170
 
171
    printf("active 0:%x 1:%x 2:%x 3:%x \n",  mbr->ptable[pnum].active, mbr->ptable[pnum].start_h, mbr->ptable[pnum].start_cs_l,mbr->ptable[pnum].start_cs_h);
172
 
173
    printf("start 0:%x 1:%x 2:%x 3:%x \n", mbr->ptable[pnum].start_0, mbr->ptable[pnum].start_1,mbr->ptable[pnum].start_2,mbr->ptable[pnum].start_3);
174
        if (pactive)
175
                *pactive = mbr->ptable[pnum].active;
176
 
177
        if (pptype)
178
                *pptype = mbr->ptable[pnum].type;
179
 
180
        if (psize){
181
                *psize = (unsigned long int) mbr->ptable[pnum].size_0 |
182
                  (((unsigned long int) mbr->ptable[pnum].size_1) << 8) |
183
                  (((unsigned long int) mbr->ptable[pnum].size_2) << 16) |
184
                  (((unsigned long int) mbr->ptable[pnum].size_3) << 24);
185
          printf("size 0:%x 1:%x 2:%x 3:%x \n", mbr->ptable[pnum].size_0, mbr->ptable[pnum].size_1,mbr->ptable[pnum].size_2,mbr->ptable[pnum].size_3);
186
          }
187
 
188
        return result;
189
}
190
 
191
 
192
 
193
 ldiv_t ldiv (long int numer, long int denom)
194
{
195
   ldiv_t result;
196
 
197
  result.quot = numer / denom;
198
  result.rem = numer % denom;
199
 
200
  /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
201
     NUMER / DENOM is to be computed in infinite precision.  In
202
     other words, we should always truncate the quotient towards
203
     zero, never -infinity.  Machine division and remainer may
204
     work either way when one or both of NUMER or DENOM is
205
     negative.  If only one is negative and QUOT has been
206
     truncated towards -infinity, REM will have the same sign as
207
     DENOM and the opposite sign of NUMER; if both are negative
208
     and QUOT has been truncated towards -infinity, REM will be
209
     positive (will have the opposite sign of NUMER).  These are
210
     considered `wrong'.  If both are NUM and DENOM are positive,
211
     RESULT will always be positive.  This all boils down to: if
212
     NUMER >= 0, but REM < 0, we got the wrong answer.  In that
213
     case, to get the right answer, add 1 to QUOT and subtract
214
     DENOM from REM.  */
215
 
216
  if (numer >= 0 && result.rem < 0)
217
    {
218
      ++result.quot;
219
      result.rem -= denom;
220
    }
221
 
222
  return result;
223
}
224
 
225
 div_t div ( int numer,  int denom)
226
{
227
    div_t result;
228
 
229
  result.quot = numer / denom;
230
  result.rem = numer % denom;
231
 
232
  /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
233
     NUMER / DENOM is to be computed in infinite precision.  In
234
     other words, we should always truncate the quotient towards
235
     zero, never -infinity.  Machine division and remainer may
236
     work either way when one or both of NUMER or DENOM is
237
     negative.  If only one is negative and QUOT has been
238
     truncated towards -infinity, REM will have the same sign as
239
     DENOM and the opposite sign of NUMER; if both are negative
240
     and QUOT has been truncated towards -infinity, REM will be
241
     positive (will have the opposite sign of NUMER).  These are
242
     considered `wrong'.  If both are NUM and DENOM are positive,
243
     RESULT will always be positive.  This all boils down to: if
244
     NUMER >= 0, but REM < 0, we got the wrong answer.  In that
245
     case, to get the right answer, add 1 to QUOT and subtract
246
     DENOM from REM.  */
247
 
248
  if (numer >= 0 && result.rem < 0)
249
    {
250
      ++result.quot;
251
      result.rem -= denom;
252
    }
253
 
254
  return result;
255
}
256
/*
257
        Retrieve volume info from BPB and store it in a VOLINFO structure
258
        You must provide the unit and starting sector of the filesystem, and
259
        a pointer to a sector buffer for scratch
260
        Attempts to read BPB and glean information about the FS from that.
261
        Returns 0 OK, nonzero for any error.
262
*/
263
unsigned long int DFS_GetVolInfo(unsigned char unit, unsigned char *scratchsector, unsigned long int startsector, PVOLINFO volinfo)
264
{
265
        PLBR lbr = (PLBR) scratchsector;
266
        volinfo->unit = unit;
267
        volinfo->startsector = startsector;
268
 
269
        if(DFS_ReadSector(unit,scratchsector,startsector,1))
270
                return DFS_ERRMISC;
271
 
272
// tag: OEMID, refer dosfs.h
273
//      strncpy(volinfo->oemid, lbr->oemid, 8);
274
//      volinfo->oemid[8] = 0;
275
 
276
        volinfo->secperclus = lbr->bpb.secperclus;
277
        volinfo->reservedsecs = (unsigned short) lbr->bpb.reserved_l |
278
                  (((unsigned short) lbr->bpb.reserved_h) << 8);
279
 
280
        volinfo->numsecs =  (unsigned short) lbr->bpb.sectors_s_l |
281
                  (((unsigned short) lbr->bpb.sectors_s_h) << 8);
282
 
283
        if (!volinfo->numsecs)
284
                volinfo->numsecs = (unsigned long int) lbr->bpb.sectors_l_0 |
285
                  (((unsigned long int) lbr->bpb.sectors_l_1) << 8) |
286
                  (((unsigned long int) lbr->bpb.sectors_l_2) << 16) |
287
                  (((unsigned long int) lbr->bpb.sectors_l_3) << 24);
288
 
289
        // If secperfat is 0, we must be in a FAT32 volume; get secperfat
290
        // from the FAT32 EBPB. The volume label and system ID string are also
291
        // in different locations for FAT12/16 vs FAT32.
292
        volinfo->secperfat =  (unsigned short) lbr->bpb.secperfat_l |
293
                  (((unsigned short) lbr->bpb.secperfat_h) << 8);
294
        if (!volinfo->secperfat) {
295
                volinfo->secperfat = (unsigned long int) lbr->ebpb.ebpb32.fatsize_0 |
296
                  (((unsigned long int) lbr->ebpb.ebpb32.fatsize_1) << 8) |
297
                  (((unsigned long int) lbr->ebpb.ebpb32.fatsize_2) << 16) |
298
                  (((unsigned long int) lbr->ebpb.ebpb32.fatsize_3) << 24);
299
 
300
                memcpy(volinfo->label, lbr->ebpb.ebpb32.label, 11);
301
                volinfo->label[11] = 0;
302
 
303
// tag: OEMID, refer dosfs.h
304
//              memcpy(volinfo->system, lbr->ebpb.ebpb32.system, 8);
305
//              volinfo->system[8] = 0; 
306
        }
307
        else {
308
                memcpy(volinfo->label, lbr->ebpb.ebpb.label, 11);
309
                volinfo->label[11] = 0;
310
 
311
// tag: OEMID, refer dosfs.h
312
//              memcpy(volinfo->system, lbr->ebpb.ebpb.system, 8);
313
//              volinfo->system[8] = 0; 
314
        }
315
 
316
        // note: if rootentries is 0, we must be in a FAT32 volume.
317
        volinfo->rootentries =  (unsigned short) lbr->bpb.rootentries_l |
318
                  (((unsigned short) lbr->bpb.rootentries_h) << 8);
319
 
320
        // after extracting raw info we perform some useful precalculations
321
        volinfo->fat1 = startsector + volinfo->reservedsecs;
322
 
323
        // The calculation below is designed to round up the root directory size for FAT12/16
324
        // and to simply ignore the root directory for FAT32, since it's a normal, expandable
325
        // file in that situation.
326
        if (volinfo->rootentries) {
327
                volinfo->rootdir = volinfo->fat1 + (volinfo->secperfat * 2);
328
                volinfo->dataarea = volinfo->rootdir + (((volinfo->rootentries * 32) + (SECTOR_SIZE - 1)) / SECTOR_SIZE);
329
        }
330
        else {
331
                volinfo->dataarea = volinfo->fat1 + (volinfo->secperfat * 2);
332
                volinfo->rootdir = (unsigned long int) lbr->ebpb.ebpb32.root_0 |
333
                  (((unsigned long int) lbr->ebpb.ebpb32.root_1) << 8) |
334
                  (((unsigned long int) lbr->ebpb.ebpb32.root_2) << 16) |
335
                  (((unsigned long int) lbr->ebpb.ebpb32.root_3) << 24);
336
        }
337
 
338
        // Calculate number of clusters in data area and infer FAT type from this information.
339
        volinfo->numclusters = (volinfo->numsecs - volinfo->dataarea) / volinfo->secperclus;
340
        if (volinfo->numclusters < 4085)
341
                volinfo->filesystem = FAT12;
342
        else if (volinfo->numclusters < 65525)
343
                volinfo->filesystem = FAT16;
344
        else
345
                volinfo->filesystem = FAT32;
346
 
347
        return DFS_OK;
348
}
349
 
350
/*
351
        Fetch FAT entry for specified cluster number
352
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
353
        Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
354
        FAT entry.
355
        scratchcache should point to a UINT32. This variable caches the physical sector number
356
        last read into the scratch buffer for performance enhancement reasons.
357
*/
358
unsigned long int DFS_GetFAT(PVOLINFO volinfo, unsigned char *scratch, unsigned long int *scratchcache, unsigned long int cluster)
359
{
360
        unsigned long int offset, sector, result;
361
 
362
        if (volinfo->filesystem == FAT12) {
363
                offset = cluster + (cluster / 2);
364
        }
365
        else if (volinfo->filesystem == FAT16) {
366
                offset = cluster * 2;
367
        }
368
        else if (volinfo->filesystem == FAT32) {
369
                offset = cluster * 4;
370
        }
371
        else
372
                return 0x0ffffff7;      // FAT32 bad cluster    
373
 
374
        // at this point, offset is the BYTE offset of the desired sector from the start
375
        // of the FAT. Calculate the physical sector containing this FAT entry.
376
        sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
377
 
378
        // If this is not the same sector we last read, then read it into RAM
379
        if (sector != *scratchcache) {
380
                if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
381
                        // avoid anyone assuming that this cache value is still valid, which
382
                        // might cause disk corruption
383
                        *scratchcache = 0;
384
                        return 0x0ffffff7;      // FAT32 bad cluster    
385
                }
386
                *scratchcache = sector;
387
        }
388
 
389
        // At this point, we "merely" need to extract the relevant entry.
390
        // This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
391
        // may span a sector boundary. The normal way around this is always to read two
392
        // FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
393
        offset = ldiv(offset, SECTOR_SIZE).rem;
394
 
395
        if (volinfo->filesystem == FAT12) {
396
                // Special case for sector boundary - Store last byte of current sector.
397
                // Then read in the next sector and put the first byte of that sector into
398
                // the high byte of result.
399
                if (offset == SECTOR_SIZE - 1) {
400
                        result = (unsigned long int) scratch[offset];
401
                        sector++;
402
                        if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
403
                                // avoid anyone assuming that this cache value is still valid, which
404
                                // might cause disk corruption
405
                                *scratchcache = 0;
406
                                return 0x0ffffff7;      // FAT32 bad cluster    
407
                        }
408
                        *scratchcache = sector;
409
                        // Thanks to Claudio Leonel for pointing out this missing line.
410
                        result |= ((unsigned long int) scratch[0]) << 8;
411
                }
412
                else {
413
                        result = (unsigned long int) scratch[offset] |
414
                          ((unsigned long int) scratch[offset+1]) << 8;
415
                }
416
                if (cluster & 1)
417
                        result = result >> 4;
418
                else
419
                        result = result & 0xfff;
420
        }
421
        else if (volinfo->filesystem == FAT16) {
422
                result = (unsigned long int) scratch[offset] |
423
                  ((unsigned long int) scratch[offset+1]) << 8;
424
        }
425
        else if (volinfo->filesystem == FAT32) {
426
                result = ((unsigned long int) scratch[offset] |
427
                  ((unsigned long int) scratch[offset+1]) << 8 |
428
                  ((unsigned long int) scratch[offset+2]) << 16 |
429
                  ((unsigned long int) scratch[offset+3]) << 24) & 0x0fffffff;
430
        }
431
        else
432
                result = 0x0ffffff7;    // FAT32 bad cluster    
433
        return result;
434
}
435
 
436
 
437
/*
438
        Set FAT entry for specified cluster number
439
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
440
        Returns DFS_ERRMISC for any error, otherwise DFS_OK
441
        scratchcache should point to a UINT32. This variable caches the physical sector number
442
        last read into the scratch buffer for performance enhancement reasons.
443
 
444
        NOTE: This code is HIGHLY WRITE-INEFFICIENT, particularly for flash media. Considerable
445
        performance gains can be realized by caching the sector. However this is difficult to
446
        achieve on FAT12 without requiring 2 sector buffers of scratch space, and it is a design
447
        requirement of this code to operate on a single 512-byte scratch.
448
 
449
        If you are operating DOSFS over flash, you are strongly advised to implement a writeback
450
        cache in your physical I/O driver. This will speed up your code significantly and will
451
        also conserve power and flash write life.
452
*/
453
unsigned long int DFS_SetFAT(PVOLINFO volinfo, unsigned char *scratch, unsigned long int *scratchcache, unsigned long int cluster, unsigned long int new_contents)
454
{
455
        unsigned long int offset, sector, result;
456
        if (volinfo->filesystem == FAT12) {
457
                offset = cluster + (cluster / 2);
458
                new_contents &=0xfff;
459
        }
460
        else if (volinfo->filesystem == FAT16) {
461
                offset = cluster * 2;
462
                new_contents &=0xffff;
463
        }
464
        else if (volinfo->filesystem == FAT32) {
465
                offset = cluster * 4;
466
                new_contents &=0x0fffffff;      // FAT32 is really "FAT28"
467
        }
468
        else
469
                return DFS_ERRMISC;
470
 
471
        // at this point, offset is the BYTE offset of the desired sector from the start
472
        // of the FAT. Calculate the physical sector containing this FAT entry.
473
        sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
474
 
475
        // If this is not the same sector we last read, then read it into RAM
476
        if (sector != *scratchcache) {
477
                if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
478
                        // avoid anyone assuming that this cache value is still valid, which
479
                        // might cause disk corruption
480
                        *scratchcache = 0;
481
                        return DFS_ERRMISC;
482
                }
483
                *scratchcache = sector;
484
        }
485
 
486
        // At this point, we "merely" need to extract the relevant entry.
487
        // This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
488
        // may span a sector boundary. The normal way around this is always to read two
489
        // FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
490
        offset = ldiv(offset, SECTOR_SIZE).rem;
491
 
492
        if (volinfo->filesystem == FAT12) {
493
 
494
                // If this is an odd cluster, pre-shift the desired new contents 4 bits to
495
                // make the calculations below simpler
496
                if (cluster & 1)
497
                        new_contents = new_contents << 4;
498
 
499
                // Special case for sector boundary
500
                if (offset == SECTOR_SIZE - 1) {
501
 
502
                        // Odd cluster: High 12 bits being set
503
                        if (cluster & 1) {
504
                                scratch[offset] = (scratch[offset] & 0x0f) | new_contents & 0xf0;
505
                        }
506
                        // Even cluster: Low 12 bits being set
507
                        else {
508
                                scratch[offset] = new_contents & 0xff;
509
                        }
510
                        result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
511
                        // mirror the FAT into copy 2
512
                        if (DFS_OK == result)
513
                                result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
514
 
515
                        // If we wrote that sector OK, then read in the subsequent sector
516
                        // and poke the first byte with the remainder of this FAT entry.
517
                        if (DFS_OK == result) {
518
                                *scratchcache++;
519
                                result = DFS_ReadSector(volinfo->unit, scratch, *scratchcache, 1);
520
                                if (DFS_OK == result) {
521
                                        // Odd cluster: High 12 bits being set
522
                                        if (cluster & 1) {
523
                                                scratch[0] = new_contents & 0xff00;
524
                                        }
525
                                        // Even cluster: Low 12 bits being set
526
                                        else {
527
                                                scratch[0] = (scratch[0] & 0xf0) | new_contents & 0x0f;
528
                                        }
529
                                        result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
530
                                        // mirror the FAT into copy 2
531
                                        if (DFS_OK == result)
532
                                                result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
533
                                }
534
                                else {
535
                                        // avoid anyone assuming that this cache value is still valid, which
536
                                        // might cause disk corruption
537
                                        *scratchcache = 0;
538
                                }
539
                        }
540
                } // if (offset == SECTOR_SIZE - 1)
541
 
542
                // Not a sector boundary. But we still have to worry about if it's an odd
543
                // or even cluster number.
544
                else {
545
                        // Odd cluster: High 12 bits being set
546
                        if (cluster & 1) {
547
                                scratch[offset] = (scratch[offset] & 0x0f) | new_contents & 0xf0;
548
                                scratch[offset+1] = new_contents & 0xff00;
549
                        }
550
                        // Even cluster: Low 12 bits being set
551
                        else {
552
                                scratch[offset] = new_contents & 0xff;
553
                                scratch[offset+1] = (scratch[offset+1] & 0xf0) | new_contents & 0x0f;
554
                        }
555
                        result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
556
                        // mirror the FAT into copy 2
557
                        if (DFS_OK == result)
558
                                result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
559
                }
560
        }
561
        else if (volinfo->filesystem == FAT16) {
562
                scratch[offset] = (new_contents & 0xff);
563
                scratch[offset+1] = (new_contents & 0xff00) >> 8;
564
                result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
565
                // mirror the FAT into copy 2
566
                if (DFS_OK == result)
567
                        result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
568
        }
569
        else if (volinfo->filesystem == FAT32) {
570
                scratch[offset] = (new_contents & 0xff);
571
                scratch[offset+1] = (new_contents & 0xff00) >> 8;
572
                scratch[offset+2] = (new_contents & 0xff0000) >> 16;
573
                scratch[offset+3] = (scratch[offset+3] & 0xf0) | ((new_contents & 0x0f000000) >> 24);
574
                // Note well from the above: Per Microsoft's guidelines we preserve the upper
575
                // 4 bits of the FAT32 cluster value. It's unclear what these bits will be used
576
                // for; in every example I've encountered they are always zero.
577
                result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
578
                // mirror the FAT into copy 2
579
                if (DFS_OK == result)
580
                        result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
581
        }
582
        else
583
                result = DFS_ERRMISC;
584
 
585
        return result;
586
}
587
 
588
/*
589
        Convert a filename element from canonical (8.3) to directory entry (11) form
590
        src must point to the first non-separator character.
591
        dest must point to a 12-byte buffer.
592
*/
593
unsigned char *DFS_CanonicalToDir(unsigned char *dest, unsigned char *src)
594
{
595
        unsigned char *destptr = dest;
596
 
597
        memset(dest, ' ', 11);
598
        dest[11] = 0;
599
 
600
        while (*src && (*src != DIR_SEPARATOR) && (destptr - dest < 11)) {
601
                if (*src >= 'a' && *src <='z') {
602
                        *destptr++ = (*src - 'a') + 'A';
603
                        src++;
604
                }
605
                else if (*src == '.') {
606
                        src++;
607
                        destptr = dest + 8;
608
                }
609
                else {
610
                        *destptr++ = *src++;
611
                }
612
        }
613
 
614
        return dest;
615
}
616
 
617
/*
618
        Find the first unused FAT entry
619
        You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
620
        Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
621
        FAT entry.
622
        Returns FAT32 bad_sector (0x0ffffff7) if there is no free cluster available
623
*/
624
unsigned long int DFS_GetFreeFAT(PVOLINFO volinfo, unsigned char *scratch)
625
{
626
        unsigned long int i, result = 0xffffffff, scratchcache = 0;
627
 
628
        // Search starts at cluster 2, which is the first usable cluster
629
        // NOTE: This search can't terminate at a bad cluster, because there might
630
        // legitimately be bad clusters on the disk.
631
        for (i=2; i < volinfo->numclusters; i++) {
632
                result = DFS_GetFAT(volinfo, scratch, &scratchcache, i);
633
                if (!result) {
634
                        return i;
635
                }
636
        }
637
        return 0x0ffffff7;              // Can't find a free cluster
638
}
639
 
640
 
641
/*
642
        Open a directory for enumeration by DFS_GetNextDirEnt
643
        You must supply a populated VOLINFO (see DFS_GetVolInfo)
644
        The empty string or a string containing only the directory separator are
645
        considered to be the root directory.
646
        Returns 0 OK, nonzero for any error.
647
*/
648
unsigned long int DFS_OpenDir(PVOLINFO volinfo, unsigned char *dirname, PDIRINFO dirinfo)
649
{
650
        // Default behavior is a regular search for existing entries
651
        dirinfo->flags = 0;
652
 
653
        if (!strlen((char *) dirname) || (strlen((char *) dirname) == 1 && dirname[0] == DIR_SEPARATOR)) {
654
                if (volinfo->filesystem == FAT32) {
655
                        dirinfo->currentcluster = volinfo->rootdir;
656
                        dirinfo->currentsector = 0;
657
                        dirinfo->currententry = 0;
658
 
659
                        // read first sector of directory
660
                        return DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((volinfo->rootdir - 2) * volinfo->secperclus), 1);
661
                }
662
                else {
663
                        dirinfo->currentcluster = 0;
664
                        dirinfo->currentsector = 0;
665
                        dirinfo->currententry = 0;
666
 
667
                        // read first sector of directory
668
                        return DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1);
669
                }
670
        }
671
 
672
        // This is not the root directory. We need to find the start of this subdirectory.
673
        // We do this by devious means, using our own companion function DFS_GetNext.
674
        else {
675
                unsigned char tmpfn[12];
676
                unsigned char *ptr = dirname;
677
                unsigned long int result;
678
                DIRENT de;
679
 
680
                if (volinfo->filesystem == FAT32) {
681
                        dirinfo->currentcluster = volinfo->rootdir;
682
                        dirinfo->currentsector = 0;
683
                        dirinfo->currententry = 0;
684
 
685
                        // read first sector of directory
686
                        if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((volinfo->rootdir - 2) * volinfo->secperclus), 1))
687
                                return DFS_ERRMISC;
688
                }
689
                else {
690
                        dirinfo->currentcluster = 0;
691
                        dirinfo->currentsector = 0;
692
                        dirinfo->currententry = 0;
693
 
694
                        // read first sector of directory
695
                        if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1))
696
                                return DFS_ERRMISC;
697
                }
698
 
699
                // skip leading path separators
700
                while (*ptr == DIR_SEPARATOR && *ptr)
701
                        ptr++;
702
 
703
                // Scan the path from left to right, finding the start cluster of each entry
704
                // Observe that this code is inelegant, but obviates the need for recursion.
705
                while (*ptr) {
706
                        DFS_CanonicalToDir(tmpfn, ptr);
707
 
708
                        de.name[0] = 0;
709
 
710
                        do {
711
                                result = DFS_GetNext(volinfo, dirinfo, &de);
712
                        } while (!result && memcmp2(de.name, tmpfn, 11));
713
 
714
                        if (!memcmp2(de.name, tmpfn, 11) && ((de.attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)) {
715
                                if (volinfo->filesystem == FAT32) {
716
                                        dirinfo->currentcluster = (unsigned long int) de.startclus_l_l |
717
                                          ((unsigned long int) de.startclus_l_h) << 8 |
718
                                          ((unsigned long int) de.startclus_h_l) << 16 |
719
                                          ((unsigned long int) de.startclus_h_h) << 24;
720
                                }
721
                                else {
722
                                        dirinfo->currentcluster = (unsigned long int) de.startclus_l_l |
723
                                          ((unsigned long int) de.startclus_l_h) << 8;
724
                                }
725
                                dirinfo->currentsector = 0;
726
                                dirinfo->currententry = 0;
727
 
728
                                if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((dirinfo->currentcluster - 2) * volinfo->secperclus), 1))
729
                                        return DFS_ERRMISC;
730
                        }
731
                        else if (!memcmp2(de.name, tmpfn, 11) && !(de.attr & ATTR_DIRECTORY))
732
                                return DFS_NOTFOUND;
733
 
734
                        // seek to next item in list
735
                        while (*ptr != DIR_SEPARATOR && *ptr)
736
                                ptr++;
737
                        if (*ptr == DIR_SEPARATOR)
738
                                ptr++;
739
                }
740
 
741
                if (!dirinfo->currentcluster)
742
                        return DFS_NOTFOUND;
743
        }
744
        return DFS_OK;
745
}
746
 
747
/*
748
        Get next entry in opened directory structure. Copies fields into the dirent
749
        structure, updates dirinfo. Note that it is the _caller's_ responsibility to
750
        handle the '.' and '..' entries.
751
        A deleted file will be returned as a NULL entry (first char of filename=0)
752
        by this code. Filenames beginning with 0x05 will be translated to 0xE5
753
        automatically. Long file name entries will be returned as NULL.
754
        returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
755
        or DFS_ERRMISC for a media error
756
*/
757
unsigned long int DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent)
758
{
759
        unsigned long int tempint;      // required by DFS_GetFAT
760
 
761
        // Do we need to read the next sector of the directory?
762
        if (dirinfo->currententry >= SECTOR_SIZE / sizeof(DIRENT)) {
763
                dirinfo->currententry = 0;
764
                dirinfo->currentsector++;
765
 
766
                // Root directory; special case handling 
767
                // Note that currentcluster will only ever be zero if both:
768
                // (a) this is the root directory, and
769
                // (b) we are on a FAT12/16 volume, where the root dir can't be expanded
770
                if (dirinfo->currentcluster == 0) {
771
                        // Trying to read past end of root directory?
772
                        if (dirinfo->currentsector * (SECTOR_SIZE / sizeof(DIRENT)) >= volinfo->rootentries)
773
                                return DFS_EOF;
774
 
775
                        // Otherwise try to read the next sector
776
                        if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir + dirinfo->currentsector, 1))
777
                                return DFS_ERRMISC;
778
                }
779
 
780
                // Normal handling
781
                else {
782
                        if (dirinfo->currentsector >= volinfo->secperclus) {
783
                                dirinfo->currentsector = 0;
784
                                if ((dirinfo->currentcluster >= 0xff7 &&  volinfo->filesystem == FAT12) ||
785
                                  (dirinfo->currentcluster >= 0xfff7 &&  volinfo->filesystem == FAT16) ||
786
                                  (dirinfo->currentcluster >= 0x0ffffff7 &&  volinfo->filesystem == FAT32)) {
787
 
788
                                        // We are at the end of the directory chain. If this is a normal
789
                                        // find operation, we should indicate that there is nothing more
790
                                        // to see.
791
                                        if (!(dirinfo->flags & DFS_DI_BLANKENT))
792
                                                return DFS_EOF;
793
 
794
                                        // On the other hand, if this is a "find free entry" search,
795
                                        // we need to tell the caller to allocate a new cluster
796
                                        else
797
                                                return DFS_ALLOCNEW;
798
                                }
799
                                dirinfo->currentcluster = DFS_GetFAT(volinfo, dirinfo->scratch, &tempint, dirinfo->currentcluster);
800
                        }
801
                        if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((dirinfo->currentcluster - 2) * volinfo->secperclus) + dirinfo->currentsector, 1))
802
                                return DFS_ERRMISC;
803
                }
804
        }
805
 
806
        memcpy(dirent, &(((PDIRENT) dirinfo->scratch)[dirinfo->currententry]), sizeof(DIRENT));
807
 
808
        if (dirent->name[0] == 0) {               // no more files in this directory
809
                // If this is a "find blank" then we can reuse this name.
810
                if (dirinfo->flags & DFS_DI_BLANKENT)
811
                        return DFS_OK;
812
                else
813
                        return DFS_EOF;
814
        }
815
 
816
        if (dirent->name[0] == 0xe5)     // handle deleted file entries
817
                dirent->name[0] = 0;
818
        else if ((dirent->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)
819
                dirent->name[0] = 0;
820
        else if (dirent->name[0] == 0x05)        // handle kanji filenames beginning with 0xE5
821
                dirent->name[0] = 0xe5;
822
 
823
        dirinfo->currententry++;
824
 
825
        return DFS_OK;
826
}
827
 
828
/*
829
        INTERNAL
830
        Find a free directory entry in the directory specified by path
831
        This function MAY cause a disk write if it is necessary to extend the directory
832
        size.
833
        Note - di.scratch must be preinitialized to point to a sector scratch buffer
834
        de is a scratch structure
835
        Returns DFS_ERRMISC if a new entry could not be located or created
836
        de is updated with the same return information you would expect from DFS_GetNext
837
*/
838
unsigned long int DFS_GetFreeDirEnt(PVOLINFO volinfo, unsigned char *path, PDIRINFO di, PDIRENT de)
839
{
840
        unsigned long int tempclus,i;
841
 
842
        if (DFS_OpenDir(volinfo, path, di))
843
                return DFS_NOTFOUND;
844
 
845
        // Set "search for empty" flag so DFS_GetNext knows what we're doing
846
        di->flags |= DFS_DI_BLANKENT;
847
 
848
        // We seek through the directory looking for an empty entry
849
        // Note we are reusing tempclus as a temporary result holder.
850
        tempclus = 0;
851
        do {
852
                tempclus = DFS_GetNext(volinfo, di, de);
853
 
854
                // Empty entry found
855
                if (tempclus == DFS_OK && (!de->name[0])) {
856
                        return DFS_OK;
857
                }
858
 
859
                // End of root directory reached
860
                else if (tempclus == DFS_EOF)
861
                        return DFS_ERRMISC;
862
 
863
                else if (tempclus == DFS_ALLOCNEW) {
864
                        tempclus = DFS_GetFreeFAT(volinfo, di->scratch);
865
                        if (tempclus == 0x0ffffff7)
866
                                return DFS_ERRMISC;
867
 
868
                        // write out zeroed sectors to the new cluster
869
                        memset(di->scratch, 0, SECTOR_SIZE);
870
                        for (i=0;i<volinfo->secperclus;i++) {
871
                                if (DFS_WriteSector(volinfo->unit, di->scratch, volinfo->dataarea + ((tempclus - 2) * volinfo->secperclus) + i, 1))
872
                                        return DFS_ERRMISC;
873
                        }
874
                        // Point old end cluster to newly allocated cluster
875
                        i = 0;
876
                        DFS_SetFAT(volinfo, di->scratch, &i, di->currentcluster, tempclus);
877
 
878
                        // Update DIRINFO so caller knows where to place the new file                   
879
                        di->currentcluster = tempclus;
880
                        di->currentsector = 0;
881
                        di->currententry = 1;   // since the code coming after this expects to subtract 1
882
 
883
                        // Mark newly allocated cluster as end of chain                 
884
                        switch(volinfo->filesystem) {
885
                                case FAT12:             tempclus = 0xff8;       break;
886
                                case FAT16:             tempclus = 0xfff8;      break;
887
                                case FAT32:             tempclus = 0x0ffffff8;  break;
888
                                default:                return DFS_ERRMISC;
889
                        }
890
                        DFS_SetFAT(volinfo, di->scratch, &i, di->currentcluster, tempclus);
891
                }
892
        } while (!tempclus);
893
 
894
        // We shouldn't get here
895
        return DFS_ERRMISC;
896
}
897
 
898
/*
899
        Open a file for reading or writing. You supply populated VOLINFO, a path to the file,
900
        mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to
901
        provide a pointer to a sector-sized scratch buffer.
902
        Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used
903
        to access the file from this point on.
904
*/
905
unsigned long int DFS_OpenFile(PVOLINFO volinfo, unsigned char *path, unsigned char mode, unsigned char *scratch, PFILEINFO fileinfo)
906
{
907
        unsigned char tmppath[MAX_PATH];
908
        unsigned char filename[12];
909
        unsigned char *p;
910
        DIRINFO di;
911
        DIRENT de;
912
 
913
        // larwe 2006-09-16 +1 zero out file structure
914
        memset(fileinfo, 0, sizeof(FILEINFO));
915
 
916
        // save access mode
917
        fileinfo->mode = mode;
918
 
919
        // Get a local copy of the path. If it's longer than MAX_PATH, abort.
920
        strcpy2((char *) tmppath, (char *) path);
921
        tmppath[MAX_PATH - 1] = 0;
922
        if (strcmp2((char *) path,(char *) tmppath)) {
923
                return DFS_PATHLEN;
924
        }
925
 
926
 
927
        // strip leading path separators
928
        while (tmppath[0] == DIR_SEPARATOR)
929
                strcpy2((char *) tmppath, (char *) tmppath + 1);
930
 
931
        // Parse filename off the end of the supplied path
932
        p = tmppath;
933
        while (*(p++));
934
 
935
        p--;
936
        while (p > tmppath && *p != DIR_SEPARATOR) // larwe 9/16/06 ">=" to ">" bugfix
937
                p--;
938
        if (*p == DIR_SEPARATOR)
939
                p++;
940
 
941
        DFS_CanonicalToDir(filename, p);
942
 
943
        if (p > tmppath)
944
                p--;
945
        if (*p == DIR_SEPARATOR || p == tmppath) // larwe 9/16/06 +"|| p == tmppath" bugfix
946
                *p = 0;
947
 
948
        // At this point, if our path was MYDIR/MYDIR2/FILE.EXT, filename = "FILE    EXT" and
949
        // tmppath = "MYDIR/MYDIR2".
950
        di.scratch = scratch;
951
        if (DFS_OpenDir(volinfo, tmppath, &di))
952
                return DFS_NOTFOUND;
953
 
954
        while (!DFS_GetNext(volinfo, &di, &de)) {
955
 
956
                if (!memcmp2(de.name, filename, 11)) {
957
                        // You can't use this function call to open a directory.
958
                        if (de.attr & ATTR_DIRECTORY)
959
                                return DFS_NOTFOUND;
960
                        printf("get enxt \n");
961
                        fileinfo->volinfo = volinfo;
962
                        fileinfo->pointer = 0;
963
                        // The reason we store this extra info about the file is so that we can
964
                        // speedily update the file size, modification date, etc. on a file that is
965
                        // opened for writing.
966
                        if (di.currentcluster == 0)
967
                                fileinfo->dirsector = volinfo->rootdir + di.currentsector;
968
                        else
969
                                fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
970
                        fileinfo->diroffset = di.currententry - 1;
971
                        if (volinfo->filesystem == FAT32) {
972
                                fileinfo->cluster = (unsigned long int) de.startclus_l_l |
973
                                  ((unsigned long int) de.startclus_l_h) << 8 |
974
                                  ((unsigned long int) de.startclus_h_l) << 16 |
975
                                  ((unsigned long int) de.startclus_h_h) << 24;
976
                        }
977
                        else {
978
                                fileinfo->cluster = (unsigned long int) de.startclus_l_l |
979
                                  ((unsigned long int) de.startclus_l_h) << 8;
980
                        }
981
                        fileinfo->firstcluster = fileinfo->cluster;
982
                        fileinfo->filelen = (unsigned long int) de.filesize_0 |
983
                          ((unsigned long int) de.filesize_1) << 8 |
984
                          ((unsigned long int) de.filesize_2) << 16 |
985
                          ((unsigned long int) de.filesize_3) << 24;
986
 
987
                        return DFS_OK;
988
                }
989
        }
990
 
991
        // At this point, we KNOW the file does not exist. If the file was opened
992
        // with write access, we can create it.
993
        if (mode & DFS_WRITE) {
994
                unsigned long int cluster, temp;
995
 
996
                // Locate or create a directory entry for this file
997
                if (DFS_OK != DFS_GetFreeDirEnt(volinfo, tmppath, &di, &de))
998
                        return DFS_ERRMISC;
999
 
1000
                // put sane values in the directory entry
1001
                memset(&de, 0, sizeof(de));
1002
                memcpy(de.name, filename, 11);
1003
                de.crttime_l = 0x20;    // 01:01:00am, Jan 1, 2006.
1004
                de.crttime_h = 0x08;
1005
                de.crtdate_l = 0x11;
1006
                de.crtdate_h = 0x34;
1007
                de.lstaccdate_l = 0x11;
1008
                de.lstaccdate_h = 0x34;
1009
                de.wrttime_l = 0x20;
1010
                de.wrttime_h = 0x08;
1011
                de.wrtdate_l = 0x11;
1012
                de.wrtdate_h = 0x34;
1013
 
1014
                // allocate a starting cluster for the directory entry
1015
                cluster = DFS_GetFreeFAT(volinfo, scratch);
1016
 
1017
                de.startclus_l_l = cluster & 0xff;
1018
                de.startclus_l_h = (cluster & 0xff00) >> 8;
1019
                de.startclus_h_l = (cluster & 0xff0000) >> 16;
1020
                de.startclus_h_h = (cluster & 0xff000000) >> 24;
1021
 
1022
                // update FILEINFO for our caller's sake
1023
                fileinfo->volinfo = volinfo;
1024
                fileinfo->pointer = 0;
1025
                // The reason we store this extra info about the file is so that we can
1026
                // speedily update the file size, modification date, etc. on a file that is
1027
                // opened for writing.
1028
                if (di.currentcluster == 0)
1029
                        fileinfo->dirsector = volinfo->rootdir + di.currentsector;
1030
                else
1031
                        fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
1032
                fileinfo->diroffset = di.currententry - 1;
1033
                fileinfo->cluster = cluster;
1034
                fileinfo->firstcluster = cluster;
1035
                fileinfo->filelen = 0;
1036
 
1037
                // write the directory entry
1038
                // note that we no longer have the sector containing the directory entry,
1039
                // tragically, so we have to re-read it
1040
                if (DFS_ReadSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
1041
                        return DFS_ERRMISC;
1042
                memcpy(&(((PDIRENT) scratch)[di.currententry-1]), &de, sizeof(DIRENT));
1043
                if (DFS_WriteSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
1044
                        return DFS_ERRMISC;
1045
 
1046
                // Mark newly allocated cluster as end of chain                 
1047
                switch(volinfo->filesystem) {
1048
                        case FAT12:             cluster = 0xff8;        break;
1049
                        case FAT16:             cluster = 0xfff8;       break;
1050
                        case FAT32:             cluster = 0x0ffffff8;   break;
1051
                        default:                return DFS_ERRMISC;
1052
                }
1053
                temp = 0;
1054
                DFS_SetFAT(volinfo, scratch, &temp, fileinfo->cluster, cluster);
1055
 
1056
                return DFS_OK;
1057
        }
1058
 
1059
        return DFS_NOTFOUND;
1060
}
1061
 
1062
/*
1063
        Read an open file
1064
        You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
1065
        pointer to a SECTOR_SIZE scratch buffer.
1066
        Note that returning DFS_EOF is not an error condition. This function updates the
1067
        successcount field with the number of bytes actually read.
1068
*/
1069
unsigned long int DFS_ReadFile(PFILEINFO fileinfo, unsigned char *scratch, unsigned char *buffer, unsigned long int *successcount, unsigned long int len)
1070
{
1071
        unsigned long int remain;
1072
        unsigned long int result = DFS_OK;
1073
        unsigned long int sector;
1074
        unsigned long int bytesread;
1075
 
1076
        // Don't try to read past EOF
1077
        if (len > fileinfo->filelen - fileinfo->pointer)
1078
                len = fileinfo->filelen - fileinfo->pointer;
1079
 
1080
        remain = len;
1081
        *successcount = 0;
1082
 
1083
        while (remain && result == DFS_OK) {
1084
                // This is a bit complicated. The sector we want to read is addressed at a cluster
1085
                // granularity by the fileinfo->cluster member. The file pointer tells us how many
1086
                // extra sectors to add to that number.
1087
                sector = fileinfo->volinfo->dataarea +
1088
                  ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
1089
                  div(div(fileinfo->pointer,fileinfo->volinfo->secperclus * SECTOR_SIZE).rem, SECTOR_SIZE).quot;
1090
 
1091
                // Case 1 - File pointer is not on a sector boundary
1092
                if (div(fileinfo->pointer, SECTOR_SIZE).rem) {
1093
 
1094
            unsigned short tempreadsize;
1095
 
1096
 
1097
                        // We always have to go through scratch in this case
1098
                        result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1099
 
1100
                        // This is the number of bytes that we actually care about in the sector
1101
                        // just read.
1102
 
1103
                        tempreadsize = SECTOR_SIZE - (div(fileinfo->pointer, SECTOR_SIZE).rem);
1104
 
1105
 
1106
            // Case 1A - We want the entire remainder of the sector. After this
1107
                        // point, all passes through the read loop will be aligned on a sector
1108
                        // boundary, which allows us to go through the optimal path 2A below.
1109
                        if (remain >= tempreadsize) {
1110
                                memcpy(buffer, scratch + (SECTOR_SIZE - tempreadsize), tempreadsize);
1111
                                bytesread = tempreadsize;
1112
                                buffer += tempreadsize;
1113
                                fileinfo->pointer += tempreadsize;
1114
                                remain -= tempreadsize;
1115
                        }
1116
                        // Case 1B - This read concludes the file read operation
1117
                        else {
1118
                                memcpy(buffer, scratch + (SECTOR_SIZE - tempreadsize), remain);
1119
 
1120
                                buffer += remain;
1121
                                fileinfo->pointer += remain;
1122
                                bytesread = remain;
1123
                                remain = 0;
1124
                        }
1125
                }
1126
                // Case 2 - File pointer is on sector boundary
1127
                else {
1128
 
1129
                        // Case 2A - We have at least one more full sector to read and don't have
1130
                        // to go through the scratch buffer. You could insert optimizations here to
1131
                        // read multiple sectors at a time, if you were thus inclined (note that
1132
                        // the maximum multi-read you could perform is a single cluster, so it would
1133
                        // be advantageous to have code similar to case 1A above that would round the
1134
                        // pointer to a cluster boundary the first pass through, so all subsequent
1135
                        // [large] read requests would be able to go a cluster at a time).
1136
                        if (remain >= SECTOR_SIZE) {
1137
 
1138
                                result = DFS_ReadSector(fileinfo->volinfo->unit, buffer, sector, 1);
1139
 
1140
                remain -= SECTOR_SIZE;
1141
 
1142
                                buffer += SECTOR_SIZE;
1143
 
1144
                                fileinfo->pointer += SECTOR_SIZE;
1145
 
1146
                                bytesread = SECTOR_SIZE;
1147
 
1148
                        }
1149
                        // Case 2B - We are only reading a partial sector
1150
                        else {
1151
 
1152
                                result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1153
                                memcpy(buffer, scratch, remain);
1154
                                buffer += remain;
1155
                                fileinfo->pointer += remain;
1156
                                bytesread = remain;
1157
                                remain = 0;
1158
                        }
1159
                }
1160
 
1161
                *successcount += bytesread;
1162
 
1163
 
1164
                // check to see if we stepped over a cluster boundary
1165
                if (div(fileinfo->pointer - bytesread, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
1166
                  div(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
1167
                        // An act of minor evil - we use bytesread as a scratch integer, knowing that
1168
                        // its value is not used after updating *successcount above
1169
 
1170
            bytesread = 0;
1171
 
1172
            if (((fileinfo->volinfo->filesystem == FAT12) && (fileinfo->cluster >= 0xff8)) ||
1173
                          ((fileinfo->volinfo->filesystem == FAT16) && (fileinfo->cluster >= 0xfff8)) ||
1174
                          ((fileinfo->volinfo->filesystem == FAT32) && (fileinfo->cluster >= 0x0ffffff8)))
1175
                                result = DFS_EOF;
1176
                        else
1177
                                fileinfo->cluster = DFS_GetFAT(fileinfo->volinfo, scratch, &bytesread, fileinfo->cluster);
1178
                }
1179
        }
1180
 
1181
 
1182
        return result;
1183
}
1184
 
1185
/*
1186
        Seek file pointer to a given position
1187
        This function does not return status - refer to the fileinfo->pointer value
1188
        to see where the pointer wound up.
1189
        Requires a SECTOR_SIZE scratch buffer
1190
*/
1191
void DFS_Seek(PFILEINFO fileinfo, unsigned long int offset, unsigned char *scratch)
1192
{
1193
        unsigned long int tempint;
1194
 
1195
        // larwe 9/16/06 bugfix split case 0a/0b and changed fallthrough handling
1196
        // Case 0a - Return immediately for degenerate case
1197
        if (offset == fileinfo->pointer) {
1198
                return;
1199
        }
1200
 
1201
        // Case 0b - Don't allow the user to seek past the end of the file
1202
        if (offset > fileinfo->filelen) {
1203
                offset = fileinfo->filelen;
1204
                // NOTE NO RETURN HERE!
1205
        }
1206
 
1207
        // Case 1 - Simple rewind to start
1208
        // Note _intentional_ fallthrough from Case 0b above
1209
        if (offset == 0) {
1210
                fileinfo->cluster = fileinfo->firstcluster;
1211
                fileinfo->pointer = 0;
1212
                return;         // larwe 9/16/06 +1 bugfix
1213
        }
1214
        // Case 2 - Seeking backwards. Need to reset and seek forwards
1215
        else if (offset < fileinfo->pointer) {
1216
                fileinfo->cluster = fileinfo->firstcluster;
1217
                fileinfo->pointer = 0;
1218
                // NOTE NO RETURN HERE!
1219
        }
1220
 
1221
        // Case 3 - Seeking forwards
1222
        // Note _intentional_ fallthrough from Case 2 above
1223
 
1224
        // Case 3a - Seek size does not cross cluster boundary - 
1225
        // very simple case
1226
        // larwe 9/16/06 changed .rem to .quot in both div calls, bugfix
1227
        if (div(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot ==
1228
          div(fileinfo->pointer + offset, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
1229
                fileinfo->pointer = offset;
1230
        }
1231
        // Case 3b - Seeking across cluster boundary(ies)
1232
        else {
1233
                // round file pointer down to cluster boundary
1234
                fileinfo->pointer = div(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot *
1235
                  fileinfo->volinfo->secperclus * SECTOR_SIZE;
1236
 
1237
                // seek by clusters
1238
                // larwe 9/30/06 bugfix changed .rem to .quot in both div calls
1239
                while (div(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
1240
                  div(fileinfo->pointer + offset, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
1241
 
1242
                        fileinfo->cluster = DFS_GetFAT(fileinfo->volinfo, scratch, &tempint, fileinfo->cluster);
1243
                        // Abort if there was an error
1244
                        if (fileinfo->cluster == 0x0ffffff7) {
1245
                                fileinfo->pointer = 0;
1246
                                fileinfo->cluster = fileinfo->firstcluster;
1247
                                return;
1248
                        }
1249
                        fileinfo->pointer += SECTOR_SIZE * fileinfo->volinfo->secperclus;
1250
                }
1251
 
1252
                // since we know the cluster is right, we have no more work to do
1253
                fileinfo->pointer = offset;
1254
        }
1255
}
1256
 
1257
/*
1258
        Delete a file
1259
        scratch must point to a sector-sized buffer
1260
*/
1261
unsigned long int DFS_UnlinkFile(PVOLINFO volinfo, unsigned char *path, unsigned char *scratch)
1262
{
1263
        PDIRENT de = (PDIRENT) scratch;
1264
        FILEINFO fi;
1265
        unsigned long int cache = 0;
1266
        unsigned long int tempclus;
1267
 
1268
        // DFS_OpenFile gives us all the information we need to delete it
1269
        if (DFS_OK != DFS_OpenFile(volinfo, path, DFS_READ, scratch, &fi))
1270
                return DFS_NOTFOUND;
1271
 
1272
        // First, read the directory sector and delete that entry
1273
        if (DFS_ReadSector(volinfo->unit, scratch, fi.dirsector, 1))
1274
                return DFS_ERRMISC;
1275
        ((PDIRENT) scratch)[fi.diroffset].name[0] = 0xe5;
1276
        if (DFS_WriteSector(volinfo->unit, scratch, fi.dirsector, 1))
1277
                return DFS_ERRMISC;
1278
 
1279
        // Now follow the cluster chain to free the file space
1280
        while (!((volinfo->filesystem == FAT12 && fi.firstcluster >= 0x0ff7) ||
1281
          (volinfo->filesystem == FAT16 && fi.firstcluster >= 0xfff7) ||
1282
          (volinfo->filesystem == FAT32 && fi.firstcluster >= 0x0ffffff7))) {
1283
                tempclus = fi.firstcluster;
1284
 
1285
                fi.firstcluster = DFS_GetFAT(volinfo, scratch, &cache, fi.firstcluster);
1286
                DFS_SetFAT(volinfo, scratch, &cache, tempclus, 0);
1287
 
1288
        }
1289
        return DFS_OK;
1290
}
1291
 
1292
 
1293
/*
1294
        Write an open file
1295
        You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
1296
        pointer to a SECTOR_SIZE scratch buffer.
1297
        This function updates the successcount field with the number of bytes actually written.
1298
*/
1299
unsigned long int DFS_WriteFile(PFILEINFO fileinfo, unsigned char *scratch, unsigned char *buffer, unsigned long int *successcount, unsigned long int len)
1300
{
1301
        unsigned long int remain;
1302
        unsigned long int result = DFS_OK;
1303
        unsigned long int sector;
1304
        unsigned long int byteswritten;
1305
 
1306
        // Don't allow writes to a file that's open as readonly
1307
        if (!(fileinfo->mode & DFS_WRITE))
1308
                return DFS_ERRMISC;
1309
 
1310
        remain = len;
1311
        *successcount = 0;
1312
 
1313
        while (remain && result == DFS_OK) {
1314
                // This is a bit complicated. The sector we want to read is addressed at a cluster
1315
                // granularity by the fileinfo->cluster member. The file pointer tells us how many
1316
                // extra sectors to add to that number.
1317
                sector = fileinfo->volinfo->dataarea +
1318
                  ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
1319
                  div(div(fileinfo->pointer,fileinfo->volinfo->secperclus * SECTOR_SIZE).rem, SECTOR_SIZE).quot;
1320
 
1321
                // Case 1 - File pointer is not on a sector boundary
1322
                if (div(fileinfo->pointer, SECTOR_SIZE).rem) {
1323
                        unsigned short tempsize;
1324
            printf("CASE 1 \n");
1325
                        // We always have to go through scratch in this case
1326
                        result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1327
 
1328
                        // This is the number of bytes that we don't want to molest in the
1329
                        // scratch sector just read.
1330
                        tempsize = div(fileinfo->pointer, SECTOR_SIZE).rem;
1331
 
1332
                        // Case 1A - We are writing the entire remainder of the sector. After
1333
                        // this point, all passes through the read loop will be aligned on a
1334
                        // sector boundary, which allows us to go through the optimal path
1335
                        // 2A below.
1336
                        if (remain >= SECTOR_SIZE - tempsize) {
1337
                                memcpy(scratch + tempsize, buffer, SECTOR_SIZE - tempsize);
1338
                                if (!result)
1339
                                        result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1340
 
1341
                                byteswritten = SECTOR_SIZE - tempsize;
1342
                                buffer += SECTOR_SIZE - tempsize;
1343
                                fileinfo->pointer += SECTOR_SIZE - tempsize;
1344
                                if (fileinfo->filelen < fileinfo->pointer) {
1345
                                        fileinfo->filelen = fileinfo->pointer;
1346
                                }
1347
                                remain -= SECTOR_SIZE - tempsize;
1348
                        }
1349
                        // Case 1B - This concludes the file write operation
1350
                        else {
1351
                  printf("CASE 1B \n");
1352
                                memcpy(scratch + tempsize, buffer, remain);
1353
                                if (!result)
1354
                                        result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1355
 
1356
                                buffer += remain;
1357
                                fileinfo->pointer += remain;
1358
                                if (fileinfo->filelen < fileinfo->pointer) {
1359
                                        fileinfo->filelen = fileinfo->pointer;
1360
                                }
1361
                                byteswritten = remain;
1362
                                remain = 0;
1363
                        }
1364
                } // case 1
1365
                // Case 2 - File pointer is on sector boundary
1366
                else {
1367
              printf("CASE 2 \n");
1368
                        // Case 2A - We have at least one more full sector to write and don't have
1369
                        // to go through the scratch buffer. You could insert optimizations here to
1370
                        // write multiple sectors at a time, if you were thus inclined. Refer to
1371
                        // similar notes in DFS_ReadFile.
1372
                        if (remain >= SECTOR_SIZE) {
1373
                                result = DFS_WriteSector(fileinfo->volinfo->unit, buffer, sector, 1);
1374
                                remain -= SECTOR_SIZE;
1375
                                buffer += SECTOR_SIZE;
1376
                                fileinfo->pointer += SECTOR_SIZE;
1377
                                if (fileinfo->filelen < fileinfo->pointer) {
1378
                                        fileinfo->filelen = fileinfo->pointer;
1379
                                }
1380
                                byteswritten = SECTOR_SIZE;
1381
                        }
1382
                        // Case 2B - We are only writing a partial sector and potentially need to
1383
                        // go through the scratch buffer.
1384
                        else {
1385
                   printf("CASE 2B \n");
1386
                                // If the current file pointer is not yet at or beyond the file
1387
                                // length, we are writing somewhere in the middle of the file and
1388
                                // need to load the original sector to do a read-modify-write.
1389
                                if (fileinfo->pointer < fileinfo->filelen) {
1390
                                        result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1391
                                        if (!result) {
1392
                                                memcpy(scratch, buffer, remain);
1393
                                                result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1394
                                        }
1395
                                }
1396
                                else {
1397
                                        result = DFS_WriteSector(fileinfo->volinfo->unit, buffer, sector, 1);
1398
                                }
1399
 
1400
                                buffer += remain;
1401
                                fileinfo->pointer += remain;
1402
                                if (fileinfo->filelen < fileinfo->pointer) {
1403
                                        fileinfo->filelen = fileinfo->pointer;
1404
                                }
1405
                                byteswritten = remain;
1406
                                remain = 0;
1407
                        }
1408
                }
1409
 
1410
                *successcount += byteswritten;
1411
        printf("Writen byte %d \n", *successcount );
1412
                // check to see if we stepped over a cluster boundary
1413
                if (div(fileinfo->pointer - byteswritten, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
1414
                  div(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
1415
                        unsigned long int lastcluster;
1416
 
1417
                        // We've transgressed into another cluster. If we were already at EOF,
1418
                        // we need to allocate a new cluster.
1419
                        // An act of minor evil - we use byteswritten as a scratch integer, knowing
1420
                        // that its value is not used after updating *successcount above
1421
                        byteswritten = 0;
1422
 
1423
                        lastcluster = fileinfo->cluster;
1424
                        fileinfo->cluster = DFS_GetFAT(fileinfo->volinfo, scratch, &byteswritten, fileinfo->cluster);
1425
 
1426
                        // Allocate a new cluster?
1427
                        if (((fileinfo->volinfo->filesystem == FAT12) && (fileinfo->cluster >= 0xff8)) ||
1428
                          ((fileinfo->volinfo->filesystem == FAT16) && (fileinfo->cluster >= 0xfff8)) ||
1429
                          ((fileinfo->volinfo->filesystem == FAT32) && (fileinfo->cluster >= 0x0ffffff8))) {
1430
                                unsigned long int tempclus;
1431
 
1432
                                tempclus = DFS_GetFreeFAT(fileinfo->volinfo, scratch);
1433
                                byteswritten = 0; // invalidate cache
1434
                                if (tempclus == 0x0ffffff7)
1435
                                        return DFS_ERRMISC;
1436
 
1437
                                // Link new cluster onto file
1438
                                DFS_SetFAT(fileinfo->volinfo, scratch, &byteswritten, lastcluster, tempclus);
1439
                                fileinfo->cluster = tempclus;
1440
 
1441
                                // Mark newly allocated cluster as end of chain                 
1442
                                switch(fileinfo->volinfo->filesystem) {
1443
                                        case FAT12:             tempclus = 0xff8;       break;
1444
                                        case FAT16:             tempclus = 0xfff8;      break;
1445
                                        case FAT32:             tempclus = 0x0ffffff8;  break;
1446
                                        default:                return DFS_ERRMISC;
1447
                                }
1448
                                DFS_SetFAT(fileinfo->volinfo, scratch, &byteswritten, fileinfo->cluster, tempclus);
1449
 
1450
                                result = DFS_OK;
1451
                        }
1452
                        // No else clause is required.
1453
                }
1454
        }
1455
 
1456
        // Update directory entry
1457
                if (DFS_ReadSector(fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1))
1458
                        return DFS_ERRMISC;
1459
                ((PDIRENT) scratch)[fileinfo->diroffset].filesize_0 = fileinfo->filelen & 0xff;
1460
                ((PDIRENT) scratch)[fileinfo->diroffset].filesize_1 = (fileinfo->filelen & 0xff00) >> 8;
1461
                ((PDIRENT) scratch)[fileinfo->diroffset].filesize_2 = (fileinfo->filelen & 0xff0000) >> 16;
1462
                ((PDIRENT) scratch)[fileinfo->diroffset].filesize_3 = (fileinfo->filelen & 0xff000000) >> 24;
1463
                if (DFS_WriteSector(fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1))
1464
                        return DFS_ERRMISC;
1465
        return result;
1466
}
1467
 
1468
int memcmp2(const void* s1, const void* s2,size_t n)
1469
{
1470
    const unsigned char *p1 = s1, *p2 = s2;
1471
    while(n--)
1472
        if( *p1 != *p2 )
1473
            return *p1 - *p2;
1474
        else
1475
            *p1++,*p2++;
1476
    return 0;
1477
}
1478
 
1479
char *strcpy2(char *dest,  char* src)
1480
{
1481
    char *ret = dest;
1482
    while (*dest++ = *src++)
1483
        ;
1484
    return ret;
1485
}
1486
 
1487
int strcmp2(const char* s1, const char* s2)
1488
{
1489
    while(*s1 && (*s1==*s2))
1490
        s1++,s2++;
1491
    return *(const unsigned char*)s1-*(const unsigned char*)s2;
1492
}

powered by: WebSVN 2.1.0

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