-
Notifications
You must be signed in to change notification settings - Fork 0
/
FSIO.c
9541 lines (8526 loc) · 316 KB
/
FSIO.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/******************************************************************************
*
* Microchip Memory Disk Drive File System
*
******************************************************************************
* FileName: FSIO.c
* Dependencies: GenericTypeDefs.h
* FSIO.h
* Physical interface include file (SD-SPI.h, CF-PMP.h, ...)
* string.h
* stdlib.h
* FSDefs.h
* ctype.h
* salloc.h
* Processor: PIC18/PIC24/dsPIC30/dsPIC33/PIC32
* Compiler: C18/C30/C32
* Company: Microchip Technology, Inc.
* Version: 1.2.4
* 1.2.4.1 LDJ optimizing FSfread
*
* Software License Agreement
*
* The software supplied herewith by Microchip Technology Incorporated
* (the “Company”) for its PICmicro® Microcontroller is intended and
* supplied to you, the Company’s customer, for use solely and
* exclusively on Microchip PICmicro Microcontroller products. The
* software is owned by the Company and/or its supplier, and is
* protected under applicable copyright laws. All rights are reserved.
* Any use in violation of the foregoing restrictions may subject the
* user to criminal sanctions under applicable laws, as well as to
* civil liability for the breach of the terms and conditions of this
* license.
*
* THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
********************************************************************
File Description:
Change History:
Rev Description
----- -----------
1.2.5 Fixed bug that prevented writes to alternate FAT tables
Fixed bug that prevented FAT being updated when media is re-inserted
1.2.6 Fixed bug that resulted in a bus error when attempts to read a invalid memory region
Fixed bug that prevented the Windows Explorer to show the Date Creation field for directories
x.x.x Fixed issue on some USB drives where the information written
to the drive is cached in a RAM for 500ms before it is
written to the flash unless the sector is accessed again.
Add some error recovery for FAT32 systems when there is
corruption in the boot sector.
********************************************************************/
#include "Compiler.h"
#include "MDD File System/FSIO.h"
#include "GenericTypeDefs.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
#include "MDD File System/FSDefs.h"
#ifdef ALLOW_FSFPRINTF
#include "stdarg.h"
#endif
#ifdef FS_DYNAMIC_MEM
#ifdef __18CXX
#include "salloc.h"
#endif
#endif
#ifndef ALLOW_WRITES
#ifdef ALLOW_FORMATS
#error Write functions must be enabled to use the format function
#endif
#ifdef ALLOW_FSFPRINTF
#error Write functions must be enabled to use the FSfprintf function
#endif
#endif
#ifdef USEREALTIMECLOCK
#ifdef USERDEFINEDCLOCK
#error Please select only one timestamp clocking mode in FSconfig.h
#endif
#ifdef INCREMENTTIMESTAMP
#error Please select only one timestamp clocking mode in FSconfig.h
#endif
#elif defined USERDEFINEDCLOCK
#ifdef INCREMENTTIMESTAMP
#error Please select only one timestamp clocking mode in FSconfig.h
#endif
#endif
/*****************************************************************************/
/* Global Variables */
/*****************************************************************************/
#ifndef FS_DYNAMIC_MEM
FSFILE gFileArray[FS_MAX_FILES_OPEN]; // Array that contains file information (static allocation)
BYTE gFileSlotOpen[FS_MAX_FILES_OPEN]; // Array that indicates which elements of gFileArray are available for use
#endif
#if defined(USEREALTIMECLOCK) || defined(USERDEFINEDCLOCK)
// Timing variables
BYTE gTimeCrtMS; // Global time variable (for timestamps) used to indicate create time (milliseconds)
WORD gTimeCrtTime; // Global time variable (for timestamps) used to indicate create time
WORD gTimeCrtDate; // Global time variable (for timestamps) used to indicate create date
WORD gTimeAccDate; // Global time variable (for timestamps) used to indicate last access date
WORD gTimeWrtTime; // Global time variable (for timestamps) used to indicate last update time
WORD gTimeWrtDate; // Global time variable (for timestamps) used to indicate last update date
#endif
DWORD gLastFATSectorRead = 0xFFFFFFFF; // Global variable indicating which FAT sector was read last
BYTE gNeedFATWrite = FALSE; // Global variable indicating that there is information that needs to be written to the FAT
FSFILE * gBufferOwner = NULL; // Global variable indicating which file is using the data buffer
DWORD gLastDataSectorRead = 0xFFFFFFFF; // Global variable indicating which data sector was read last
BYTE gNeedDataWrite = FALSE; // Global variable indicating that there is information that needs to be written to the data section
BYTE nextClusterIsLast = FALSE; // Global variable indicating that the entries in a directory align with a cluster boundary
BYTE gBufferZeroed = FALSE; // Global variable indicating that the data buffer contains all zeros
DWORD FatRootDirClusterValue; // Global variable containing the cluster number of the root dir (0 for FAT12/16)
BYTE FSerrno; // Global error variable. Set to one of many error codes after each function call.
DWORD TempClusterCalc; // Global variable used to store the calculated value of the cluster of a specified sector.
BYTE dirCleared; // Global variable used by the "recursive" FSrmdir function to indicate that all subdirectories and files have been deleted from the target directory.
BYTE recache = FALSE; // Global variable used by the "recursive" FSrmdir function to indicate that additional cache reads are needed.
FSFILE tempCWDobj; // Global variable used to preserve the current working directory information.
FSFILE gFileTemp; // Global variable used for file operations.
#ifdef ALLOW_DIRS
FSFILE cwd; // Global current working directory
FSFILE * cwdptr = &cwd; // Pointer to the current working directory
#endif
#ifdef __18CXX
#pragma udata dataBuffer = DATA_BUFFER_ADDRESS
BYTE gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer
#pragma udata FATBuffer = FAT_BUFFER_ADDRESS
BYTE gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer
#endif
#if defined (__C30__) || defined (__PIC32MX__)
BYTE __attribute__ ((aligned(4))) gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer
BYTE __attribute__ ((aligned(4))) gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer
#endif
#pragma udata
DISK gDiskData; // Global structure containing device information.
/************************************************************************/
/* Structures and defines */
/************************************************************************/
// Directory entry structure
typedef struct
{
char DIR_Name[DIR_NAMESIZE]; // File name
char DIR_Extension[DIR_EXTENSION]; // File extension
BYTE DIR_Attr; // File attributes
BYTE DIR_NTRes; // Reserved byte
BYTE DIR_CrtTimeTenth; // Create time (millisecond field)
WORD DIR_CrtTime; // Create time (second, minute, hour field)
WORD DIR_CrtDate; // Create date
WORD DIR_LstAccDate; // Last access date
WORD DIR_FstClusHI; // High word of the entry's first cluster number
WORD DIR_WrtTime; // Last update time
WORD DIR_WrtDate; // Last update date
WORD DIR_FstClusLO; // Low word of the entry's first cluster number
DWORD DIR_FileSize; // The 32-bit file size
}_DIRENTRY;
typedef _DIRENTRY * DIRENTRY; // A pointer to a directory entry structure
#define DIRECTORY 0x12 // Value indicating that the CreateFileEntry function will be creating a directory
#define DIRENTRIES_PER_SECTOR (MEDIA_SECTOR_SIZE / 32) // The number of directory entries in a sector
// internal errors
#define CE_FAT_EOF 60 // Error that indicates an attempt to read FAT entries beyond the end of the file
#define CE_EOF 61 // Error that indicates that the end of the file has been reached
typedef FSFILE * FILEOBJ; // Pointer to an FSFILE object
#ifdef ALLOW_FSFPRINTF
#define _FLAG_MINUS 0x1 // FSfprintf minus flag indicator
#define _FLAG_PLUS 0x2 // FSfprintf plus flag indicator
#define _FLAG_SPACE 0x4 // FSfprintf space flag indicator
#define _FLAG_OCTO 0x8 // FSfprintf octothorpe (hash mark) flag indicator
#define _FLAG_ZERO 0x10 // FSfprintf zero flag indicator
#define _FLAG_SIGNED 0x80 // FSfprintf signed flag indicator
#ifdef __18CXX
#define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag
#define _FMT_LONG 1 // FSfprintf 32-bit argument size flag
#define _FMT_SHRTLONG 2 // FSfprintf 24-bit argument size flag
#define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag
#else
#define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag
#define _FMT_LONGLONG 1 // FSfprintf 64-bit argument size flag
#define _FMT_LONG 2 // FSfprintf 32-bit argument size flag
#define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag
#endif
#ifdef __18CXX
static const rom char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits
#else
static const char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits
#endif
#endif
/************************************************************************************/
/* Prototypes */
/************************************************************************************/
DWORD ReadFAT (DISK *dsk, DWORD ccls);
DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead);
BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle);
DWORD Cluster2Sector(DISK * disk, DWORD cluster);
DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle);
#ifdef INCREMENTTIMESTAMP
void IncrementTimeStamp(DIRENTRY dir);
#elif defined USEREALTIMECLOCK
void CacheTime (void);
#endif
#if defined (__C30__) || defined (__PIC32MX__)
BYTE ReadByte( BYTE* pBuffer, WORD index );
WORD ReadWord( BYTE* pBuffer, WORD index );
DWORD ReadDWord( BYTE* pBuffer, WORD index );
#endif
void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource);
BYTE ValidateChars (char * FileName, BYTE mode);
BYTE FormatFileName( const char* fileName, char* fN2, BYTE mode);
CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode);
BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n);
CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type);
// Write functions
#ifdef ALLOW_WRITES
BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry);
BYTE flushData (void);
CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters);
BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode);
BYTE FAT_erase_cluster_chain (DWORD cluster, DISK * dsk);
DWORD FATfindEmptyCluster(FILEOBJ fo);
BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle);
BYTE PopulateEntries(FILEOBJ fo, char *name , WORD *fHandle, BYTE mode);
CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster);
BYTE EraseCluster(DISK *disk, DWORD cluster);
CETYPE CreateFirstCluster(FILEOBJ fo);
DWORD WriteFAT (DISK *dsk, DWORD ccls, DWORD value, BYTE forceWrite);
CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode);
#endif
// Directory functions
#ifdef ALLOW_DIRS
BYTE GetPreviousEntry (FSFILE * fo);
BYTE FormatDirName (char * string, BYTE mode);
int CreateDIR (char * path);
BYTE writeDotEntries (DISK * dsk, DWORD dotAddress, DWORD dotdotAddress);
int eraseDir (char * path);
#ifdef ALLOW_PGMFUNCTIONS
#ifdef ALLOW_WRITES
int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr);
int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs);
#endif
int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr);
#else
#ifdef ALLOW_WRITES
int mkdirhelper (BYTE mode, char * ramptr, char * romptr);
int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs);
#endif
int chdirhelper (BYTE mode, char * ramptr, char * romptr);
#endif
#endif
#ifdef ALLOW_FSFPRINTF
#ifdef __18CXX
int FSvfprintf (auto FSFILE *handle, auto const rom char *formatString, auto va_list ap);
#else
int FSvfprintf (FSFILE *handle, const char *formatString, va_list ap);
#endif
int FSputc (char c, FSFILE * file);
unsigned char str_put_n_chars (FSFILE * handle, unsigned char n, char c);
#endif
BYTE DISKmount( DISK *dsk);
BYTE LoadMBR(DISK *dsk);
BYTE LoadBootSector(DISK *dsk);
DWORD GetFullClusterNumber(DIRENTRY entry);
/*************************************************************************
Function:
int FSInit(void)
Summary:
Function to initialize the device.
Conditions:
The physical device should be connected to the microcontroller.
Input:
None
Return Values:
TRUE - Initialization successful
FALSE - Initialization unsuccessful
Side Effects:
The FSerrno variable will be changed.
Description:
Initializes the static or dynamic memory slots for holding file
structures. Initializes the device with the DISKmount function. Loads
MBR and boot sector information. Initializes the current working
directory to the root directory for the device if directory support
is enabled.
Remarks:
None
*************************************************************************/
int FSInit(void)
{
int fIndex;
#ifndef FS_DYNAMIC_MEM
for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ )
gFileSlotOpen[fIndex] = TRUE;
#else
#ifdef __18CXX
SRAMInitHeap();
#endif
#endif
gBufferZeroed = FALSE;
gNeedFATWrite = FALSE;
gLastFATSectorRead = 0xFFFFFFFF;
gLastDataSectorRead = 0xFFFFFFFF;
MDD_InitIO();
if(DISKmount(&gDiskData) == CE_GOOD)
{
// Initialize the current working directory to the root
#ifdef ALLOW_DIRS
cwdptr->dsk = &gDiskData;
cwdptr->sec = 0;
cwdptr->pos = 0;
cwdptr->seek = 0;
cwdptr->size = 0;
cwdptr->name[0] = '\\';
for (fIndex = 1; fIndex < 11; fIndex++)
{
cwdptr->name[fIndex] = 0x20;
}
cwdptr->entry = 0;
cwdptr->attributes = ATTR_DIRECTORY;
// "FatRootDirClusterValue" indicates the root
cwdptr->dirclus = FatRootDirClusterValue;
cwdptr->dirccls = FatRootDirClusterValue;
#endif
FSerrno = 0;
return TRUE;
}
return FALSE;
}
/********************************************************************************
Function:
CETYPE FILEfind (FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode)
Summary
Finds a file on the device
Conditions:
This function should not be called by the user.
Input:
foDest - FSFILE object containing information of the file found
foCompareTo - FSFILE object containing the name/attr of the file to be
found
cmd -
- LOOK_FOR_EMPTY_ENTRY: Search for empty entry.
- LOOK_FOR_MATCHING_ENTRY: Search for matching entry.
mode -
- 0: Match file exactly with default attributes.
- 1: Match file to user-specified attributes.
Return Values:
CE_GOOD - File found.
CE_FILE_NOT_FOUND - File not found.
Side Effects:
None.
Description:
The FILEfind function will sequentially cache directory entries within
the current working directory into the foDest FSFILE object. If the cmd
parameter is specified as LOOK_FOR_EMPTY_ENTRY the search will continue
until an empty directory entry is found. If the cmd parameter is specified
as LOOK_FOR_MATCHING_ENTRY these entries will be compared to the foCompareTo
object until a match is found or there are no more entries in the current
working directory. If the mode is specified a '0' the attributes of the FSFILE
entries are irrelevant. If the mode is specified as '1' the attributes of the
foDest entry must match the attributes specified in the foCompareTo file and
partial string search characters may bypass portions of the comparison.
Remarks:
None
********************************************************************************/
CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode)
{
WORD attrib, compareAttrib;
WORD fHandle = foDest->entry; // current entry counter
BYTE state,index; // state of the current object
CETYPE statusB = CE_FILE_NOT_FOUND;
BYTE character,test;
// reset the cluster
foDest->dirccls = foDest->dirclus;
compareAttrib = 0xFFFF ^ foCompareTo->attributes; // Attribute to be compared as per application layer request
if (fHandle == 0)
{
if (Cache_File_Entry(foDest, &fHandle, TRUE) == NULL)
{
statusB = CE_BADCACHEREAD;
}
}
else
{
if ((fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) != 0) // Maximum 16 entries possible
{
if (Cache_File_Entry (foDest, &fHandle, TRUE) == NULL)
{
statusB = CE_BADCACHEREAD;
}
}
}
if (statusB != CE_BADCACHEREAD)
{
// Loop until you reach the end or find the file
while(1)
{
if(statusB!=CE_GOOD) //First time entry always here
{
state = Fill_File_Object(foDest, &fHandle);
if(state == NO_MORE) // Reached the end of available files. Comparision over and file not found so quit.
{
break;
}
}
else // statusB == CE_GOOD then exit
{
break; // Code below intializes"statusB = CE_GOOD;" so, if no problem in the filled file, Exit the while loop.
}
if(state == FOUND) // Validate the correct matching of filled file data with the required(to be found) one.
{
/* We got something */
// get the attributes
attrib = foDest->attributes;
attrib &= ATTR_MASK;
switch (mode)
{
case 0:
// see if we are a volume id or hidden, ignore
if(attrib != ATTR_VOLUME)
{
statusB = CE_GOOD;
character = (BYTE)'m'; // random value
// search for one. if status = TRUE we found one
for(index = 0; index < DIR_NAMECOMP; index++)
{
// get the source character
character = foDest->name[index];
// get the destination character
test = foCompareTo->name[index];
if(tolower(character) != tolower(test))
{
statusB = CE_FILE_NOT_FOUND; // Nope its not a match
break;
}
}// for loop
} // not dir nor vol
break;
case 1:
// Check for attribute match
if (((attrib & compareAttrib) == 0) && (attrib != ATTR_LONG_NAME))
{
statusB = CE_GOOD; // Indicate the already filled file data is correct and go back
character = (BYTE)'m'; // random value
if (foCompareTo->name[0] != '*') //If "*" is passed for comparion as 1st char then don't proceed. Go back, file alreay found.
{
for (index = 0; index < DIR_NAMESIZE; index++)
{
// Get the source character
character = foDest->name[index];
// Get the destination character
test = foCompareTo->name[index];
if (test == '*')
break;
if (test != '?')
{
if(tolower(character) != tolower(test))
{
statusB = CE_FILE_NOT_FOUND; // it's not a match
break;
}
}
}
}
// Before calling this "FILEfind" fn, "formatfilename" must be called. Hence, extn always starts from position "8".
if ((foCompareTo->name[8] != '*') && (statusB == CE_GOOD))
{
for (index = 8; index < DIR_NAMECOMP; index++)
{
// Get the source character
character = foDest->name[index];
// Get the destination character
test = foCompareTo->name[index];
if (test == '*')
break;
if (test != '?')
{
if(tolower(character) != tolower(test))
{
statusB = CE_FILE_NOT_FOUND; // it's not a match
break;
}
}
}
}
} // Attribute match
break;
}
} // not found
else
{
/*** looking for an empty/re-usable entry ***/
if ( cmd == LOOK_FOR_EMPTY_ENTRY)
statusB = CE_GOOD;
} // found or not
// increment it no matter what happened
fHandle++;
}// while
}
return(statusB);
} // FILEFind
/**************************************************************************
Function:
CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
Summary:
Loads file information from the device
Conditions:
This function should not be called by the user.
Input:
fo - File to be opened
fHandle - Location of file
type -
- WRITE - Create a new file or replace an existing file
- READ - Read data from an existing file
- APPEND - Append data to an existing file
Return Values:
CE_GOOD - FILEopen successful
CE_NOT_INIT - Device is not yet initialized
CE_FILE_NOT_FOUND - Could not find the file on the device
CE_BAD_SECTOR_READ - A bad read of a sector occured
Side Effects:
None
Description:
This function will cache a directory entry in the directory specified
by the dirclus parameter of hte FSFILE object 'fo.' The offset of the
entry in the directory is specified by fHandle. Once the directory entry
has been loaded, the first sector of the file can be loaded using the
cluster value specified in the directory entry. The type argument will
specify the mode the files will be opened in. This will allow this
function to set the correct read/write flags for the file.
Remarks:
If the mode the file is being opened in is a plus mode (e.g. READ+) the
flags will be modified further in the FSfopen function.
**************************************************************************/
CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
{
DISK *dsk; //Disk structure
BYTE r; //Result of search for file
DWORD l; //lba of first sector of first cluster
CETYPE error = CE_GOOD;
dsk = (DISK *)(fo->dsk);
if (dsk->mount == FALSE)
{
error = CE_NOT_INIT;
}
else
{
// load the sector
fo->dirccls = fo->dirclus;
// Cache no matter what if it's the first entry
if (*fHandle == 0)
{
if (Cache_File_Entry(fo, fHandle, TRUE) == NULL)
{
error = CE_BADCACHEREAD;
}
}
else
{
// If it's not the first, only cache it if it's
// not divisible by the number of entries per sector
// If it is, Fill_File_Object will cache it
if ((*fHandle & 0xf) != 0)
{
if (Cache_File_Entry (fo, fHandle, TRUE) == NULL)
{
error = CE_BADCACHEREAD;
}
}
}
// Fill up the File Object with the information pointed to by fHandle
r = Fill_File_Object(fo, fHandle);
if (r != FOUND)
error = CE_FILE_NOT_FOUND;
else
{
fo->seek = 0; // first byte in file
fo->ccls = fo->cluster; // first cluster
fo->sec = 0; // first sector in the cluster
fo->pos = 0; // first byte in sector/cluster
if ( r == NOT_FOUND)
{
error = CE_FILE_NOT_FOUND;
}
else
{
// Determine the lba of the selected sector and load
l = Cluster2Sector(dsk,fo->ccls);
#ifdef ALLOW_WRITES
if (gNeedDataWrite)
if (flushData())
return CE_WRITE_ERROR;
#endif
gBufferOwner = fo;
if (gLastDataSectorRead != l)
{
gBufferZeroed = FALSE;
if ( !MDD_SectorRead( l, dsk->buffer))
error = CE_BAD_SECTOR_READ;
gLastDataSectorRead = l;
}
} // -- found
fo->flags.FileWriteEOF = FALSE;
// Set flag for operation type
#ifdef ALLOW_WRITES
if (type == 'w' || type == 'a')
{
fo->flags.write = 1; //write or append
fo->flags.read = 0;
}
else
{
#endif
fo->flags.write = 0; //read
fo->flags.read = 1;
#ifdef ALLOW_WRITES
} // -- flags
#endif
} // -- r = Found
} // -- Mounted
return (error);
} // -- FILEopen
/*************************************************************************
Function:
BYTE FILEget_next_cluster(FILEOBJ fo, WORD n)
Summary:
Step through a chain of clusters
Conditions:
This function should not be called by the user.
Input:
fo - The file to get the next cluster of
n - Number of links in the FAT cluster chain to jump through
Return Values:
CE_GOOD - Operation successful
CE_BAD_SECTOR_READ - A bad read occured of a sector
CE_INVALID_CLUSTER - Invalid cluster value \> maxcls
CE_FAT_EOF - Fat attempt to read beyond EOF
Side Effects:
None
Description:
This function will load 'n' proximate clusters for a file from
the FAT on the device. It will stop checking for clusters if the
ReadFAT function returns an error, if it reaches the last cluster in
a file, or if the device tries to read beyond the last cluster used
by the device.
Remarks:
None
*************************************************************************/
BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n)
{
DWORD c, c2, ClusterFailValue, LastClustervalue;
BYTE error = CE_GOOD;
DISK * disk;
disk = fo->dsk;
/* Settings based on FAT type */
switch (disk->type)
{
#ifdef SUPPORT_FAT32 // If FAT32 supported.
case FAT32:
LastClustervalue = LAST_CLUSTER_FAT32;
ClusterFailValue = CLUSTER_FAIL_FAT32;
break;
#endif
case FAT12:
LastClustervalue = LAST_CLUSTER_FAT12;
ClusterFailValue = CLUSTER_FAIL_FAT16;
break;
case FAT16:
default:
LastClustervalue = LAST_CLUSTER_FAT16;
ClusterFailValue = CLUSTER_FAIL_FAT16;
break;
}
// loop n times
do
{
// get the next cluster link from FAT
c2 = fo->ccls;
if ( (c = ReadFAT( disk, c2)) == ClusterFailValue)
error = CE_BAD_SECTOR_READ;
else
{
// check if cluster value is valid
if ( c >= disk->maxcls)
{
error = CE_INVALID_CLUSTER;
}
// compare against max value of a cluster in FAT
// return if eof
if ( c >= LastClustervalue) // check against eof
{
error = CE_FAT_EOF;
}
}
// update the FSFILE structure
fo->ccls = c;
} while (--n > 0 && error == CE_GOOD);// loop end
return(error);
} // get next cluster
/**************************************************************************
Function:
BYTE DISKmount ( DISK *dsk)
Summary:
Initialies the device and loads MBR and boot sector information
Conditions:
This function should not be called by the user.
Input:
dsk - The disk structure to be initialized.
Return Values:
CE_GOOD - Disk mounted
CE_INIT_ERROR - Initialization error has occured
CE_UNSUPPORTED_SECTOR_SIZE - Media sector size bigger than
MEDIA_SECTOR_SIZE as defined in FSconfig.h.
Side Effects:
None
Description:
This function will use the function pointed to by the MDD_MediaInitialize
function pointer to initialize the device (if any initialization is
required). It then attempts to load the master boot record with the
LoadMBR function and the boot sector with the LoadBootSector function.
These two functions will be used to initialize a global DISK structure
that will be used when accessing file information in the future.
Remarks:
None
**************************************************************************/
BYTE DISKmount( DISK *dsk)
{
BYTE error = CE_GOOD;
MEDIA_INFORMATION *mediaInformation;
dsk->mount = FALSE; // default invalid
dsk->buffer = gDataBuffer; // assign buffer
// Initialize the device
mediaInformation = MDD_MediaInitialize();
if (mediaInformation->errorCode != MEDIA_NO_ERROR)
{
error = CE_INIT_ERROR;
FSerrno = CE_INIT_ERROR;
}
else
{
// If the media initialization routine determined the sector size,
// check it and make sure we can support it.
if (mediaInformation->validityFlags.bits.sectorSize)
{
dsk->sectorSize = mediaInformation->sectorSize;
if (mediaInformation->sectorSize > MEDIA_SECTOR_SIZE)
{
error = CE_UNSUPPORTED_SECTOR_SIZE;
FSerrno = CE_UNSUPPORTED_SECTOR_SIZE;
return error;
}
}
// Load the Master Boot Record (partition)
if((error = LoadMBR(dsk)) == CE_GOOD)
{
// Now the boot sector
if((error = LoadBootSector(dsk)) == CE_GOOD)
dsk->mount = TRUE; // Mark that the DISK mounted successfully
}
} // -- Load file parameters
return(error);
} // -- mount
/********************************************************************
Function:
CETYPE LoadMBR ( DISK *dsk)
Summary:
Loads the MBR and extracts necessary information
Conditions:
This function should not be called by the user.
Input:
dsk - The disk containing the master boot record to be loaded
Return Values:
CE_GOOD - MBR loaded successfully
CE_BAD_SECTOR_READ - A bad read occured of a sector
CE_BAD_PARTITION - The boot record is bad
Side Effects:
None
Description:
The LoadMBR function will use the function pointed to by the
MDD_SectorRead function pointer to read the 0 sector from the
device. If a valid boot signature is obtained, this function
will compare fields in that cached sector to the values that
would be present if that sector was a boot sector. If all of
those values match, it will be assumed that the device does not
have a master boot record and the 0 sector is actually the boot
sector. Otherwise, data about the partition and the actual
location of the boot sector will be loaded from the MBR into
the DISK structure pointed to by 'dsk.'
Remarks:
None
********************************************************************/
BYTE LoadMBR(DISK *dsk)
{
PT_MBR Partition;
BYTE error = CE_GOOD;
BYTE type;
BootSec BSec;
// Get the partition table from the MBR
if ( MDD_SectorRead( FO_MBR, dsk->buffer) != TRUE)
{
error = CE_BAD_SECTOR_READ;
FSerrno = CE_BAD_SECTOR_READ;
}
else
{
// Check if the card has no MBR
BSec = (BootSec) dsk->buffer;
if((BSec->Signature0 == FAT_GOOD_SIGN_0) && (BSec->Signature1 == FAT_GOOD_SIGN_1))
{
// Technically, the OEM name is not for indication
// The alternative is to read the CIS from attribute
// memory. See the PCMCIA metaformat for more details
#if defined (__C30__) || defined (__PIC32MX__)
if (ReadByte( dsk->buffer, BSI_FSTYPE ) == 'F' && \
ReadByte( dsk->buffer, BSI_FSTYPE + 1 ) == 'A' && \
ReadByte( dsk->buffer, BSI_FSTYPE + 2 ) == 'T' && \
ReadByte( dsk->buffer, BSI_FSTYPE + 3 ) == '1' && \
ReadByte( dsk->buffer, BSI_BOOTSIG) == 0x29)
#else
if (BSec->FAT.FAT_16.BootSec_FSType[0] == 'F' && \
BSec->FAT.FAT_16.BootSec_FSType[1] == 'A' && \
BSec->FAT.FAT_16.BootSec_FSType[2] == 'T' && \
BSec->FAT.FAT_16.BootSec_FSType[3] == '1' && \
BSec->FAT.FAT_16.BootSec_BootSig == 0x29)
#endif
{
dsk->firsts = 0;
dsk->type = FAT16;
return CE_GOOD;
}
else
{
#if defined (__C30__) || defined (__PIC32MX__)
if (ReadByte( dsk->buffer, BSI_FAT32_FSTYPE ) == 'F' && \
ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 1 ) == 'A' && \
ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 2 ) == 'T' && \
ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 3 ) == '3' && \
ReadByte( dsk->buffer, BSI_FAT32_BOOTSIG) == 0x29)
#else
if (BSec->FAT.FAT_32.BootSec_FilSysType[0] == 'F' && \
BSec->FAT.FAT_32.BootSec_FilSysType[1] == 'A' && \
BSec->FAT.FAT_32.BootSec_FilSysType[2] == 'T' && \
BSec->FAT.FAT_32.BootSec_FilSysType[3] == '3' && \
BSec->FAT.FAT_32.BootSec_BootSig == 0x29)
#endif
{
dsk->firsts = 0;
dsk->type = FAT32;
return CE_GOOD;
}
}
}
// assign it the partition table strucutre
Partition = (PT_MBR)dsk->buffer;
// Ensure its good
if((Partition->Signature0 != FAT_GOOD_SIGN_0) || (Partition->Signature1 != FAT_GOOD_SIGN_1))
{
FSerrno = CE_BAD_PARTITION;
error = CE_BAD_PARTITION;
}
else
{
/* Valid Master Boot Record Loaded */
// Get the 32 bit offset to the first partition
dsk->firsts = Partition->Partition0.PTE_FrstSect;
// check if the partition type is acceptable
type = Partition->Partition0.PTE_FSDesc;
switch (type)
{
case 0x01:
dsk->type = FAT12;
break;
case 0x04:
case 0x06:
case 0x0E:
dsk->type = FAT16;
break;
case 0x0B:
case 0x0C:
#ifdef SUPPORT_FAT32 // If FAT32 supported.
dsk->type = FAT32; // FAT32 is supported too
#else
FSerrno = CE_CARDFAT32;
error = CE_CARDFAT32;
#endif
break;
default:
FSerrno = CE_UNSUPPORTED_FS;
error = CE_UNSUPPORTED_FS;
} // switch
}
}
return(error);
}// -- LoadMBR
/**************************************************************************