Line No. | Rev | Author | Line |
---|---|---|---|
1 | 32 | kaklik | /****************************************************************************** |
2 | * |
||
3 | * Microchip Memory Disk Drive File System |
||
4 | * |
||
5 | ****************************************************************************** |
||
6 | * FileName: FSIO.c |
||
7 | * Dependencies: GenericTypeDefs.h |
||
8 | * FSIO.h |
||
9 | * Physical interface include file (SD-SPI.h, CF-PMP.h, ...) |
||
10 | * string.h |
||
11 | * stdlib.h |
||
12 | * FSDefs.h |
||
13 | * ctype.h |
||
14 | * salloc.h |
||
15 | * Processor: PIC18/PIC24/dsPIC30/dsPIC33/PIC32 |
||
16 | * Compiler: C18/C30/C32 |
||
17 | * Company: Microchip Technology, Inc. |
||
18 | * |
||
19 | * Software License Agreement |
||
20 | * |
||
21 | * The software supplied herewith by Microchip Technology Incorporated |
||
22 | * (the Company) for its PICmicro® Microcontroller is intended and |
||
23 | * supplied to you, the Companys customer, for use solely and |
||
24 | * exclusively on Microchip PICmicro Microcontroller products. The |
||
25 | * software is owned by the Company and/or its supplier, and is |
||
26 | * protected under applicable copyright laws. All rights are reserved. |
||
27 | * Any use in violation of the foregoing restrictions may subject the |
||
28 | * user to criminal sanctions under applicable laws, as well as to |
||
29 | * civil liability for the breach of the terms and conditions of this |
||
30 | * license. |
||
31 | * |
||
32 | * THIS SOFTWARE IS PROVIDED IN AN AS IS CONDITION. NO WARRANTIES, |
||
33 | * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED |
||
34 | * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
||
35 | * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, |
||
36 | * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR |
||
37 | * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. |
||
38 | * |
||
39 | ******************************************************************** |
||
40 | File Description: |
||
41 | |||
42 | Change History: |
||
43 | Rev Description |
||
44 | ----- ----------- |
||
45 | 1.2.5 Fixed bug that prevented writes to alternate FAT tables |
||
46 | 1.2.5 Fixed bug that prevented FAT being updated when media is re-inserted |
||
47 | 1.2.6 Fixed bug that resulted in a bus error when attempts to read a invalid memory region |
||
48 | 1.2.6 Fixed bug that prevented the Windows Explorer to show the Date Creation field for directories |
||
49 | ********************************************************************/ |
||
50 | |||
51 | #include "Compiler.h" |
||
52 | #include "MDD File System\FSIO.h" |
||
53 | #include "GenericTypeDefs.h" |
||
54 | #include "string.h" |
||
55 | #include "stdlib.h" |
||
56 | #include "ctype.h" |
||
57 | #include "MDD File System\FSDefs.h" |
||
58 | |||
59 | #ifdef ALLOW_FSFPRINTF |
||
60 | #include "stdarg.h" |
||
61 | #endif |
||
62 | |||
63 | #ifdef FS_DYNAMIC_MEM |
||
64 | #ifdef __18CXX |
||
65 | #include "salloc.h" |
||
66 | #endif |
||
67 | #endif |
||
68 | |||
69 | #ifndef ALLOW_WRITES |
||
70 | #ifdef ALLOW_FORMATS |
||
71 | #error Write functions must be enabled to use the format function |
||
72 | #endif |
||
73 | #ifdef ALLOW_FSFPRINTF |
||
74 | #error Write functions must be enabled to use the FSfprintf function |
||
75 | #endif |
||
76 | #endif |
||
77 | |||
78 | #ifdef USEREALTIMECLOCK |
||
79 | #ifdef USERDEFINEDCLOCK |
||
80 | #error Please select only one timestamp clocking mode in FSconfig.h |
||
81 | #endif |
||
82 | #ifdef INCREMENTTIMESTAMP |
||
83 | #error Please select only one timestamp clocking mode in FSconfig.h |
||
84 | #endif |
||
85 | #elif defined USERDEFINEDCLOCK |
||
86 | #ifdef INCREMENTTIMESTAMP |
||
87 | #error Please select only one timestamp clocking mode in FSconfig.h |
||
88 | #endif |
||
89 | #endif |
||
90 | /*****************************************************************************/ |
||
91 | /* Global Variables */ |
||
92 | /*****************************************************************************/ |
||
93 | |||
94 | #ifndef FS_DYNAMIC_MEM |
||
95 | FSFILE gFileArray[FS_MAX_FILES_OPEN]; // Array that contains file information (static allocation) |
||
96 | BYTE gFileSlotOpen[FS_MAX_FILES_OPEN]; // Array that indicates which elements of gFileArray are available for use |
||
97 | #endif |
||
98 | |||
99 | #if defined(USEREALTIMECLOCK) || defined(USERDEFINEDCLOCK) |
||
100 | // Timing variables |
||
101 | BYTE gTimeCrtMS; // Global time variable (for timestamps) used to indicate create time (milliseconds) |
||
102 | WORD gTimeCrtTime; // Global time variable (for timestamps) used to indicate create time |
||
103 | WORD gTimeCrtDate; // Global time variable (for timestamps) used to indicate create date |
||
104 | WORD gTimeAccDate; // Global time variable (for timestamps) used to indicate last access date |
||
105 | WORD gTimeWrtTime; // Global time variable (for timestamps) used to indicate last update time |
||
106 | WORD gTimeWrtDate; // Global time variable (for timestamps) used to indicate last update date |
||
107 | #endif |
||
108 | |||
109 | DWORD gLastFATSectorRead = 0xFFFFFFFF; // Global variable indicating which FAT sector was read last |
||
110 | BYTE gNeedFATWrite = FALSE; // Global variable indicating that there is information that needs to be written to the FAT |
||
111 | FSFILE * gBufferOwner = NULL; // Global variable indicating which file is using the data buffer |
||
112 | DWORD gLastDataSectorRead = 0xFFFFFFFF; // Global variable indicating which data sector was read last |
||
113 | BYTE gNeedDataWrite = FALSE; // Global variable indicating that there is information that needs to be written to the data section |
||
114 | BYTE nextClusterIsLast = FALSE; // Global variable indicating that the entries in a directory align with a cluster boundary |
||
115 | |||
116 | BYTE gBufferZeroed = FALSE; // Global variable indicating that the data buffer contains all zeros |
||
117 | |||
118 | DWORD FatRootDirClusterValue; // Global variable containing the cluster number of the root dir (0 for FAT12/16) |
||
119 | |||
120 | BYTE FSerrno; // Global error variable. Set to one of many error codes after each function call. |
||
121 | |||
122 | DWORD TempClusterCalc; // Global variable used to store the calculated value of the cluster of a specified sector. |
||
123 | BYTE dirCleared; // Global variable used by the "recursive" FSrmdir function to indicate that all subdirectories and files have been deleted from the target directory. |
||
124 | BYTE recache = FALSE; // Global variable used by the "recursive" FSrmdir function to indicate that additional cache reads are needed. |
||
125 | FSFILE tempCWDobj; // Global variable used to preserve the current working directory information. |
||
126 | FSFILE gFileTemp; // Global variable used for file operations. |
||
127 | |||
128 | #ifdef ALLOW_DIRS |
||
129 | FSFILE cwd; // Global current working directory |
||
130 | FSFILE * cwdptr = &cwd; // Pointer to the current working directory |
||
131 | #endif |
||
132 | |||
133 | |||
134 | #ifdef __18CXX |
||
135 | #pragma udata dataBuffer = DATA_BUFFER_ADDRESS |
||
136 | BYTE gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer |
||
137 | #pragma udata FATBuffer = FAT_BUFFER_ADDRESS |
||
138 | BYTE gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer |
||
139 | #endif |
||
140 | |||
141 | #if defined (__C30__) || defined (__PIC32MX__) |
||
142 | BYTE __attribute__ ((aligned(4))) gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer |
||
143 | BYTE __attribute__ ((aligned(4))) gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer |
||
144 | #endif |
||
145 | |||
146 | |||
147 | #pragma udata |
||
148 | |||
149 | DISK gDiskData; // Global structure containing device information. |
||
150 | |||
151 | |||
152 | |||
153 | /************************************************************************/ |
||
154 | /* Structures and defines */ |
||
155 | /************************************************************************/ |
||
156 | |||
157 | // Directory entry structure |
||
158 | typedef struct |
||
159 | { |
||
160 | char DIR_Name[DIR_NAMESIZE]; // File name |
||
161 | char DIR_Extension[DIR_EXTENSION]; // File extension |
||
162 | BYTE DIR_Attr; // File attributes |
||
163 | BYTE DIR_NTRes; // Reserved byte |
||
164 | BYTE DIR_CrtTimeTenth; // Create time (millisecond field) |
||
165 | WORD DIR_CrtTime; // Create time (second, minute, hour field) |
||
166 | WORD DIR_CrtDate; // Create date |
||
167 | WORD DIR_LstAccDate; // Last access date |
||
168 | WORD DIR_FstClusHI; // High word of the entry's first cluster number |
||
169 | WORD DIR_WrtTime; // Last update time |
||
170 | WORD DIR_WrtDate; // Last update date |
||
171 | WORD DIR_FstClusLO; // Low word of the entry's first cluster number |
||
172 | DWORD DIR_FileSize; // The 32-bit file size |
||
173 | }_DIRENTRY; |
||
174 | |||
175 | typedef _DIRENTRY * DIRENTRY; // A pointer to a directory entry structure |
||
176 | |||
177 | #define DIRECTORY 0x12 // Value indicating that the CreateFileEntry function will be creating a directory |
||
178 | |||
179 | #define DIRENTRIES_PER_SECTOR (MEDIA_SECTOR_SIZE / 32) // The number of directory entries in a sector |
||
180 | |||
181 | // internal errors |
||
182 | #define CE_FAT_EOF 60 // Error that indicates an attempt to read FAT entries beyond the end of the file |
||
183 | #define CE_EOF 61 // Error that indicates that the end of the file has been reached |
||
184 | |||
185 | typedef FSFILE * FILEOBJ; // Pointer to an FSFILE object |
||
186 | |||
187 | #ifdef ALLOW_FSFPRINTF |
||
188 | |||
189 | #define _FLAG_MINUS 0x1 // FSfprintf minus flag indicator |
||
190 | #define _FLAG_PLUS 0x2 // FSfprintf plus flag indicator |
||
191 | #define _FLAG_SPACE 0x4 // FSfprintf space flag indicator |
||
192 | #define _FLAG_OCTO 0x8 // FSfprintf octothorpe (hash mark) flag indicator |
||
193 | #define _FLAG_ZERO 0x10 // FSfprintf zero flag indicator |
||
194 | #define _FLAG_SIGNED 0x80 // FSfprintf signed flag indicator |
||
195 | |||
196 | #ifdef __18CXX |
||
197 | #define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag |
||
198 | #define _FMT_LONG 1 // FSfprintf 32-bit argument size flag |
||
199 | #define _FMT_SHRTLONG 2 // FSfprintf 24-bit argument size flag |
||
200 | #define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag |
||
201 | #else |
||
202 | #define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag |
||
203 | #define _FMT_LONGLONG 1 // FSfprintf 64-bit argument size flag |
||
204 | #define _FMT_LONG 2 // FSfprintf 32-bit argument size flag |
||
205 | #define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag |
||
206 | #endif |
||
207 | |||
208 | #ifdef __18CXX |
||
209 | static const rom char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits |
||
210 | #else |
||
211 | static const char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits |
||
212 | #endif |
||
213 | |||
214 | #endif |
||
215 | |||
216 | /************************************************************************************/ |
||
217 | /* Prototypes */ |
||
218 | /************************************************************************************/ |
||
219 | |||
220 | DWORD ReadFAT (DISK *dsk, DWORD ccls); |
||
221 | DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead); |
||
222 | BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle); |
||
223 | DWORD Cluster2Sector(DISK * disk, DWORD cluster); |
||
224 | DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle); |
||
225 | #ifdef INCREMENTTIMESTAMP |
||
226 | void IncrementTimeStamp(DIRENTRY dir); |
||
227 | #elif defined USEREALTIMECLOCK |
||
228 | void CacheTime (void); |
||
229 | #endif |
||
230 | |||
231 | #if defined (__C30__) || defined (__PIC32MX__) |
||
232 | BYTE ReadByte( BYTE* pBuffer, WORD index ); |
||
233 | WORD ReadWord( BYTE* pBuffer, WORD index ); |
||
234 | DWORD ReadDWord( BYTE* pBuffer, WORD index ); |
||
235 | #endif |
||
236 | |||
237 | void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource); |
||
238 | BYTE ValidateChars (char * FileName, BYTE mode); |
||
239 | BYTE FormatFileName( const char* fileName, char* fN2, BYTE mode); |
||
240 | CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode); |
||
241 | BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n); |
||
242 | CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type); |
||
243 | |||
244 | // Write functions |
||
245 | #ifdef ALLOW_WRITES |
||
246 | BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry); |
||
247 | BYTE flushData (void); |
||
248 | CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters); |
||
249 | BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode); |
||
250 | BYTE FAT_erase_cluster_chain (DWORD cluster, DISK * dsk); |
||
251 | DWORD FATfindEmptyCluster(FILEOBJ fo); |
||
252 | BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle); |
||
253 | BYTE PopulateEntries(FILEOBJ fo, char *name , WORD *fHandle, BYTE mode); |
||
254 | CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster); |
||
255 | BYTE EraseCluster(DISK *disk, DWORD cluster); |
||
256 | CETYPE CreateFirstCluster(FILEOBJ fo); |
||
257 | DWORD WriteFAT (DISK *dsk, DWORD ccls, DWORD value, BYTE forceWrite); |
||
258 | CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode); |
||
259 | #endif |
||
260 | |||
261 | // Directory functions |
||
262 | #ifdef ALLOW_DIRS |
||
263 | BYTE GetPreviousEntry (FSFILE * fo); |
||
264 | BYTE FormatDirName (char * string, BYTE mode); |
||
265 | int CreateDIR (char * path); |
||
266 | BYTE writeDotEntries (DISK * dsk, DWORD dotAddress, DWORD dotdotAddress); |
||
267 | int eraseDir (char * path); |
||
268 | #ifdef ALLOW_PGMFUNCTIONS |
||
269 | #ifdef ALLOW_WRITES |
||
270 | int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr); |
||
271 | int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs); |
||
272 | #endif |
||
273 | int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr); |
||
274 | #else |
||
275 | #ifdef ALLOW_WRITES |
||
276 | int mkdirhelper (BYTE mode, char * ramptr, char * romptr); |
||
277 | int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs); |
||
278 | #endif |
||
279 | int chdirhelper (BYTE mode, char * ramptr, char * romptr); |
||
280 | #endif |
||
281 | #endif |
||
282 | |||
283 | #ifdef ALLOW_FSFPRINTF |
||
284 | #ifdef __18CXX |
||
285 | int FSvfprintf (auto FSFILE *handle, auto const rom char *formatString, auto va_list ap); |
||
286 | #else |
||
287 | int FSvfprintf (FSFILE *handle, const char *formatString, va_list ap); |
||
288 | #endif |
||
289 | int FSputc (char c, FSFILE * file); |
||
290 | unsigned char str_put_n_chars (FSFILE * handle, unsigned char n, char c); |
||
291 | #endif |
||
292 | |||
293 | BYTE DISKmount( DISK *dsk); |
||
294 | BYTE LoadMBR(DISK *dsk); |
||
295 | BYTE LoadBootSector(DISK *dsk); |
||
296 | DWORD GetFullClusterNumber(DIRENTRY entry); |
||
297 | |||
298 | |||
299 | /************************************************************************* |
||
300 | Function: |
||
301 | int FSInit(void) |
||
302 | Summary: |
||
303 | Function to initialize the device. |
||
304 | Conditions: |
||
305 | The physical device should be connected to the microcontroller. |
||
306 | Input: |
||
307 | None |
||
308 | Return Values: |
||
309 | TRUE - Initialization successful |
||
310 | FALSE - Initialization unsuccessful |
||
311 | Side Effects: |
||
312 | The FSerrno variable will be changed. |
||
313 | Description: |
||
314 | Initializes the static or dynamic memory slots for holding file |
||
315 | structures. Initializes the device with the DISKmount function. Loads |
||
316 | MBR and boot sector information. Initializes the current working |
||
317 | directory to the root directory for the device if directory support |
||
318 | is enabled. |
||
319 | Remarks: |
||
320 | None |
||
321 | *************************************************************************/ |
||
322 | |||
323 | int FSInit(void) |
||
324 | { |
||
325 | int fIndex; |
||
326 | #ifndef FS_DYNAMIC_MEM |
||
327 | for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ ) |
||
328 | gFileSlotOpen[fIndex] = TRUE; |
||
329 | #else |
||
330 | #ifdef __18CXX |
||
331 | SRAMInitHeap(); |
||
332 | #endif |
||
333 | #endif |
||
334 | |||
335 | gBufferZeroed = FALSE; |
||
336 | gNeedFATWrite = FALSE; |
||
337 | gLastFATSectorRead = 0xFFFFFFFF; |
||
338 | gLastDataSectorRead = 0xFFFFFFFF; |
||
339 | |||
340 | MDD_InitIO(); |
||
341 | |||
342 | if(DISKmount(&gDiskData) == CE_GOOD) |
||
343 | { |
||
344 | // Initialize the current working directory to the root |
||
345 | #ifdef ALLOW_DIRS |
||
346 | cwdptr->dsk = &gDiskData; |
||
347 | cwdptr->sec = 0; |
||
348 | cwdptr->pos = 0; |
||
349 | cwdptr->seek = 0; |
||
350 | cwdptr->size = 0; |
||
351 | cwdptr->name[0] = '\\'; |
||
352 | for (fIndex = 1; fIndex < 11; fIndex++) |
||
353 | { |
||
354 | cwdptr->name[fIndex] = 0x20; |
||
355 | } |
||
356 | cwdptr->entry = 0; |
||
357 | cwdptr->attributes = ATTR_DIRECTORY; |
||
358 | // "FatRootDirClusterValue" indicates the root |
||
359 | cwdptr->dirclus = FatRootDirClusterValue; |
||
360 | cwdptr->dirccls = FatRootDirClusterValue; |
||
361 | #endif |
||
362 | |||
363 | FSerrno = 0; |
||
364 | return TRUE; |
||
365 | } |
||
366 | |||
367 | return FALSE; |
||
368 | } |
||
369 | |||
370 | |||
371 | /******************************************************************************** |
||
372 | Function: |
||
373 | CETYPE FILEfind (FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode) |
||
374 | Summary |
||
375 | Finds a file on the device |
||
376 | Conditions: |
||
377 | This function should not be called by the user. |
||
378 | Input: |
||
379 | foDest - FSFILE object containing information of the file found |
||
380 | foCompareTo - FSFILE object containing the name/attr of the file to be |
||
381 | found |
||
382 | cmd - |
||
383 | - LOOK_FOR_EMPTY_ENTRY: Search for empty entry. |
||
384 | - LOOK_FOR_MATCHING_ENTRY: Search for matching entry. |
||
385 | mode - |
||
386 | - 0: Match file exactly with default attributes. |
||
387 | - 1: Match file to user-specified attributes. |
||
388 | Return Values: |
||
389 | CE_GOOD - File found. |
||
390 | CE_FILE_NOT_FOUND - File not found. |
||
391 | Side Effects: |
||
392 | None. |
||
393 | Description: |
||
394 | The FILEfind function will sequentially cache directory entries within |
||
395 | the current working directory into the foDest FSFILE object. If the cmd |
||
396 | parameter is specified as LOOK_FOR_EMPTY_ENTRY the search will continue |
||
397 | until an empty directory entry is found. If the cmd parameter is specified |
||
398 | as LOOK_FOR_MATCHING_ENTRY these entries will be compared to the foCompareTo |
||
399 | object until a match is found or there are no more entries in the current |
||
400 | working directory. If the mode is specified a '0' the attributes of the FSFILE |
||
401 | entries are irrelevant. If the mode is specified as '1' the attributes of the |
||
402 | foDest entry must match the attributes specified in the foCompareTo file and |
||
403 | partial string search characters may bypass portions of the comparison. |
||
404 | Remarks: |
||
405 | None |
||
406 | ********************************************************************************/ |
||
407 | |||
408 | CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode) |
||
409 | { |
||
410 | WORD attrib, compareAttrib; |
||
411 | WORD fHandle = foDest->entry; // current entry counter |
||
412 | BYTE state,index; // state of the current object |
||
413 | CETYPE statusB = CE_FILE_NOT_FOUND; |
||
414 | BYTE character,test; |
||
415 | |||
416 | // reset the cluster |
||
417 | foDest->dirccls = foDest->dirclus; |
||
418 | compareAttrib = 0xFFFF ^ foCompareTo->attributes; // Attribute to be compared as per application layer request |
||
419 | |||
420 | if (fHandle == 0) |
||
421 | { |
||
422 | if (Cache_File_Entry(foDest, &fHandle, TRUE) == NULL) |
||
423 | { |
||
424 | statusB = CE_BADCACHEREAD; |
||
425 | } |
||
426 | } |
||
427 | else |
||
428 | { |
||
429 | if ((fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) != 0) // Maximum 16 entries possible |
||
430 | { |
||
431 | if (Cache_File_Entry (foDest, &fHandle, TRUE) == NULL) |
||
432 | { |
||
433 | statusB = CE_BADCACHEREAD; |
||
434 | } |
||
435 | } |
||
436 | } |
||
437 | |||
438 | if (statusB != CE_BADCACHEREAD) |
||
439 | { |
||
440 | // Loop until you reach the end or find the file |
||
441 | while(1) |
||
442 | { |
||
443 | if(statusB!=CE_GOOD) //First time entry always here |
||
444 | { |
||
445 | state = Fill_File_Object(foDest, &fHandle); |
||
446 | if(state == NO_MORE) // Reached the end of available files. Comparision over and file not found so quit. |
||
447 | { |
||
448 | break; |
||
449 | } |
||
450 | } |
||
451 | else // statusB == CE_GOOD then exit |
||
452 | { |
||
453 | break; // Code below intializes"statusB = CE_GOOD;" so, if no problem in the filled file, Exit the while loop. |
||
454 | } |
||
455 | |||
456 | if(state == FOUND) // Validate the correct matching of filled file data with the required(to be found) one. |
||
457 | { |
||
458 | /* We got something */ |
||
459 | // get the attributes |
||
460 | attrib = foDest->attributes; |
||
461 | |||
462 | attrib &= ATTR_MASK; |
||
463 | switch (mode) |
||
464 | { |
||
465 | case 0: |
||
466 | // see if we are a volume id or hidden, ignore |
||
467 | if(attrib != ATTR_VOLUME) |
||
468 | { |
||
469 | statusB = CE_GOOD; |
||
470 | character = (BYTE)'m'; // random value |
||
471 | |||
472 | // search for one. if status = TRUE we found one |
||
473 | for(index = 0; index < DIR_NAMECOMP; index++) |
||
474 | { |
||
475 | // get the source character |
||
476 | character = foDest->name[index]; |
||
477 | // get the destination character |
||
478 | test = foCompareTo->name[index]; |
||
479 | if(tolower(character) != tolower(test)) |
||
480 | { |
||
481 | statusB = CE_FILE_NOT_FOUND; // Nope its not a match |
||
482 | break; |
||
483 | } |
||
484 | }// for loop |
||
485 | } // not dir nor vol |
||
486 | break; |
||
487 | |||
488 | case 1: |
||
489 | // Check for attribute match |
||
490 | if (((attrib & compareAttrib) == 0) && (attrib != ATTR_LONG_NAME)) |
||
491 | { |
||
492 | statusB = CE_GOOD; // Indicate the already filled file data is correct and go back |
||
493 | character = (BYTE)'m'; // random value |
||
494 | if (foCompareTo->name[0] != '*') //If "*" is passed for comparion as 1st char then don't proceed. Go back, file alreay found. |
||
495 | { |
||
496 | for (index = 0; index < DIR_NAMESIZE; index++) |
||
497 | { |
||
498 | // Get the source character |
||
499 | character = foDest->name[index]; |
||
500 | // Get the destination character |
||
501 | test = foCompareTo->name[index]; |
||
502 | if (test == '*') |
||
503 | break; |
||
504 | if (test != '?') |
||
505 | { |
||
506 | if(tolower(character) != tolower(test)) |
||
507 | { |
||
508 | statusB = CE_FILE_NOT_FOUND; // it's not a match |
||
509 | break; |
||
510 | } |
||
511 | } |
||
512 | } |
||
513 | } |
||
514 | |||
515 | // Before calling this "FILEfind" fn, "formatfilename" must be called. Hence, extn always starts from position "8". |
||
516 | if ((foCompareTo->name[8] != '*') && (statusB == CE_GOOD)) |
||
517 | { |
||
518 | for (index = 8; index < DIR_NAMECOMP; index++) |
||
519 | { |
||
520 | // Get the source character |
||
521 | character = foDest->name[index]; |
||
522 | // Get the destination character |
||
523 | test = foCompareTo->name[index]; |
||
524 | if (test == '*') |
||
525 | break; |
||
526 | if (test != '?') |
||
527 | { |
||
528 | if(tolower(character) != tolower(test)) |
||
529 | { |
||
530 | statusB = CE_FILE_NOT_FOUND; // it's not a match |
||
531 | break; |
||
532 | } |
||
533 | } |
||
534 | } |
||
535 | } |
||
536 | |||
537 | } // Attribute match |
||
538 | |||
539 | break; |
||
540 | } |
||
541 | } // not found |
||
542 | else |
||
543 | { |
||
544 | /*** looking for an empty/re-usable entry ***/ |
||
545 | if ( cmd == LOOK_FOR_EMPTY_ENTRY) |
||
546 | statusB = CE_GOOD; |
||
547 | } // found or not |
||
548 | |||
549 | // increment it no matter what happened |
||
550 | fHandle++; |
||
551 | |||
552 | }// while |
||
553 | } |
||
554 | |||
555 | return(statusB); |
||
556 | } // FILEFind |
||
557 | |||
558 | |||
559 | /************************************************************************** |
||
560 | Function: |
||
561 | CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type) |
||
562 | Summary: |
||
563 | Loads file information from the device |
||
564 | Conditions: |
||
565 | This function should not be called by the user. |
||
566 | Input: |
||
567 | fo - File to be opened |
||
568 | fHandle - Location of file |
||
569 | type - |
||
570 | - WRITE - Create a new file or replace an existing file |
||
571 | - READ - Read data from an existing file |
||
572 | - APPEND - Append data to an existing file |
||
573 | Return Values: |
||
574 | CE_GOOD - FILEopen successful |
||
575 | CE_NOT_INIT - Device is not yet initialized |
||
576 | CE_FILE_NOT_FOUND - Could not find the file on the device |
||
577 | CE_BAD_SECTOR_READ - A bad read of a sector occured |
||
578 | Side Effects: |
||
579 | None |
||
580 | Description: |
||
581 | This function will cache a directory entry in the directory specified |
||
582 | by the dirclus parameter of hte FSFILE object 'fo.' The offset of the |
||
583 | entry in the directory is specified by fHandle. Once the directory entry |
||
584 | has been loaded, the first sector of the file can be loaded using the |
||
585 | cluster value specified in the directory entry. The type argument will |
||
586 | specify the mode the files will be opened in. This will allow this |
||
587 | function to set the correct read/write flags for the file. |
||
588 | Remarks: |
||
589 | If the mode the file is being opened in is a plus mode (e.g. READ+) the |
||
590 | flags will be modified further in the FSfopen function. |
||
591 | **************************************************************************/ |
||
592 | |||
593 | CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type) |
||
594 | { |
||
595 | DISK *dsk; //Disk structure |
||
596 | BYTE r; //Result of search for file |
||
597 | DWORD l; //lba of first sector of first cluster |
||
598 | CETYPE error = CE_GOOD; |
||
599 | |||
600 | dsk = (DISK *)(fo->dsk); |
||
601 | if (dsk->mount == FALSE) |
||
602 | { |
||
603 | error = CE_NOT_INIT; |
||
604 | } |
||
605 | else |
||
606 | { |
||
607 | // load the sector |
||
608 | fo->dirccls = fo->dirclus; |
||
609 | // Cache no matter what if it's the first entry |
||
610 | if (*fHandle == 0) |
||
611 | { |
||
612 | if (Cache_File_Entry(fo, fHandle, TRUE) == NULL) |
||
613 | { |
||
614 | error = CE_BADCACHEREAD; |
||
615 | } |
||
616 | } |
||
617 | else |
||
618 | { |
||
619 | // If it's not the first, only cache it if it's |
||
620 | // not divisible by the number of entries per sector |
||
621 | // If it is, Fill_File_Object will cache it |
||
622 | if ((*fHandle & 0xf) != 0) |
||
623 | { |
||
624 | if (Cache_File_Entry (fo, fHandle, TRUE) == NULL) |
||
625 | { |
||
626 | error = CE_BADCACHEREAD; |
||
627 | } |
||
628 | } |
||
629 | } |
||
630 | |||
631 | // Fill up the File Object with the information pointed to by fHandle |
||
632 | r = Fill_File_Object(fo, fHandle); |
||
633 | if (r != FOUND) |
||
634 | error = CE_FILE_NOT_FOUND; |
||
635 | else |
||
636 | { |
||
637 | fo->seek = 0; // first byte in file |
||
638 | fo->ccls = fo->cluster; // first cluster |
||
639 | fo->sec = 0; // first sector in the cluster |
||
640 | fo->pos = 0; // first byte in sector/cluster |
||
641 | |||
642 | if ( r == NOT_FOUND) |
||
643 | { |
||
644 | error = CE_FILE_NOT_FOUND; |
||
645 | } |
||
646 | else |
||
647 | { |
||
648 | // Determine the lba of the selected sector and load |
||
649 | l = Cluster2Sector(dsk,fo->ccls); |
||
650 | #ifdef ALLOW_WRITES |
||
651 | if (gNeedDataWrite) |
||
652 | if (flushData()) |
||
653 | return CE_WRITE_ERROR; |
||
654 | #endif |
||
655 | gBufferOwner = fo; |
||
656 | if (gLastDataSectorRead != l) |
||
657 | { |
||
658 | gBufferZeroed = FALSE; |
||
659 | if ( !MDD_SectorRead( l, dsk->buffer)) |
||
660 | error = CE_BAD_SECTOR_READ; |
||
661 | gLastDataSectorRead = l; |
||
662 | } |
||
663 | } // -- found |
||
664 | |||
665 | fo->flags.FileWriteEOF = FALSE; |
||
666 | // Set flag for operation type |
||
667 | #ifdef ALLOW_WRITES |
||
668 | if (type == 'w' || type == 'a') |
||
669 | { |
||
670 | fo->flags.write = 1; //write or append |
||
671 | fo->flags.read = 0; |
||
672 | } |
||
673 | else |
||
674 | { |
||
675 | #endif |
||
676 | fo->flags.write = 0; //read |
||
677 | fo->flags.read = 1; |
||
678 | #ifdef ALLOW_WRITES |
||
679 | } // -- flags |
||
680 | #endif |
||
681 | } // -- r = Found |
||
682 | } // -- Mounted |
||
683 | return (error); |
||
684 | } // -- FILEopen |
||
685 | |||
686 | |||
687 | /************************************************************************* |
||
688 | Function: |
||
689 | BYTE FILEget_next_cluster(FILEOBJ fo, WORD n) |
||
690 | Summary: |
||
691 | Step through a chain of clusters |
||
692 | Conditions: |
||
693 | This function should not be called by the user. |
||
694 | Input: |
||
695 | fo - The file to get the next cluster of |
||
696 | n - Number of links in the FAT cluster chain to jump through |
||
697 | Return Values: |
||
698 | CE_GOOD - Operation successful |
||
699 | CE_BAD_SECTOR_READ - A bad read occured of a sector |
||
700 | CE_INVALID_CLUSTER - Invalid cluster value \> maxcls |
||
701 | CE_FAT_EOF - Fat attempt to read beyond EOF |
||
702 | Side Effects: |
||
703 | None |
||
704 | Description: |
||
705 | This function will load 'n' proximate clusters for a file from |
||
706 | the FAT on the device. It will stop checking for clusters if the |
||
707 | ReadFAT function returns an error, if it reaches the last cluster in |
||
708 | a file, or if the device tries to read beyond the last cluster used |
||
709 | by the device. |
||
710 | Remarks: |
||
711 | None |
||
712 | *************************************************************************/ |
||
713 | |||
714 | BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n) |
||
715 | { |
||
716 | DWORD c, c2, ClusterFailValue, LastClustervalue; |
||
717 | BYTE error = CE_GOOD; |
||
718 | DISK * disk; |
||
719 | |||
720 | disk = fo->dsk; |
||
721 | |||
722 | /* Settings based on FAT type */ |
||
723 | switch (disk->type) |
||
724 | { |
||
725 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
726 | case FAT32: |
||
727 | LastClustervalue = LAST_CLUSTER_FAT32; |
||
728 | ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
729 | break; |
||
730 | #endif |
||
731 | case FAT12: |
||
732 | LastClustervalue = LAST_CLUSTER_FAT12; |
||
733 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
734 | break; |
||
735 | case FAT16: |
||
736 | default: |
||
737 | LastClustervalue = LAST_CLUSTER_FAT16; |
||
738 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
739 | break; |
||
740 | } |
||
741 | |||
742 | // loop n times |
||
743 | do |
||
744 | { |
||
745 | // get the next cluster link from FAT |
||
746 | c2 = fo->ccls; |
||
747 | if ( (c = ReadFAT( disk, c2)) == ClusterFailValue) |
||
748 | error = CE_BAD_SECTOR_READ; |
||
749 | else |
||
750 | { |
||
751 | // check if cluster value is valid |
||
752 | if ( c >= disk->maxcls) |
||
753 | { |
||
754 | error = CE_INVALID_CLUSTER; |
||
755 | } |
||
756 | |||
757 | // compare against max value of a cluster in FAT |
||
758 | // return if eof |
||
759 | if ( c >= LastClustervalue) // check against eof |
||
760 | { |
||
761 | error = CE_FAT_EOF; |
||
762 | } |
||
763 | } |
||
764 | |||
765 | // update the FSFILE structure |
||
766 | fo->ccls = c; |
||
767 | |||
768 | } while (--n > 0 && error == CE_GOOD);// loop end |
||
769 | |||
770 | return(error); |
||
771 | } // get next cluster |
||
772 | |||
773 | |||
774 | /************************************************************************** |
||
775 | Function: |
||
776 | BYTE DISKmount ( DISK *dsk) |
||
777 | Summary: |
||
778 | Initialies the device and loads MBR and boot sector information |
||
779 | Conditions: |
||
780 | This function should not be called by the user. |
||
781 | Input: |
||
782 | dsk - The disk structure to be initialized. |
||
783 | Return Values: |
||
784 | CE_GOOD - Disk mounted |
||
785 | CE_INIT_ERROR - Initialization error has occured |
||
786 | CE_UNSUPPORTED_SECTOR_SIZE - Media sector size bigger than |
||
787 | MEDIA_SECTOR_SIZE as defined in FSconfig.h. |
||
788 | Side Effects: |
||
789 | None |
||
790 | Description: |
||
791 | This function will use the function pointed to by the MDD_MediaInitialize |
||
792 | function pointer to initialize the device (if any initialization is |
||
793 | required). It then attempts to load the master boot record with the |
||
794 | LoadMBR function and the boot sector with the LoadBootSector function. |
||
795 | These two functions will be used to initialize a global DISK structure |
||
796 | that will be used when accessing file information in the future. |
||
797 | Remarks: |
||
798 | None |
||
799 | **************************************************************************/ |
||
800 | |||
801 | BYTE DISKmount( DISK *dsk) |
||
802 | { |
||
803 | BYTE error = CE_GOOD; |
||
804 | MEDIA_INFORMATION *mediaInformation; |
||
805 | |||
806 | dsk->mount = FALSE; // default invalid |
||
807 | dsk->buffer = gDataBuffer; // assign buffer |
||
808 | |||
809 | // Initialize the device |
||
810 | mediaInformation = MDD_MediaInitialize(); |
||
811 | if (mediaInformation->errorCode != MEDIA_NO_ERROR) |
||
812 | { |
||
813 | error = CE_INIT_ERROR; |
||
814 | FSerrno = CE_INIT_ERROR; |
||
815 | } |
||
816 | else |
||
817 | { |
||
818 | // If the media initialization routine determined the sector size, |
||
819 | // check it and make sure we can support it. |
||
820 | if (mediaInformation->validityFlags.bits.sectorSize) |
||
821 | { |
||
822 | dsk->sectorSize = mediaInformation->sectorSize; |
||
823 | if (mediaInformation->sectorSize > MEDIA_SECTOR_SIZE) |
||
824 | { |
||
825 | error = CE_UNSUPPORTED_SECTOR_SIZE; |
||
826 | FSerrno = CE_UNSUPPORTED_SECTOR_SIZE; |
||
827 | return error; |
||
828 | } |
||
829 | } |
||
830 | |||
831 | // Load the Master Boot Record (partition) |
||
832 | if((error = LoadMBR(dsk)) == CE_GOOD) |
||
833 | { |
||
834 | // Now the boot sector |
||
835 | if((error = LoadBootSector(dsk)) == CE_GOOD) |
||
836 | dsk->mount = TRUE; // Mark that the DISK mounted successfully |
||
837 | } |
||
838 | } // -- Load file parameters |
||
839 | |||
840 | return(error); |
||
841 | } // -- mount |
||
842 | |||
843 | |||
844 | |||
845 | /******************************************************************** |
||
846 | Function: |
||
847 | CETYPE LoadMBR ( DISK *dsk) |
||
848 | Summary: |
||
849 | Loads the MBR and extracts necessary information |
||
850 | Conditions: |
||
851 | This function should not be called by the user. |
||
852 | Input: |
||
853 | dsk - The disk containing the master boot record to be loaded |
||
854 | Return Values: |
||
855 | CE_GOOD - MBR loaded successfully |
||
856 | CE_BAD_SECTOR_READ - A bad read occured of a sector |
||
857 | CE_BAD_PARTITION - The boot record is bad |
||
858 | Side Effects: |
||
859 | None |
||
860 | Description: |
||
861 | The LoadMBR function will use the function pointed to by the |
||
862 | MDD_SectorRead function pointer to read the 0 sector from the |
||
863 | device. If a valid boot signature is obtained, this function |
||
864 | will compare fields in that cached sector to the values that |
||
865 | would be present if that sector was a boot sector. If all of |
||
866 | those values match, it will be assumed that the device does not |
||
867 | have a master boot record and the 0 sector is actually the boot |
||
868 | sector. Otherwise, data about the partition and the actual |
||
869 | location of the boot sector will be loaded from the MBR into |
||
870 | the DISK structure pointed to by 'dsk.' |
||
871 | Remarks: |
||
872 | None |
||
873 | ********************************************************************/ |
||
874 | |||
875 | BYTE LoadMBR(DISK *dsk) |
||
876 | { |
||
877 | PT_MBR Partition; |
||
878 | BYTE error = CE_GOOD; |
||
879 | BYTE type; |
||
880 | BootSec BSec; |
||
881 | |||
882 | // Get the partition table from the MBR |
||
883 | if ( MDD_SectorRead( FO_MBR, dsk->buffer) != TRUE) |
||
884 | { |
||
885 | error = CE_BAD_SECTOR_READ; |
||
886 | FSerrno = CE_BAD_SECTOR_READ; |
||
887 | } |
||
888 | else |
||
889 | { |
||
890 | // Check if the card has no MBR |
||
891 | BSec = (BootSec) dsk->buffer; |
||
892 | |||
893 | if((BSec->Signature0 == FAT_GOOD_SIGN_0) && (BSec->Signature1 == FAT_GOOD_SIGN_1)) |
||
894 | { |
||
895 | // Technically, the OEM name is not for indication |
||
896 | // The alternative is to read the CIS from attribute |
||
897 | // memory. See the PCMCIA metaformat for more details |
||
898 | #if defined (__C30__) || defined (__PIC32MX__) |
||
899 | if (ReadByte( dsk->buffer, BSI_FSTYPE ) == 'F' && \ |
||
900 | ReadByte( dsk->buffer, BSI_FSTYPE + 1 ) == 'A' && \ |
||
901 | ReadByte( dsk->buffer, BSI_FSTYPE + 2 ) == 'T' && \ |
||
902 | ReadByte( dsk->buffer, BSI_FSTYPE + 3 ) == '1' && \ |
||
903 | ReadByte( dsk->buffer, BSI_BOOTSIG) == 0x29) |
||
904 | #else |
||
905 | if (BSec->FAT.FAT_16.BootSec_FSType[0] == 'F' && \ |
||
906 | BSec->FAT.FAT_16.BootSec_FSType[1] == 'A' && \ |
||
907 | BSec->FAT.FAT_16.BootSec_FSType[2] == 'T' && \ |
||
908 | BSec->FAT.FAT_16.BootSec_FSType[3] == '1' && \ |
||
909 | BSec->FAT.FAT_16.BootSec_BootSig == 0x29) |
||
910 | #endif |
||
911 | { |
||
912 | dsk->firsts = 0; |
||
913 | dsk->type = FAT16; |
||
914 | return CE_GOOD; |
||
915 | } |
||
916 | else |
||
917 | { |
||
918 | #if defined (__C30__) || defined (__PIC32MX__) |
||
919 | if (ReadByte( dsk->buffer, BSI_FAT32_FSTYPE ) == 'F' && \ |
||
920 | ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 1 ) == 'A' && \ |
||
921 | ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 2 ) == 'T' && \ |
||
922 | ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 3 ) == '3' && \ |
||
923 | ReadByte( dsk->buffer, BSI_FAT32_BOOTSIG) == 0x29) |
||
924 | #else |
||
925 | if (BSec->FAT.FAT_32.BootSec_FilSysType[0] == 'F' && \ |
||
926 | BSec->FAT.FAT_32.BootSec_FilSysType[1] == 'A' && \ |
||
927 | BSec->FAT.FAT_32.BootSec_FilSysType[2] == 'T' && \ |
||
928 | BSec->FAT.FAT_32.BootSec_FilSysType[3] == '3' && \ |
||
929 | BSec->FAT.FAT_32.BootSec_BootSig == 0x29) |
||
930 | #endif |
||
931 | { |
||
932 | dsk->firsts = 0; |
||
933 | dsk->type = FAT32; |
||
934 | return CE_GOOD; |
||
935 | } |
||
936 | } |
||
937 | } |
||
938 | // assign it the partition table strucutre |
||
939 | Partition = (PT_MBR)dsk->buffer; |
||
940 | |||
941 | // Ensure its good |
||
942 | if((Partition->Signature0 != FAT_GOOD_SIGN_0) || (Partition->Signature1 != FAT_GOOD_SIGN_1)) |
||
943 | { |
||
944 | FSerrno = CE_BAD_PARTITION; |
||
945 | error = CE_BAD_PARTITION; |
||
946 | } |
||
947 | else |
||
948 | { |
||
949 | /* Valid Master Boot Record Loaded */ |
||
950 | |||
951 | // Get the 32 bit offset to the first partition |
||
952 | dsk->firsts = Partition->Partition0.PTE_FrstSect; |
||
953 | |||
954 | // check if the partition type is acceptable |
||
955 | type = Partition->Partition0.PTE_FSDesc; |
||
956 | |||
957 | switch (type) |
||
958 | { |
||
959 | case 0x01: |
||
960 | dsk->type = FAT12; |
||
961 | break; |
||
962 | |||
963 | case 0x04: |
||
964 | case 0x06: |
||
965 | case 0x0E: |
||
966 | dsk->type = FAT16; |
||
967 | break; |
||
968 | |||
969 | case 0x0B: |
||
970 | case 0x0C: |
||
971 | |||
972 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
973 | dsk->type = FAT32; // FAT32 is supported too |
||
974 | #else |
||
975 | FSerrno = CE_CARDFAT32; |
||
976 | error = CE_CARDFAT32; |
||
977 | #endif |
||
978 | break; |
||
979 | |||
980 | default: |
||
981 | FSerrno = CE_UNSUPPORTED_FS; |
||
982 | error = CE_UNSUPPORTED_FS; |
||
983 | } // switch |
||
984 | } |
||
985 | } |
||
986 | |||
987 | return(error); |
||
988 | }// -- LoadMBR |
||
989 | |||
990 | |||
991 | /************************************************************************** |
||
992 | Function: |
||
993 | BYTE LoadBootSector (DISK *dsk) |
||
994 | Summary: |
||
995 | Load the boot sector and extract the necessary information |
||
996 | Conditions: |
||
997 | This function should not be called by the user. |
||
998 | Input: |
||
999 | dsk - The disk containing the boot sector |
||
1000 | Return Values: |
||
1001 | CE_GOOD - Boot sector loaded |
||
1002 | CE_BAD_SECTOR_READ - A bad read occured of a sector |
||
1003 | CE_NOT_FORMATTED - The disk is of an unsupported format |
||
1004 | CE_CARDFAT32 - FAT 32 device not supported |
||
1005 | CE_UNSUPPORTED_SECTOR_SIZE - The sector size is not supported |
||
1006 | Side Effects: |
||
1007 | None |
||
1008 | Description: |
||
1009 | LoadBootSector will use the function pointed to by the MDD_SectorWrite |
||
1010 | function pointer to load the boot sector, whose location was obtained |
||
1011 | by a previous call of LoadMBR. If the boot sector is loaded successfully, |
||
1012 | partition information will be calcualted from it and copied into the DISK |
||
1013 | structure pointed to by 'dsk.' |
||
1014 | Remarks: |
||
1015 | None |
||
1016 | **************************************************************************/ |
||
1017 | |||
1018 | |||
1019 | BYTE LoadBootSector(DISK *dsk) |
||
1020 | { |
||
1021 | DWORD RootDirSectors; |
||
1022 | DWORD TotSec,DataSec; |
||
1023 | BYTE error = CE_GOOD; |
||
1024 | BootSec BSec; |
||
1025 | WORD BytesPerSec; |
||
1026 | WORD ReservedSectorCount; |
||
1027 | |||
1028 | // Get the Boot sector |
||
1029 | if ( MDD_SectorRead( dsk->firsts, dsk->buffer) != TRUE) |
||
1030 | { |
||
1031 | FSerrno = CE_BAD_SECTOR_READ; |
||
1032 | error = CE_BAD_SECTOR_READ; |
||
1033 | } |
||
1034 | else |
||
1035 | { |
||
1036 | BSec = (BootSec)dsk->buffer; |
||
1037 | |||
1038 | //Verify the Boot Sector is valid |
||
1039 | if((BSec->Signature0 != FAT_GOOD_SIGN_0) || (BSec->Signature1 != FAT_GOOD_SIGN_1)) |
||
1040 | { |
||
1041 | FSerrno = CE_NOT_FORMATTED; |
||
1042 | error = CE_NOT_FORMATTED; |
||
1043 | } |
||
1044 | else |
||
1045 | { |
||
1046 | #ifdef __18CXX |
||
1047 | |||
1048 | // Load count of sectors per cluster |
||
1049 | dsk->SecPerClus = BSec->FAT.FAT_16.BootSec_SPC; |
||
1050 | // Load the sector number of the first FAT sector |
||
1051 | dsk->fat = dsk->firsts + BSec->FAT.FAT_16.BootSec_ResrvSec; |
||
1052 | // Load the count of FAT tables |
||
1053 | dsk->fatcopy = BSec->FAT.FAT_16.BootSec_FATCount; |
||
1054 | // Load the size of the FATs |
||
1055 | dsk->fatsize = BSec->FAT.FAT_16.BootSec_SPF; |
||
1056 | if(dsk->fatsize == 0) |
||
1057 | dsk->fatsize = BSec->FAT.FAT_32.BootSec_FATSz32; |
||
1058 | // Calculate the location of the root sector (for FAT12/16) |
||
1059 | dsk->root = dsk->fat + (DWORD)(dsk->fatcopy * (DWORD)dsk->fatsize); |
||
1060 | // Determine the max size of the root (will be 0 for FAT32) |
||
1061 | dsk->maxroot = BSec->FAT.FAT_16.BootSec_RootDirEnts; |
||
1062 | |||
1063 | // Determine the total number of sectors in the partition |
||
1064 | if(BSec->FAT.FAT_16.BootSec_TotSec16 != 0) |
||
1065 | { |
||
1066 | TotSec = BSec->FAT.FAT_16.BootSec_TotSec16; |
||
1067 | } |
||
1068 | else |
||
1069 | { |
||
1070 | TotSec = BSec->FAT.FAT_16.BootSec_TotSec32; |
||
1071 | } |
||
1072 | |||
1073 | // Calculate the number of bytes in each sector |
||
1074 | BytesPerSec = BSec->FAT.FAT_16.BootSec_BPS; |
||
1075 | if( BytesPerSec == 0 || (BytesPerSec & 1) == 1 ) |
||
1076 | { |
||
1077 | FSerrno = CE_UNSUPPORTED_SECTOR_SIZE; |
||
1078 | return( CE_UNSUPPORTED_SECTOR_SIZE ); |
||
1079 | } |
||
1080 | |||
1081 | // Calculate the number of sectors in the root (will be 0 for FAT32) |
||
1082 | RootDirSectors = ((BSec->FAT.FAT_16.BootSec_RootDirEnts * 32) + (BSec->FAT.FAT_16.BootSec_BPS - 1)) / BSec->FAT.FAT_16.BootSec_BPS; |
||
1083 | // Calculate the number of data sectors on the card |
||
1084 | DataSec = TotSec - (dsk->root + RootDirSectors); |
||
1085 | // Calculate the maximum number of clusters on the card |
||
1086 | dsk->maxcls = DataSec / dsk->SecPerClus; |
||
1087 | |||
1088 | #else // PIC24/30/33 |
||
1089 | |||
1090 | // Read the count of reserved sectors |
||
1091 | ReservedSectorCount = ReadWord( dsk->buffer, BSI_RESRVSEC ); |
||
1092 | // Load the count of sectors per cluster |
||
1093 | dsk->SecPerClus = ReadByte( dsk->buffer, BSI_SPC ); |
||
1094 | // Load the sector number of the first FAT sector |
||
1095 | dsk->fat = dsk->firsts + ReservedSectorCount; |
||
1096 | // Load the count of FAT tables |
||
1097 | dsk->fatcopy = ReadByte( dsk->buffer, BSI_FATCOUNT ); |
||
1098 | // Load the size of the FATs |
||
1099 | dsk->fatsize = ReadWord( dsk->buffer, BSI_SPF ); |
||
1100 | if(dsk->fatsize == 0) |
||
1101 | dsk->fatsize = ReadDWord( dsk->buffer, BSI_FATSZ32 ); |
||
1102 | // Calculate the location of the root sector (for FAT12/16) |
||
1103 | dsk->root = dsk->fat + (DWORD)(dsk->fatcopy * (DWORD)dsk->fatsize); |
||
1104 | // Determine the max size of the root (will be 0 for FAT32) |
||
1105 | dsk->maxroot = ReadWord( dsk->buffer, BSI_ROOTDIRENTS ); |
||
1106 | |||
1107 | // Determine the total number of sectors in the partition |
||
1108 | TotSec = ReadWord( dsk->buffer, BSI_TOTSEC16 ); |
||
1109 | if( TotSec == 0 ) |
||
1110 | TotSec = ReadDWord( dsk->buffer, BSI_TOTSEC32 ); |
||
1111 | |||
1112 | // Calculate the number of bytes in each sector |
||
1113 | BytesPerSec = ReadWord( dsk->buffer, BSI_BPS ); |
||
1114 | if( BytesPerSec == 0 || (BytesPerSec & 1) == 1 ) |
||
1115 | { |
||
1116 | FSerrno = CE_UNSUPPORTED_SECTOR_SIZE; |
||
1117 | return( CE_UNSUPPORTED_SECTOR_SIZE ); |
||
1118 | } |
||
1119 | |||
1120 | // Calculate the number of sectors in the root (will be 0 for FAT32) |
||
1121 | RootDirSectors = ((dsk->maxroot * NUMBER_OF_BYTES_IN_DIR_ENTRY) + (BytesPerSec - 1)) / BytesPerSec; |
||
1122 | // Calculate the number of data sectors on the card |
||
1123 | DataSec = TotSec - (ReservedSectorCount + (dsk->fatcopy * dsk->fatsize ) + RootDirSectors); |
||
1124 | // Calculate the maximum number of clusters on the card |
||
1125 | dsk->maxcls = DataSec / dsk->SecPerClus; |
||
1126 | |||
1127 | #endif |
||
1128 | |||
1129 | // Determine the file system type based on the number of clusters used |
||
1130 | if(dsk->maxcls < 4085) |
||
1131 | { |
||
1132 | dsk->type = FAT12; |
||
1133 | } |
||
1134 | else |
||
1135 | { |
||
1136 | if(dsk->maxcls < 65525) |
||
1137 | { |
||
1138 | dsk->type = FAT16; |
||
1139 | } |
||
1140 | else |
||
1141 | { |
||
1142 | #ifdef SUPPORT_FAT32 |
||
1143 | dsk->type = FAT32; |
||
1144 | #else |
||
1145 | error = CE_CARDFAT32; |
||
1146 | FSerrno = CE_CARDFAT32; |
||
1147 | #endif |
||
1148 | } |
||
1149 | } |
||
1150 | |||
1151 | #ifdef SUPPORT_FAT32 |
||
1152 | if (dsk->type == FAT32) |
||
1153 | { |
||
1154 | #ifdef __18CXX |
||
1155 | FatRootDirClusterValue = BSec->FAT.FAT_32.BootSec_RootClus; |
||
1156 | #else |
||
1157 | FatRootDirClusterValue = ReadDWord( dsk->buffer, BSI_ROOTCLUS ); |
||
1158 | #endif |
||
1159 | dsk->data = dsk->root + RootDirSectors; |
||
1160 | } |
||
1161 | else |
||
1162 | #endif |
||
1163 | { |
||
1164 | FatRootDirClusterValue = 0; |
||
1165 | dsk->data = dsk->root + ( dsk->maxroot >> 4); |
||
1166 | } |
||
1167 | |||
1168 | #ifdef __18CXX |
||
1169 | if(BSec->FAT.FAT_16.BootSec_BPS > MEDIA_SECTOR_SIZE) |
||
1170 | #else |
||
1171 | if(BytesPerSec > MEDIA_SECTOR_SIZE) |
||
1172 | #endif |
||
1173 | { |
||
1174 | error = CE_UNSUPPORTED_SECTOR_SIZE; |
||
1175 | FSerrno = CE_UNSUPPORTED_SECTOR_SIZE; |
||
1176 | } |
||
1177 | } |
||
1178 | } |
||
1179 | return(error); |
||
1180 | } |
||
1181 | |||
1182 | |||
1183 | |||
1184 | /************************************************************************* |
||
1185 | Function: |
||
1186 | DWORD GetFullClusterNumber (DIRENTRY entry) |
||
1187 | Summary: |
||
1188 | Gets the cluster number from a directory entry |
||
1189 | Conditions: |
||
1190 | This function should not be called by the user. |
||
1191 | Input: |
||
1192 | entry - The cached directory entry to get the cluster number from |
||
1193 | Returns: |
||
1194 | The cluster value from the passed directory entry |
||
1195 | Side Effects: |
||
1196 | None. |
||
1197 | Description: |
||
1198 | This function will load both the high and low 16-bit first cluster |
||
1199 | values of a file from a directory entry and copy them into a 32-bit |
||
1200 | cluster number variable, which will be returned. |
||
1201 | Remarks: |
||
1202 | None |
||
1203 | *************************************************************************/ |
||
1204 | |||
1205 | DWORD GetFullClusterNumber(DIRENTRY entry) |
||
1206 | { |
||
1207 | |||
1208 | DWORD TempFullClusterCalc = 0; |
||
1209 | |||
1210 | #ifndef SUPPORT_FAT32 // If FAT32 Not supported. |
||
1211 | entry->DIR_FstClusHI = 0; // If FAT32 is not supported then Higher Word of the address is "0" |
||
1212 | #endif |
||
1213 | |||
1214 | // Get the cluster |
||
1215 | TempFullClusterCalc = (entry->DIR_FstClusHI); |
||
1216 | TempFullClusterCalc = TempFullClusterCalc << 16; |
||
1217 | TempFullClusterCalc |= entry->DIR_FstClusLO; |
||
1218 | |||
1219 | return TempFullClusterCalc; |
||
1220 | } |
||
1221 | |||
1222 | |||
1223 | #ifdef ALLOW_FORMATS |
||
1224 | #ifdef ALLOW_WRITES |
||
1225 | |||
1226 | |||
1227 | /********************************************************************************* |
||
1228 | Function: |
||
1229 | int FSCreateMBR (unsigned long firstSector, unsigned long numSectors) |
||
1230 | Summary: |
||
1231 | Creates a master boot record |
||
1232 | Conditions: |
||
1233 | The I/O pins for the device have been initialized by the InitIO function. |
||
1234 | Input: |
||
1235 | firstSector - The first sector of the partition on the device (cannot |
||
1236 | be 0; that's the MBR) |
||
1237 | numSectors - The number of sectors available in memory (including the |
||
1238 | MBR) |
||
1239 | Return Values: |
||
1240 | |||
1241 | EOF - MBR could not be created |
||
1242 | Side Effects: |
||
1243 | None |
||
1244 | Description: |
||
1245 | This function can be used to create a master boot record for a device. Note |
||
1246 | that this function should not be used on a device that is already formatted |
||
1247 | with a master boot record (i.e. most SD cards, CF cards, USB keys). This |
||
1248 | function will fill the global data buffer with appropriate partition information |
||
1249 | for a FAT partition with a type determined by the number of sectors available |
||
1250 | to the partition. It will then write the MBR information to the first sector |
||
1251 | on the device. This function should be followed by a call to FSformat, which |
||
1252 | will create a boot sector, root dir, and FAT appropriate the the information |
||
1253 | contained in the new master boot record. Note that FSformat only supports |
||
1254 | FAT12 and FAT16 formatting at this time, and so cannot be used to format a |
||
1255 | device with more than 0x3FFD5F sectors. |
||
1256 | Remarks: |
||
1257 | This function can damage the device being used, and should not be called |
||
1258 | unless the user is sure about the size of the device and the first sector value. |
||
1259 | *********************************************************************************/ |
||
1260 | |||
1261 | int FSCreateMBR (unsigned long firstSector, unsigned long numSectors) |
||
1262 | { |
||
1263 | PT_MBR Partition; |
||
1264 | DWORD CyHdSc = 0x00000000; |
||
1265 | DWORD tempSector; |
||
1266 | |||
1267 | if ((firstSector == 0) || (numSectors <= 1)) |
||
1268 | return EOF; |
||
1269 | |||
1270 | if (firstSector > (numSectors - 1)) |
||
1271 | return EOF; |
||
1272 | |||
1273 | if (gNeedDataWrite) |
||
1274 | if (flushData()) |
||
1275 | return EOF; |
||
1276 | |||
1277 | memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE); |
||
1278 | |||
1279 | Partition = (PT_MBR) gDataBuffer; |
||
1280 | |||
1281 | // Set Cylinder-head-sector address of the first sector |
||
1282 | tempSector = firstSector; |
||
1283 | CyHdSc = (tempSector / (unsigned int)16065 ) << 14; |
||
1284 | tempSector %= 16065; |
||
1285 | CyHdSc |= (tempSector / 63) << 6; |
||
1286 | tempSector %= 63; |
||
1287 | CyHdSc |= tempSector + 1; |
||
1288 | gDataBuffer[447] = (BYTE)((CyHdSc >> 16) & 0xFF); |
||
1289 | gDataBuffer[448] = (BYTE)((CyHdSc >> 8) & 0xFF); |
||
1290 | gDataBuffer[449] = (BYTE)((CyHdSc) & 0xFF); |
||
1291 | |||
1292 | // Set the count of sectors |
||
1293 | Partition->Partition0.PTE_NumSect = numSectors - firstSector; |
||
1294 | |||
1295 | // Set the partition type |
||
1296 | // We only support creating FAT12 and FAT16 MBRs at this time |
||
1297 | if (Partition->Partition0.PTE_NumSect < 0x1039) |
||
1298 | { |
||
1299 | // FAT12 |
||
1300 | Partition->Partition0.PTE_FSDesc = 0x01; |
||
1301 | } |
||
1302 | else if (Partition->Partition0.PTE_NumSect <= 0x3FFD5F) |
||
1303 | { |
||
1304 | // FAT16 |
||
1305 | Partition->Partition0.PTE_FSDesc = 0x06; |
||
1306 | } |
||
1307 | else |
||
1308 | return EOF; |
||
1309 | |||
1310 | // Set the LBA of the first sector |
||
1311 | Partition->Partition0.PTE_FrstSect = firstSector; |
||
1312 | |||
1313 | // Set the Cylinder-head-sector address of the last sector |
||
1314 | tempSector = firstSector + numSectors - 1; |
||
1315 | CyHdSc = (tempSector / (unsigned int)16065 ) << 14; |
||
1316 | tempSector %= 16065; |
||
1317 | CyHdSc |= (tempSector / 63) << 6; |
||
1318 | tempSector %= 63; |
||
1319 | CyHdSc |= tempSector + 1; |
||
1320 | gDataBuffer[451] = (BYTE)((CyHdSc >> 16) & 0xFF); |
||
1321 | gDataBuffer[452] = (BYTE)((CyHdSc >> 8) & 0xFF); |
||
1322 | gDataBuffer[453] = (BYTE)((CyHdSc) & 0xFF); |
||
1323 | |||
1324 | // Set the boot descriptor. This will be 0, since we won't |
||
1325 | // be booting anything from our device probably |
||
1326 | Partition->Partition0.PTE_BootDes = 0x00; |
||
1327 | |||
1328 | // Set the signature codes |
||
1329 | Partition->Signature0 = 0x55; |
||
1330 | Partition->Signature1 = 0xAA; |
||
1331 | |||
1332 | if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) != TRUE) |
||
1333 | return EOF; |
||
1334 | else |
||
1335 | return 0; |
||
1336 | |||
1337 | } |
||
1338 | |||
1339 | |||
1340 | |||
1341 | /******************************************************************* |
||
1342 | Function: |
||
1343 | int FSformat (char mode, long int serialNumber, char * volumeID) |
||
1344 | Summary: |
||
1345 | Formats a device |
||
1346 | Conditions: |
||
1347 | The device must possess a valid master boot record. |
||
1348 | Input: |
||
1349 | mode - - 0 - Just erase the FAT and root |
||
1350 | - 1 - Create a new boot sector |
||
1351 | serialNumber - Serial number to write to the card |
||
1352 | volumeID - Name of the card |
||
1353 | Return Values: |
||
1354 | |||
1355 | EOF - Format was unsuccessful |
||
1356 | Side Effects: |
||
1357 | The FSerrno variable will be changed. |
||
1358 | Description: |
||
1359 | The FSformat function can be used to create a new boot sector |
||
1360 | on a device, based on the information in the master boot record. |
||
1361 | This function will first initialize the I/O pins and the device, |
||
1362 | and then attempts to read the master boot record. If the MBR |
||
1363 | cannot be loaded successfully, the function will fail. Next, if |
||
1364 | the 'mode' argument is specified as '0' the existing boot sector |
||
1365 | information will be loaded. If the 'mode' argument is '1' an |
||
1366 | entirely new boot sector will be constructed using the disk |
||
1367 | values from the master boot record. Once the boot sector has |
||
1368 | been successfully loaded/created, the locations of the FAT and |
||
1369 | root will be loaded from it, and they will be completely |
||
1370 | erased. If the user has specified a volumeID parameter, a |
||
1371 | VOLUME attribute entry will be created in the root directory |
||
1372 | to name the device. |
||
1373 | |||
1374 | FAT12, FAT16 and FAT32 formatting are supported. |
||
1375 | |||
1376 | Based on the number of sectors, the format function automatically |
||
1377 | compute the smallest possible value for the cluster size in order to |
||
1378 | accommodate the physical size of the media. In this case, if a media |
||
1379 | with a big capacity is formatted, the format function may take a very |
||
1380 | long time to write all the FAT tables. |
||
1381 | |||
1382 | Therefore, the FORMAT_SECTORS_PER_CLUSTER macro may be used to |
||
1383 | specify the exact cluster size (in multiples of sector size). This |
||
1384 | macro can be defined in FSconfig.h |
||
1385 | |||
1386 | Remarks: |
||
1387 | Only devices with a sector size of 512 bytes are supported by the |
||
1388 | format function |
||
1389 | *******************************************************************/ |
||
1390 | |||
1391 | int FSformat (char mode, long int serialNumber, char * volumeID) |
||
1392 | { |
||
1393 | PT_MBR masterBootRecord; |
||
1394 | DWORD secCount, DataClusters, RootDirSectors; |
||
1395 | BootSec BSec; |
||
1396 | DISK d; |
||
1397 | DISK * disk = &d; |
||
1398 | WORD j; |
||
1399 | DWORD fatsize, test; |
||
1400 | DWORD Index; |
||
1401 | MEDIA_INFORMATION * mediaInfo; |
||
1402 | #ifdef __18CXX |
||
1403 | // This is here because of a C18 compiler feature |
||
1404 | BYTE * dataBufferPointer = gDataBuffer; |
||
1405 | #endif |
||
1406 | |||
1407 | FSerrno = CE_GOOD; |
||
1408 | |||
1409 | gBufferZeroed = FALSE; |
||
1410 | gNeedFATWrite = FALSE; |
||
1411 | gLastFATSectorRead = 0xFFFFFFFF; |
||
1412 | gLastDataSectorRead = 0xFFFFFFFF; |
||
1413 | |||
1414 | disk->buffer = gDataBuffer; |
||
1415 | |||
1416 | MDD_InitIO(); |
||
1417 | |||
1418 | mediaInfo = MDD_MediaInitialize(); |
||
1419 | if (mediaInfo->errorCode != MEDIA_NO_ERROR) |
||
1420 | { |
||
1421 | FSerrno = CE_INIT_ERROR; |
||
1422 | return EOF; |
||
1423 | } |
||
1424 | |||
1425 | if (MDD_SectorRead (0x00, gDataBuffer) == FALSE) |
||
1426 | { |
||
1427 | FSerrno = CE_BADCACHEREAD; |
||
1428 | return EOF; |
||
1429 | } |
||
1430 | |||
1431 | // Check if the card has no MBR |
||
1432 | BSec = (BootSec) disk->buffer; |
||
1433 | if((BSec->Signature0 == FAT_GOOD_SIGN_0) && (BSec->Signature1 == FAT_GOOD_SIGN_1)) |
||
1434 | { |
||
1435 | // Technically, the OEM name is not for indication |
||
1436 | // The alternative is to read the CIS from attribute |
||
1437 | // memory. See the PCMCIA metaformat for more details |
||
1438 | #if defined (__C30__) || defined (__PIC32MX__) |
||
1439 | if (ReadByte( disk->buffer, BSI_FSTYPE ) == 'F' && \ |
||
1440 | ReadByte( disk->buffer, BSI_FSTYPE + 1 ) == 'A' && \ |
||
1441 | ReadByte( disk->buffer, BSI_FSTYPE + 2 ) == 'T' && \ |
||
1442 | ReadByte( disk->buffer, BSI_FSTYPE + 3 ) == '1' && \ |
||
1443 | ReadByte( disk->buffer, BSI_BOOTSIG) == 0x29) |
||
1444 | #else |
||
1445 | if (BSec->FAT.FAT_16.BootSec_FSType[0] == 'F' && \ |
||
1446 | BSec->FAT.FAT_16.BootSec_FSType[1] == 'A' && \ |
||
1447 | BSec->FAT.FAT_16.BootSec_FSType[2] == 'T' && \ |
||
1448 | BSec->FAT.FAT_16.BootSec_FSType[3] == '1' && \ |
||
1449 | BSec->FAT.FAT_16.BootSec_BootSig == 0x29) |
||
1450 | #endif |
||
1451 | { |
||
1452 | /* Mark that we do not have a MBR; |
||
1453 | this is not actualy used - is here only to remove a compilation warning */ |
||
1454 | masterBootRecord = (PT_MBR) NULL; |
||
1455 | switch (mode) |
||
1456 | { |
||
1457 | case 1: |
||
1458 | // not enough info to construct our own boot sector |
||
1459 | FSerrno = CE_INVALID_ARGUMENT; |
||
1460 | return EOF; |
||
1461 | case 0: |
||
1462 | // We have to determine the operating system, and the |
||
1463 | // locations and sizes of the root dir and FAT, and the |
||
1464 | // count of FATs |
||
1465 | disk->firsts = 0; |
||
1466 | if (LoadBootSector (disk) != CE_GOOD) |
||
1467 | { |
||
1468 | FSerrno = CE_BADCACHEREAD; |
||
1469 | return EOF; |
||
1470 | } |
||
1471 | default: |
||
1472 | break; |
||
1473 | } |
||
1474 | } |
||
1475 | else |
||
1476 | { |
||
1477 | masterBootRecord = (PT_MBR) &gDataBuffer; |
||
1478 | disk->firsts = masterBootRecord->Partition0.PTE_FrstSect; |
||
1479 | } |
||
1480 | } |
||
1481 | else |
||
1482 | { |
||
1483 | /* If the signature is not correct, this is neither a MBR, nor a VBR */ |
||
1484 | FSerrno = CE_BAD_PARTITION; |
||
1485 | return EOF; |
||
1486 | } |
||
1487 | |||
1488 | switch (mode) |
||
1489 | { |
||
1490 | // True: Rewrite the whole boot sector |
||
1491 | case 1: |
||
1492 | secCount = masterBootRecord->Partition0.PTE_NumSect; |
||
1493 | |||
1494 | if (secCount < 0x1039) |
||
1495 | { |
||
1496 | disk->type = FAT12; |
||
1497 | // Format to FAT12 only if there are too few sectors to format |
||
1498 | // as FAT16 |
||
1499 | masterBootRecord->Partition0.PTE_FSDesc = 0x01; |
||
1500 | if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE) |
||
1501 | { |
||
1502 | FSerrno = CE_WRITE_ERROR; |
||
1503 | return EOF; |
||
1504 | } |
||
1505 | |||
1506 | if (secCount >= 0x1028) |
||
1507 | { |
||
1508 | // More than 0x18 sectors for FATs, 0x20 for root dir, |
||
1509 | // 0x8 reserved, and 0xFED for data |
||
1510 | // So double the number of sectors in a cluster to reduce |
||
1511 | // the number of data clusters used |
||
1512 | disk->SecPerClus = 2; |
||
1513 | } |
||
1514 | else |
||
1515 | { |
||
1516 | // One sector per cluster |
||
1517 | disk->SecPerClus = 1; |
||
1518 | } |
||
1519 | |||
1520 | // Prepare a boot sector |
||
1521 | memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE); |
||
1522 | |||
1523 | // Last digit of file system name (FAT12 ) |
||
1524 | gDataBuffer[58] = '2'; |
||
1525 | |||
1526 | // Calculate the size of the FAT |
||
1527 | fatsize = (secCount - 0x21 + (2*disk->SecPerClus)); |
||
1528 | test = (341 * disk->SecPerClus) + 2; |
||
1529 | fatsize = (fatsize + (test-1)) / test; |
||
1530 | |||
1531 | disk->fatcopy = 0x02; |
||
1532 | disk->maxroot = 0x200; |
||
1533 | |||
1534 | disk->fatsize = fatsize; |
||
1535 | |||
1536 | } |
||
1537 | else if (secCount <= 0x3FFD5F) |
||
1538 | { |
||
1539 | disk->type = FAT16; |
||
1540 | // Format to FAT16 |
||
1541 | masterBootRecord->Partition0.PTE_FSDesc = 0x06; |
||
1542 | if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE) |
||
1543 | { |
||
1544 | FSerrno = CE_WRITE_ERROR; |
||
1545 | return EOF; |
||
1546 | } |
||
1547 | |||
1548 | DataClusters = secCount - 0x218; |
||
1549 | // Figure out how many sectors per cluster we need |
||
1550 | disk->SecPerClus = 1; |
||
1551 | while (DataClusters > 0xFFED) |
||
1552 | { |
||
1553 | disk->SecPerClus *= 2; |
||
1554 | DataClusters /= 2; |
||
1555 | } |
||
1556 | // This shouldnt happen |
||
1557 | if (disk->SecPerClus > 128) |
||
1558 | { |
||
1559 | FSerrno = CE_BAD_PARTITION; |
||
1560 | return EOF; |
||
1561 | } |
||
1562 | |||
1563 | // Prepare a boot sector |
||
1564 | memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE); |
||
1565 | |||
1566 | // Last digit of file system name (FAT16 ) |
||
1567 | gDataBuffer[58] = '6'; |
||
1568 | |||
1569 | // Calculate the size of the FAT |
||
1570 | fatsize = (secCount - 0x21 + (2*disk->SecPerClus)); |
||
1571 | test = (256 * disk->SecPerClus) + 2; |
||
1572 | fatsize = (fatsize + (test-1)) / test; |
||
1573 | |||
1574 | disk->fatcopy = 0x02; |
||
1575 | disk->maxroot = 0x200; |
||
1576 | |||
1577 | disk->fatsize = fatsize; |
||
1578 | } |
||
1579 | else |
||
1580 | { |
||
1581 | disk->type = FAT32; |
||
1582 | // Format to FAT32 |
||
1583 | masterBootRecord->Partition0.PTE_FSDesc = 0x0B; |
||
1584 | if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE) |
||
1585 | { |
||
1586 | FSerrno = CE_WRITE_ERROR; |
||
1587 | return EOF; |
||
1588 | } |
||
1589 | |||
1590 | #ifdef FORMAT_SECTORS_PER_CLUSTER |
||
1591 | disk->SecPerClus = FORMAT_SECTORS_PER_CLUSTER; |
||
1592 | DataClusters = secCount / disk->SecPerClus; |
||
1593 | |||
1594 | /* FAT32: 65526 < Number of clusters < 4177918 */ |
||
1595 | if ((DataClusters <= 65526) || (DataClusters >= 4177918)) |
||
1596 | { |
||
1597 | FSerrno = CE_BAD_PARTITION; |
||
1598 | return EOF; |
||
1599 | } |
||
1600 | #else |
||
1601 | /* FAT32: 65526 < Number of clusters < 4177918 */ |
||
1602 | DataClusters = secCount; |
||
1603 | // Figure out how many sectors per cluster we need |
||
1604 | disk->SecPerClus = 1; |
||
1605 | while (DataClusters > 0x3FBFFE) |
||
1606 | { |
||
1607 | disk->SecPerClus *= 2; |
||
1608 | DataClusters /= 2; |
||
1609 | } |
||
1610 | #endif |
||
1611 | // Check the cluster size: FAT32 supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K |
||
1612 | if (disk->SecPerClus > 128) |
||
1613 | { |
||
1614 | FSerrno = CE_BAD_PARTITION; |
||
1615 | return EOF; |
||
1616 | } |
||
1617 | |||
1618 | // Prepare a boot sector |
||
1619 | memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE); |
||
1620 | |||
1621 | // Calculate the size of the FAT |
||
1622 | fatsize = (secCount - 0x20); |
||
1623 | test = (128 * disk->SecPerClus) + 1; |
||
1624 | fatsize = (fatsize + (test-1)) / test; |
||
1625 | |||
1626 | disk->fatcopy = 0x02; |
||
1627 | disk->maxroot = 0x200; |
||
1628 | |||
1629 | disk->fatsize = fatsize; |
||
1630 | } |
||
1631 | |||
1632 | // Non-file system specific values |
||
1633 | gDataBuffer[0] = 0xEB; //Jump instruction |
||
1634 | gDataBuffer[1] = 0x3C; |
||
1635 | gDataBuffer[2] = 0x90; |
||
1636 | gDataBuffer[3] = 'M'; //OEM Name "MCHP FAT" |
||
1637 | gDataBuffer[4] = 'C'; |
||
1638 | gDataBuffer[5] = 'H'; |
||
1639 | gDataBuffer[6] = 'P'; |
||
1640 | gDataBuffer[7] = ' '; |
||
1641 | gDataBuffer[8] = 'F'; |
||
1642 | gDataBuffer[9] = 'A'; |
||
1643 | gDataBuffer[10] = 'T'; |
||
1644 | |||
1645 | gDataBuffer[11] = 0x00; //Sector size |
||
1646 | gDataBuffer[12] = 0x02; |
||
1647 | |||
1648 | gDataBuffer[13] = disk->SecPerClus; //Sectors per cluster |
||
1649 | |||
1650 | if (disk->type == FAT12 || disk->type == FAT16) |
||
1651 | { |
||
1652 | gDataBuffer[14] = 0x08; //Reserved sector count |
||
1653 | gDataBuffer[15] = 0x00; |
||
1654 | disk->fat = 0x08 + disk->firsts; |
||
1655 | |||
1656 | gDataBuffer[16] = 0x02; //number of FATs |
||
1657 | |||
1658 | gDataBuffer[17] = 0x00; //Max number of root directory entries - 512 files allowed |
||
1659 | gDataBuffer[18] = 0x02; |
||
1660 | |||
1661 | gDataBuffer[19] = 0x00; //total sectors |
||
1662 | gDataBuffer[20] = 0x00; |
||
1663 | |||
1664 | gDataBuffer[21] = 0xF8; //Media Descriptor |
||
1665 | |||
1666 | gDataBuffer[22] = fatsize & 0xFF; //Sectors per FAT |
||
1667 | gDataBuffer[23] = (fatsize >> 8) & 0xFF; |
||
1668 | |||
1669 | gDataBuffer[24] = 0x3F; //Sectors per track |
||
1670 | gDataBuffer[25] = 0x00; |
||
1671 | |||
1672 | gDataBuffer[26] = 0xFF; //Number of heads |
||
1673 | gDataBuffer[27] = 0x00; |
||
1674 | |||
1675 | // Hidden sectors = sectors between the MBR and the boot sector |
||
1676 | gDataBuffer[28] = (BYTE)(disk->firsts & 0xFF); |
||
1677 | gDataBuffer[29] = (BYTE)((disk->firsts / 0x100) & 0xFF); |
||
1678 | gDataBuffer[30] = (BYTE)((disk->firsts / 0x10000) & 0xFF); |
||
1679 | gDataBuffer[31] = (BYTE)((disk->firsts / 0x1000000) & 0xFF); |
||
1680 | |||
1681 | // Total Sectors = same as sectors in the partition from MBR |
||
1682 | gDataBuffer[32] = (BYTE)(secCount & 0xFF); |
||
1683 | gDataBuffer[33] = (BYTE)((secCount / 0x100) & 0xFF); |
||
1684 | gDataBuffer[34] = (BYTE)((secCount / 0x10000) & 0xFF); |
||
1685 | gDataBuffer[35] = (BYTE)((secCount / 0x1000000) & 0xFF); |
||
1686 | |||
1687 | gDataBuffer[36] = 0x00; // Physical drive number |
||
1688 | |||
1689 | gDataBuffer[37] = 0x00; // Reserved (current head) |
||
1690 | |||
1691 | gDataBuffer[38] = 0x29; // Signature code |
||
1692 | |||
1693 | gDataBuffer[39] = (BYTE)(serialNumber & 0xFF); |
||
1694 | gDataBuffer[40] = (BYTE)((serialNumber / 0x100) & 0xFF); |
||
1695 | gDataBuffer[41] = (BYTE)((serialNumber / 0x10000) & 0xFF); |
||
1696 | gDataBuffer[42] = (BYTE)((serialNumber / 0x1000000) & 0xFF); |
||
1697 | |||
1698 | // Volume ID |
||
1699 | if (volumeID != NULL) |
||
1700 | { |
||
1701 | for (Index = 0; (*(volumeID + Index) != 0) && (Index < 11); Index++) |
||
1702 | { |
||
1703 | gDataBuffer[Index + 43] = *(volumeID + Index); |
||
1704 | } |
||
1705 | while (Index < 11) |
||
1706 | { |
||
1707 | gDataBuffer[43 + Index++] = 0x20; |
||
1708 | } |
||
1709 | } |
||
1710 | else |
||
1711 | { |
||
1712 | for (Index = 0; Index < 11; Index++) |
||
1713 | { |
||
1714 | gDataBuffer[Index+43] = 0; |
||
1715 | } |
||
1716 | } |
||
1717 | |||
1718 | gDataBuffer[54] = 'F'; |
||
1719 | gDataBuffer[55] = 'A'; |
||
1720 | gDataBuffer[56] = 'T'; |
||
1721 | gDataBuffer[57] = '1'; |
||
1722 | gDataBuffer[59] = ' '; |
||
1723 | gDataBuffer[60] = ' '; |
||
1724 | gDataBuffer[61] = ' '; |
||
1725 | |||
1726 | } |
||
1727 | else //FAT32 |
||
1728 | { |
||
1729 | gDataBuffer[14] = 0x20; //Reserved sector count |
||
1730 | gDataBuffer[15] = 0x00; |
||
1731 | disk->fat = 0x20 + disk->firsts; |
||
1732 | |||
1733 | gDataBuffer[16] = 0x02; //number of FATs |
||
1734 | |||
1735 | gDataBuffer[17] = 0x00; //Max number of root directory entries - 512 files allowed |
||
1736 | gDataBuffer[18] = 0x00; |
||
1737 | |||
1738 | gDataBuffer[19] = 0x00; //total sectors |
||
1739 | gDataBuffer[20] = 0x00; |
||
1740 | |||
1741 | gDataBuffer[21] = 0xF8; //Media Descriptor |
||
1742 | |||
1743 | gDataBuffer[22] = 0x00; //Sectors per FAT |
||
1744 | gDataBuffer[23] = 0x00; |
||
1745 | |||
1746 | gDataBuffer[24] = 0x3F; //Sectors per track |
||
1747 | gDataBuffer[25] = 0x00; |
||
1748 | |||
1749 | gDataBuffer[26] = 0xFF; //Number of heads |
||
1750 | gDataBuffer[27] = 0x00; |
||
1751 | |||
1752 | // Hidden sectors = sectors between the MBR and the boot sector |
||
1753 | gDataBuffer[28] = (BYTE)(disk->firsts & 0xFF); |
||
1754 | gDataBuffer[29] = (BYTE)((disk->firsts / 0x100) & 0xFF); |
||
1755 | gDataBuffer[30] = (BYTE)((disk->firsts / 0x10000) & 0xFF); |
||
1756 | gDataBuffer[31] = (BYTE)((disk->firsts / 0x1000000) & 0xFF); |
||
1757 | |||
1758 | // Total Sectors = same as sectors in the partition from MBR |
||
1759 | gDataBuffer[32] = (BYTE)(secCount & 0xFF); |
||
1760 | gDataBuffer[33] = (BYTE)((secCount / 0x100) & 0xFF); |
||
1761 | gDataBuffer[34] = (BYTE)((secCount / 0x10000) & 0xFF); |
||
1762 | gDataBuffer[35] = (BYTE)((secCount / 0x1000000) & 0xFF); |
||
1763 | |||
1764 | gDataBuffer[36] = fatsize & 0xFF; //Sectors per FAT |
||
1765 | gDataBuffer[37] = (fatsize >> 8) & 0xFF; |
||
1766 | gDataBuffer[38] = (fatsize >> 16) & 0xFF; |
||
1767 | gDataBuffer[39] = (fatsize >> 24) & 0xFF; |
||
1768 | |||
1769 | gDataBuffer[40] = 0x00; //Active FAT |
||
1770 | gDataBuffer[41] = 0x00; |
||
1771 | |||
1772 | gDataBuffer[42] = 0x00; //File System version |
||
1773 | gDataBuffer[43] = 0x00; |
||
1774 | |||
1775 | gDataBuffer[44] = 0x02; //First cluster of the root directory |
||
1776 | gDataBuffer[45] = 0x00; |
||
1777 | gDataBuffer[46] = 0x00; |
||
1778 | gDataBuffer[47] = 0x00; |
||
1779 | |||
1780 | gDataBuffer[48] = 0x01; //FSInfo |
||
1781 | gDataBuffer[49] = 0x00; |
||
1782 | |||
1783 | gDataBuffer[50] = 0x00; //Backup Boot Sector |
||
1784 | gDataBuffer[51] = 0x00; |
||
1785 | |||
1786 | gDataBuffer[52] = 0x00; //Reserved for future expansion |
||
1787 | gDataBuffer[53] = 0x00; |
||
1788 | gDataBuffer[54] = 0x00; |
||
1789 | gDataBuffer[55] = 0x00; |
||
1790 | gDataBuffer[56] = 0x00; |
||
1791 | gDataBuffer[57] = 0x00; |
||
1792 | gDataBuffer[58] = 0x00; |
||
1793 | gDataBuffer[59] = 0x00; |
||
1794 | gDataBuffer[60] = 0x00; |
||
1795 | gDataBuffer[61] = 0x00; |
||
1796 | gDataBuffer[62] = 0x00; |
||
1797 | gDataBuffer[63] = 0x00; |
||
1798 | |||
1799 | gDataBuffer[64] = 0x00; // Physical drive number |
||
1800 | |||
1801 | gDataBuffer[65] = 0x00; // Reserved (current head) |
||
1802 | |||
1803 | gDataBuffer[66] = 0x29; // Signature code |
||
1804 | |||
1805 | gDataBuffer[67] = (BYTE)(serialNumber & 0xFF); |
||
1806 | gDataBuffer[68] = (BYTE)((serialNumber / 0x100) & 0xFF); |
||
1807 | gDataBuffer[69] = (BYTE)((serialNumber / 0x10000) & 0xFF); |
||
1808 | gDataBuffer[70] = (BYTE)((serialNumber / 0x1000000) & 0xFF); |
||
1809 | |||
1810 | // Volume ID |
||
1811 | if (volumeID != NULL) |
||
1812 | { |
||
1813 | for (Index = 0; (*(volumeID + Index) != 0) && (Index < 11); Index++) |
||
1814 | { |
||
1815 | gDataBuffer[Index + 71] = *(volumeID + Index); |
||
1816 | } |
||
1817 | while (Index < 11) |
||
1818 | { |
||
1819 | gDataBuffer[71 + Index++] = 0x20; |
||
1820 | } |
||
1821 | } |
||
1822 | else |
||
1823 | { |
||
1824 | for (Index = 0; Index < 11; Index++) |
||
1825 | { |
||
1826 | gDataBuffer[Index+71] = 0; |
||
1827 | } |
||
1828 | } |
||
1829 | |||
1830 | gDataBuffer[82] = 'F'; |
||
1831 | gDataBuffer[83] = 'A'; |
||
1832 | gDataBuffer[84] = 'T'; |
||
1833 | gDataBuffer[85] = '3'; |
||
1834 | gDataBuffer[86] = '2'; |
||
1835 | gDataBuffer[87] = ' '; |
||
1836 | gDataBuffer[88] = ' '; |
||
1837 | gDataBuffer[89] = ' '; |
||
1838 | |||
1839 | |||
1840 | } |
||
1841 | |||
1842 | #ifdef __18CXX |
||
1843 | // C18 can't reference a value greater than 256 |
||
1844 | // using an array name pointer |
||
1845 | *(dataBufferPointer + 510) = 0x55; |
||
1846 | *(dataBufferPointer + 511) = 0xAA; |
||
1847 | #else |
||
1848 | gDataBuffer[510] = 0x55; |
||
1849 | gDataBuffer[511] = 0xAA; |
||
1850 | #endif |
||
1851 | |||
1852 | disk->root = disk->fat + (disk->fatcopy * disk->fatsize); |
||
1853 | |||
1854 | if (MDD_SectorWrite (disk->firsts, gDataBuffer, FALSE) == FALSE) |
||
1855 | { |
||
1856 | FSerrno = CE_WRITE_ERROR; |
||
1857 | return EOF; |
||
1858 | } |
||
1859 | |||
1860 | break; |
||
1861 | case 0: |
||
1862 | if (LoadBootSector (disk) != CE_GOOD) |
||
1863 | { |
||
1864 | FSerrno = CE_BADCACHEREAD; |
||
1865 | return EOF; |
||
1866 | } |
||
1867 | break; |
||
1868 | default: |
||
1869 | FSerrno = CE_INVALID_ARGUMENT; |
||
1870 | return EOF; |
||
1871 | } |
||
1872 | |||
1873 | // Erase the FAT |
||
1874 | memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE); |
||
1875 | |||
1876 | if (disk->type == FAT32) |
||
1877 | { |
||
1878 | gDataBuffer[0] = 0xF8; //BPB_Media byte value in its low 8 bits, and all other bits are set to 1 |
||
1879 | gDataBuffer[1] = 0xFF; |
||
1880 | gDataBuffer[2] = 0xFF; |
||
1881 | gDataBuffer[3] = 0xFF; |
||
1882 | |||
1883 | gDataBuffer[4] = 0x00; //Disk is clean and no read/write errors were encountered |
||
1884 | gDataBuffer[5] = 0x00; |
||
1885 | gDataBuffer[6] = 0x00; |
||
1886 | gDataBuffer[7] = 0x0C; |
||
1887 | |||
1888 | gDataBuffer[8] = 0xFF; //Root Directory EOF |
||
1889 | gDataBuffer[9] = 0xFF; |
||
1890 | gDataBuffer[10] = 0xFF; |
||
1891 | gDataBuffer[11] = 0xFF; |
||
1892 | |||
1893 | for (j = disk->fatcopy - 1; j != 0xFFFF; j--) |
||
1894 | { |
||
1895 | if (MDD_SectorWrite (disk->fat + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE) |
||
1896 | return EOF; |
||
1897 | } |
||
1898 | |||
1899 | memset (gDataBuffer, 0x00, 12); |
||
1900 | |||
1901 | for (Index = disk->fat + 1; Index < (disk->fat + disk->fatsize); Index++) |
||
1902 | { |
||
1903 | for (j = disk->fatcopy - 1; j != 0xFFFF; j--) |
||
1904 | { |
||
1905 | if (MDD_SectorWrite (Index + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE) |
||
1906 | return EOF; |
||
1907 | } |
||
1908 | } |
||
1909 | |||
1910 | // Erase the root directory |
||
1911 | for (Index = 1; Index < disk->SecPerClus; Index++) |
||
1912 | { |
||
1913 | if (MDD_SectorWrite (disk->root + Index, gDataBuffer, FALSE) == FALSE) |
||
1914 | return EOF; |
||
1915 | } |
||
1916 | |||
1917 | if (volumeID != NULL) |
||
1918 | { |
||
1919 | // Create a drive name entry in the root dir |
||
1920 | Index = 0; |
||
1921 | while ((*(volumeID + Index) != 0) && (Index < 11)) |
||
1922 | { |
||
1923 | gDataBuffer[Index] = *(volumeID + Index); |
||
1924 | Index++; |
||
1925 | } |
||
1926 | while (Index < 11) |
||
1927 | { |
||
1928 | gDataBuffer[Index++] = ' '; |
||
1929 | } |
||
1930 | gDataBuffer[11] = 0x08; |
||
1931 | gDataBuffer[17] = 0x11; |
||
1932 | gDataBuffer[19] = 0x11; |
||
1933 | gDataBuffer[23] = 0x11; |
||
1934 | |||
1935 | if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE) |
||
1936 | return EOF; |
||
1937 | } |
||
1938 | else |
||
1939 | { |
||
1940 | if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE) |
||
1941 | return EOF; |
||
1942 | } |
||
1943 | |||
1944 | return 0; |
||
1945 | } |
||
1946 | else |
||
1947 | { |
||
1948 | gDataBuffer[0] = 0xF8; |
||
1949 | gDataBuffer[1] = 0xFF; |
||
1950 | gDataBuffer[2] = 0xFF; |
||
1951 | if (disk->type == FAT16) |
||
1952 | gDataBuffer[3] = 0xFF; |
||
1953 | |||
1954 | for (j = disk->fatcopy - 1; j != 0xFFFF; j--) |
||
1955 | { |
||
1956 | if (MDD_SectorWrite (disk->fat + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE) |
||
1957 | return EOF; |
||
1958 | } |
||
1959 | |||
1960 | memset (gDataBuffer, 0x00, 4); |
||
1961 | |||
1962 | for (Index = disk->fat + 1; Index < (disk->fat + disk->fatsize); Index++) |
||
1963 | { |
||
1964 | for (j = disk->fatcopy - 1; j != 0xFFFF; j--) |
||
1965 | { |
||
1966 | if (MDD_SectorWrite (Index + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE) |
||
1967 | return EOF; |
||
1968 | } |
||
1969 | } |
||
1970 | |||
1971 | // Erase the root directory |
||
1972 | RootDirSectors = ((disk->maxroot * 32) + (disk->sectorSize - 1)) / disk->sectorSize; |
||
1973 | |||
1974 | for (Index = 1; Index < RootDirSectors; Index++) |
||
1975 | { |
||
1976 | if (MDD_SectorWrite (disk->root + Index, gDataBuffer, FALSE) == FALSE) |
||
1977 | return EOF; |
||
1978 | } |
||
1979 | |||
1980 | if (volumeID != NULL) |
||
1981 | { |
||
1982 | // Create a drive name entry in the root dir |
||
1983 | Index = 0; |
||
1984 | while ((*(volumeID + Index) != 0) && (Index < 11)) |
||
1985 | { |
||
1986 | gDataBuffer[Index] = *(volumeID + Index); |
||
1987 | Index++; |
||
1988 | } |
||
1989 | while (Index < 11) |
||
1990 | { |
||
1991 | gDataBuffer[Index++] = ' '; |
||
1992 | } |
||
1993 | gDataBuffer[11] = 0x08; |
||
1994 | gDataBuffer[17] = 0x11; |
||
1995 | gDataBuffer[19] = 0x11; |
||
1996 | gDataBuffer[23] = 0x11; |
||
1997 | |||
1998 | if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE) |
||
1999 | return EOF; |
||
2000 | } |
||
2001 | else |
||
2002 | { |
||
2003 | if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE) |
||
2004 | return EOF; |
||
2005 | } |
||
2006 | |||
2007 | return 0; |
||
2008 | } |
||
2009 | } |
||
2010 | #endif |
||
2011 | #endif |
||
2012 | |||
2013 | |||
2014 | /******************************************************* |
||
2015 | Function: |
||
2016 | BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry) |
||
2017 | Summary: |
||
2018 | Write dir entry info into a specified entry |
||
2019 | Conditions: |
||
2020 | This function should not be called by the user. |
||
2021 | Input: |
||
2022 | fo - \File structure |
||
2023 | curEntry - Write destination |
||
2024 | Return Values: |
||
2025 | TRUE - Operation successful |
||
2026 | FALSE - Operation failed |
||
2027 | Side Effects: |
||
2028 | None |
||
2029 | Description: |
||
2030 | This function will calculate the sector of the |
||
2031 | directory (whose base sector is pointed to by the |
||
2032 | dirccls value in the FSFILE object 'fo') that contains |
||
2033 | a directory entry whose offset is indicated by the |
||
2034 | curEntry parameter. It will then write the data |
||
2035 | in the global data buffer (which should already |
||
2036 | contain the entries for that sector) to the device. |
||
2037 | Remarks: |
||
2038 | None |
||
2039 | *******************************************************/ |
||
2040 | |||
2041 | #ifdef ALLOW_WRITES |
||
2042 | BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry) |
||
2043 | { |
||
2044 | DISK *dsk; |
||
2045 | BYTE status; |
||
2046 | BYTE offset2; |
||
2047 | DWORD sector; |
||
2048 | DWORD ccls; |
||
2049 | |||
2050 | dsk = fo->dsk; |
||
2051 | |||
2052 | // get the cluster of this entry |
||
2053 | ccls = fo->dirccls; |
||
2054 | |||
2055 | // figure out the offset from the base sector |
||
2056 | offset2 = (*curEntry / (dsk->sectorSize/32)); |
||
2057 | |||
2058 | /* Settings based on FAT type */ |
||
2059 | switch (dsk->type) |
||
2060 | { |
||
2061 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2062 | case FAT32: |
||
2063 | // Root is always cluster-based in FAT32 |
||
2064 | offset2 = offset2 % (dsk->SecPerClus); |
||
2065 | break; |
||
2066 | #endif |
||
2067 | case FAT12: |
||
2068 | case FAT16: |
||
2069 | if(ccls != FatRootDirClusterValue) |
||
2070 | offset2 = offset2 % (dsk->SecPerClus); |
||
2071 | break; |
||
2072 | } |
||
2073 | |||
2074 | sector = Cluster2Sector(dsk,ccls); |
||
2075 | |||
2076 | // Now write it |
||
2077 | // "Offset" ensures writing of data belonging to a file entry only. Hence it doesn't change other file entries. |
||
2078 | if ( !MDD_SectorWrite( sector + offset2, dsk->buffer, FALSE)) |
||
2079 | status = FALSE; |
||
2080 | else |
||
2081 | status = TRUE; |
||
2082 | |||
2083 | return(status); |
||
2084 | } // Write_File_Entry |
||
2085 | #endif |
||
2086 | |||
2087 | |||
2088 | /********************************************************** |
||
2089 | Function: |
||
2090 | BYTE FAT_erase_cluster_chain (WORD cluster, DISK * dsk) |
||
2091 | Summary: |
||
2092 | Erase a chain of clusters |
||
2093 | Conditions: |
||
2094 | This function should not be called by the user. |
||
2095 | Input: |
||
2096 | cluster - The cluster number |
||
2097 | dsk - The disk structure |
||
2098 | Return Values: |
||
2099 | TRUE - Operation successful |
||
2100 | FALSE - Operation failed |
||
2101 | Side Effects: |
||
2102 | None |
||
2103 | Description: |
||
2104 | This function will parse through a cluster chain |
||
2105 | starting with the cluster pointed to by 'cluster' and |
||
2106 | mark all of the FAT entries as empty until the end of |
||
2107 | the chain has been reached or an error occurs. |
||
2108 | Remarks: |
||
2109 | None |
||
2110 | **********************************************************/ |
||
2111 | |||
2112 | #ifdef ALLOW_WRITES |
||
2113 | BYTE FAT_erase_cluster_chain (DWORD cluster, DISK * dsk) |
||
2114 | { |
||
2115 | DWORD c,c2,ClusterFailValue; |
||
2116 | enum _status {Good, Fail, Exit}status; |
||
2117 | |||
2118 | status = Good; |
||
2119 | |||
2120 | /* Settings based on FAT type */ |
||
2121 | switch (dsk->type) |
||
2122 | { |
||
2123 | |||
2124 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2125 | case FAT32: |
||
2126 | ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
2127 | c2 = LAST_CLUSTER_FAT32; |
||
2128 | break; |
||
2129 | #endif |
||
2130 | case FAT12: |
||
2131 | ClusterFailValue = CLUSTER_FAIL_FAT16; // FAT16 value itself |
||
2132 | c2 = LAST_CLUSTER_FAT12; |
||
2133 | break; |
||
2134 | case FAT16: |
||
2135 | default: |
||
2136 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
2137 | c2 = LAST_CLUSTER_FAT16; |
||
2138 | break; |
||
2139 | } |
||
2140 | |||
2141 | // Make sure there is actually a cluster assigned |
||
2142 | if(cluster == 0 || cluster == 1) // Cluster assigned can't be "0" and "1" |
||
2143 | { |
||
2144 | status = Exit; |
||
2145 | } |
||
2146 | else |
||
2147 | { |
||
2148 | while(status == Good) |
||
2149 | { |
||
2150 | // Get the FAT entry |
||
2151 | if((c = ReadFAT( dsk, cluster)) == ClusterFailValue) |
||
2152 | status = Fail; |
||
2153 | else |
||
2154 | { |
||
2155 | if(c == 0 || c == 1) // Cluster assigned can't be "0" and "1" |
||
2156 | { |
||
2157 | status = Exit; |
||
2158 | } |
||
2159 | else |
||
2160 | { |
||
2161 | // compare against max value of a cluster in FATxx |
||
2162 | // look for the last cluster in the chain |
||
2163 | if ( c >= c2) |
||
2164 | status = Exit; |
||
2165 | |||
2166 | // Now erase this FAT entry |
||
2167 | if(WriteFAT(dsk, cluster, CLUSTER_EMPTY, FALSE) == ClusterFailValue) |
||
2168 | status = Fail; |
||
2169 | |||
2170 | // now update what the current cluster is |
||
2171 | cluster = c; |
||
2172 | } |
||
2173 | } |
||
2174 | }// while status |
||
2175 | }// cluster == 0 |
||
2176 | |||
2177 | WriteFAT (dsk, 0, 0, TRUE); |
||
2178 | |||
2179 | if(status == Exit) |
||
2180 | return(TRUE); |
||
2181 | else |
||
2182 | return(FALSE); |
||
2183 | } // Erase cluster |
||
2184 | #endif |
||
2185 | |||
2186 | /************************************************************************** |
||
2187 | Function: |
||
2188 | DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead) |
||
2189 | Summary: |
||
2190 | Load a file entry |
||
2191 | Conditions: |
||
2192 | This function should not be called by the user. |
||
2193 | Input: |
||
2194 | fo - File information |
||
2195 | curEntry - Offset of the directory entry to load. |
||
2196 | ForceRead - Forces loading of a new sector of the directory. |
||
2197 | Return: |
||
2198 | DIRENTRY - Pointer to the directory entry that was loaded. |
||
2199 | Side Effects: |
||
2200 | Any unwritten data in the data buffer will be written to the device. |
||
2201 | Description: |
||
2202 | Load the sector containing the file entry pointed to by 'curEntry' |
||
2203 | from the directory pointed to by the variables in 'fo.' |
||
2204 | Remarks: |
||
2205 | Any modification of this function is extremely likely to |
||
2206 | break something. |
||
2207 | **************************************************************************/ |
||
2208 | |||
2209 | DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead) |
||
2210 | { |
||
2211 | DIRENTRY dir; |
||
2212 | DISK *dsk; |
||
2213 | DWORD sector; |
||
2214 | DWORD cluster, LastClusterLimit; |
||
2215 | DWORD ccls; |
||
2216 | BYTE offset2; |
||
2217 | BYTE numofclus; |
||
2218 | |||
2219 | dsk = fo->dsk; |
||
2220 | |||
2221 | // get the base sector of this directory |
||
2222 | cluster = fo->dirclus; |
||
2223 | ccls = fo->dirccls; |
||
2224 | |||
2225 | // figure out the offset from the base sector |
||
2226 | offset2 = (*curEntry / (dsk->sectorSize/32)); |
||
2227 | |||
2228 | offset2 = offset2; // emulator issue |
||
2229 | |||
2230 | /* Settings based on FAT type */ |
||
2231 | switch (dsk->type) |
||
2232 | { |
||
2233 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2234 | case FAT32: |
||
2235 | // the ROOT is always cluster based in FAT32 |
||
2236 | /* In FAT32: There is no ROOT region. Root etries are made in DATA region only. |
||
2237 | Every cluster of DATA which is accupied by ROOT is tracked by FAT table/entry so the ROOT can grow |
||
2238 | to an amount which is restricted only by available free DATA region. */ |
||
2239 | offset2 = offset2 % (dsk->SecPerClus); // figure out the offset |
||
2240 | LastClusterLimit = LAST_CLUSTER_FAT32; |
||
2241 | break; |
||
2242 | #endif |
||
2243 | case FAT12: |
||
2244 | case FAT16: |
||
2245 | default: |
||
2246 | // if its the root its not cluster based |
||
2247 | if(cluster != 0) |
||
2248 | offset2 = offset2 % (dsk->SecPerClus); // figure out the offset |
||
2249 | LastClusterLimit = LAST_CLUSTER_FAT16; |
||
2250 | break; |
||
2251 | } |
||
2252 | |||
2253 | // check if a new sector of the root must be loaded |
||
2254 | if (ForceRead || (*curEntry & MASK_MAX_FILE_ENTRY_LIMIT_BITS) == 0) // only 16 entries per sector |
||
2255 | { |
||
2256 | // see if we have to load a new cluster |
||
2257 | if((offset2 == 0 && (*curEntry) >= DIRENTRIES_PER_SECTOR) || ForceRead) |
||
2258 | { |
||
2259 | if(cluster == 0) |
||
2260 | { |
||
2261 | ccls = 0; |
||
2262 | } |
||
2263 | else |
||
2264 | { |
||
2265 | // If ForceRead, read the number of sectors from 0 |
||
2266 | if(ForceRead) |
||
2267 | numofclus = ((WORD)(*curEntry) / (WORD)(((WORD)DIRENTRIES_PER_SECTOR) * (WORD)dsk->SecPerClus)); |
||
2268 | // Otherwise just read the next sector |
||
2269 | else |
||
2270 | numofclus = 1; |
||
2271 | |||
2272 | // move to the correct cluster |
||
2273 | while(numofclus) |
||
2274 | { |
||
2275 | ccls = ReadFAT(dsk, ccls); |
||
2276 | |||
2277 | if(ccls >= LastClusterLimit) |
||
2278 | break; |
||
2279 | else |
||
2280 | numofclus--; |
||
2281 | } |
||
2282 | } |
||
2283 | } |
||
2284 | |||
2285 | // see if that we have a valid cluster number |
||
2286 | if(ccls < LastClusterLimit) |
||
2287 | { |
||
2288 | fo->dirccls = ccls; // write it back |
||
2289 | |||
2290 | sector = Cluster2Sector(dsk,ccls); |
||
2291 | |||
2292 | /* see if we are root and about to go pass our boundaries |
||
2293 | FAT32 stores the root directory in the Data Region along with files and other directories, |
||
2294 | allowing it to grow without such a restraint */ |
||
2295 | if((ccls == FatRootDirClusterValue) && ((sector + offset2) >= dsk->data) && (FAT32 != dsk->type)) |
||
2296 | { |
||
2297 | dir = ((DIRENTRY)NULL); // reached the end of the root |
||
2298 | } |
||
2299 | else |
||
2300 | { |
||
2301 | #ifdef ALLOW_WRITES |
||
2302 | if (gNeedDataWrite) |
||
2303 | if (flushData()) |
||
2304 | return NULL; |
||
2305 | #endif |
||
2306 | gBufferOwner = NULL; |
||
2307 | gBufferZeroed = FALSE; |
||
2308 | |||
2309 | if ( MDD_SectorRead( sector + offset2, dsk->buffer) != TRUE) // if FALSE: sector could not be read. |
||
2310 | { |
||
2311 | dir = ((DIRENTRY)NULL); |
||
2312 | } |
||
2313 | else // Sector has been read properly, Copy the root entry info of the file searched. |
||
2314 | { |
||
2315 | if(ForceRead) // Buffer holds all 16 root entry info. Point to the one required. |
||
2316 | dir = (DIRENTRY)((DIRENTRY)dsk->buffer) + ((*curEntry)%DIRENTRIES_PER_SECTOR); |
||
2317 | else |
||
2318 | dir = (DIRENTRY)dsk->buffer; |
||
2319 | } |
||
2320 | gLastDataSectorRead = 0xFFFFFFFF; |
||
2321 | } |
||
2322 | } |
||
2323 | else |
||
2324 | { |
||
2325 | nextClusterIsLast = TRUE; |
||
2326 | dir = ((DIRENTRY)NULL); |
||
2327 | } |
||
2328 | } |
||
2329 | else |
||
2330 | dir = (DIRENTRY)((DIRENTRY)dsk->buffer) + ((*curEntry)%DIRENTRIES_PER_SECTOR); |
||
2331 | |||
2332 | return(dir); |
||
2333 | } // Cache_File_Entry |
||
2334 | |||
2335 | |||
2336 | /************************************************************************* |
||
2337 | Function: |
||
2338 | CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle) |
||
2339 | Summary: |
||
2340 | Create a new file entry |
||
2341 | Conditions: |
||
2342 | Should not be called by the user. |
||
2343 | Input: |
||
2344 | fo - Pointer to file structure |
||
2345 | fHandle - Location to create file |
||
2346 | Return Values: |
||
2347 | CE_GOOD - File Creation successful |
||
2348 | CE_DIR_FULL - All root directory entries are taken |
||
2349 | CE_WRITE_ERROR - The head cluster of the file could not be created. |
||
2350 | Side Effects: |
||
2351 | Modifies the FSerrno variable. |
||
2352 | Description: |
||
2353 | With the data passed within fo, create a new file entry in the current |
||
2354 | directory. This function will first search for empty file entries. |
||
2355 | Once an empty entry is found, the entry will be populated with data |
||
2356 | for a file or directory entry. Finally, the first cluster of the |
||
2357 | new file will be located and allocated, and its value will be |
||
2358 | written into the file entry. |
||
2359 | Remarks: |
||
2360 | None |
||
2361 | *************************************************************************/ |
||
2362 | |||
2363 | #ifdef ALLOW_WRITES |
||
2364 | CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode) |
||
2365 | { |
||
2366 | BYTE index; |
||
2367 | CETYPE error = CE_GOOD; |
||
2368 | char name[11]; |
||
2369 | |||
2370 | FSerrno = CE_GOOD; |
||
2371 | |||
2372 | for (index = 0; index < FILE_NAME_SIZE; index ++) |
||
2373 | { |
||
2374 | name[index] = fo->name[index]; |
||
2375 | } |
||
2376 | |||
2377 | *fHandle = 0; |
||
2378 | |||
2379 | // figure out where to put this file in the directory stucture |
||
2380 | if(FindEmptyEntries(fo, fHandle)) |
||
2381 | { |
||
2382 | // found the entry, now populate it |
||
2383 | if((error = PopulateEntries(fo, name ,fHandle, mode)) == CE_GOOD) |
||
2384 | { |
||
2385 | // if everything is ok, create a first cluster |
||
2386 | error = CreateFirstCluster(fo); |
||
2387 | } |
||
2388 | } |
||
2389 | else |
||
2390 | { |
||
2391 | error = CE_DIR_FULL; |
||
2392 | } |
||
2393 | |||
2394 | FSerrno = error; |
||
2395 | |||
2396 | return(error); |
||
2397 | } |
||
2398 | #endif |
||
2399 | |||
2400 | /****************************************************** |
||
2401 | Function: |
||
2402 | CETYPE CreateFirstCluster(FILEOBJ fo) |
||
2403 | Summary: |
||
2404 | Create the first cluster for a file |
||
2405 | Conditions: |
||
2406 | This function should not be called by the user. |
||
2407 | Input: |
||
2408 | fo - The file that contains the first cluster |
||
2409 | Return Values: |
||
2410 | CE_GOOD - First cluster created successfully |
||
2411 | CE_WRITE_ERROR - Cluster creation failed |
||
2412 | Side Effects: |
||
2413 | None |
||
2414 | Description: |
||
2415 | This function will find an unused cluster, link it to |
||
2416 | a file's directory entry, and write the entry back |
||
2417 | to the device. |
||
2418 | Remarks: |
||
2419 | None. |
||
2420 | ******************************************************/ |
||
2421 | |||
2422 | #ifdef ALLOW_WRITES |
||
2423 | CETYPE CreateFirstCluster(FILEOBJ fo) |
||
2424 | { |
||
2425 | CETYPE error; |
||
2426 | DWORD cluster,TempMsbCluster; |
||
2427 | WORD fHandle; |
||
2428 | DIRENTRY dir; |
||
2429 | fHandle = fo->entry; |
||
2430 | |||
2431 | // Now create the first cluster (head cluster) |
||
2432 | if((error = FILECreateHeadCluster(fo,&cluster)) == CE_GOOD) |
||
2433 | { |
||
2434 | // load the file entry so the new cluster can be linked to it |
||
2435 | dir = LoadDirAttrib(fo, &fHandle); |
||
2436 | |||
2437 | // Now update the new cluster |
||
2438 | dir->DIR_FstClusLO = (cluster & 0x0000FFFF); |
||
2439 | |||
2440 | |||
2441 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2442 | // Get the higher part of cluster and store it in directory entry. |
||
2443 | TempMsbCluster = (cluster & 0x0FFF0000); // Since only 28 bits usedin FAT32. Mask the higher MSB nibble. |
||
2444 | TempMsbCluster = TempMsbCluster >> 16; // Get the date into Lsb place. |
||
2445 | dir->DIR_FstClusHI = TempMsbCluster; |
||
2446 | #else // If FAT32 support not enabled |
||
2447 | TempMsbCluster = 0; // Just to avoid compiler warnigng. |
||
2448 | dir->DIR_FstClusHI = 0; |
||
2449 | #endif |
||
2450 | |||
2451 | // now write it |
||
2452 | if(Write_File_Entry(fo, &fHandle) != TRUE) |
||
2453 | error = CE_WRITE_ERROR; |
||
2454 | } // Create Cluster |
||
2455 | |||
2456 | return(error); |
||
2457 | }// End of CreateFirstCluster |
||
2458 | #endif |
||
2459 | |||
2460 | /********************************************************** |
||
2461 | Function: |
||
2462 | BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle) |
||
2463 | Summary: |
||
2464 | Find an empty dir entry |
||
2465 | Conditions: |
||
2466 | This function should not be called by the user. |
||
2467 | Input: |
||
2468 | fo - Pointer to file structure |
||
2469 | fHandle - Start of entries |
||
2470 | Return Values: |
||
2471 | TRUE - One found |
||
2472 | FALSE - None found |
||
2473 | Side Effects: |
||
2474 | None |
||
2475 | Description: |
||
2476 | This function will cache directory entries, starting |
||
2477 | with the one pointed to by the fHandle argument. It will |
||
2478 | then search through the entries until an unused one |
||
2479 | is found. If the end of the cluster chain for the |
||
2480 | directory is reached, a new cluster will be allocated |
||
2481 | to the directory (unless it's a FAT12 or FAT16 root) |
||
2482 | and the first entry of the new cluster will be used. |
||
2483 | Remarks: |
||
2484 | None. |
||
2485 | **********************************************************/ |
||
2486 | |||
2487 | #ifdef ALLOW_WRITES |
||
2488 | BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle) |
||
2489 | { |
||
2490 | BYTE status = NOT_FOUND; |
||
2491 | BYTE amountfound; |
||
2492 | BYTE a; |
||
2493 | WORD bHandle; |
||
2494 | DWORD b; |
||
2495 | DIRENTRY dir; |
||
2496 | |||
2497 | fo->dirccls = fo->dirclus; |
||
2498 | if((dir = Cache_File_Entry( fo, fHandle, TRUE)) == NULL) |
||
2499 | { |
||
2500 | status = CE_BADCACHEREAD; |
||
2501 | } |
||
2502 | else |
||
2503 | { |
||
2504 | // while its still not found |
||
2505 | while(status == NOT_FOUND) |
||
2506 | { |
||
2507 | amountfound = 0; |
||
2508 | bHandle = *fHandle; |
||
2509 | |||
2510 | // find (number) continuous entries |
||
2511 | do |
||
2512 | { |
||
2513 | // Get the entry |
||
2514 | dir = Cache_File_Entry( fo, fHandle, FALSE); |
||
2515 | |||
2516 | // Read the first char of the file name |
||
2517 | if(dir != NULL) // Last entry of the cluster |
||
2518 | { |
||
2519 | a = dir->DIR_Name[0]; |
||
2520 | } |
||
2521 | // increase number |
||
2522 | (*fHandle)++; |
||
2523 | }while((a == DIR_DEL || a == DIR_EMPTY) && (dir != (DIRENTRY)NULL) && (++amountfound < 1)); |
||
2524 | |||
2525 | // --- now why did we exit? |
||
2526 | if(dir == NULL) // Last entry of the cluster |
||
2527 | { |
||
2528 | //setup the current cluster |
||
2529 | b = fo->dirccls; // write it back |
||
2530 | |||
2531 | // make sure we are not the root directory |
||
2532 | if(b == FatRootDirClusterValue) |
||
2533 | { |
||
2534 | if (fo->dsk->type != FAT32) |
||
2535 | status = NO_MORE; |
||
2536 | else |
||
2537 | { |
||
2538 | fo->ccls = b; |
||
2539 | |||
2540 | if(FILEallocate_new_cluster(fo, 1) == CE_DISK_FULL) |
||
2541 | status = NO_MORE; |
||
2542 | else |
||
2543 | { |
||
2544 | *fHandle = bHandle; |
||
2545 | status = FOUND; // a new cluster will surely hold a new file name |
||
2546 | } |
||
2547 | } |
||
2548 | } |
||
2549 | else |
||
2550 | { |
||
2551 | fo->ccls = b; |
||
2552 | |||
2553 | if(FILEallocate_new_cluster(fo, 1) == CE_DISK_FULL) |
||
2554 | status = NO_MORE; |
||
2555 | else |
||
2556 | { |
||
2557 | *fHandle = bHandle; |
||
2558 | status = FOUND; // a new cluster will surely hold a new file name |
||
2559 | } |
||
2560 | } |
||
2561 | } |
||
2562 | else |
||
2563 | { |
||
2564 | if(amountfound == 1) |
||
2565 | { |
||
2566 | status = FOUND; |
||
2567 | *fHandle = bHandle; |
||
2568 | } |
||
2569 | } |
||
2570 | }// while |
||
2571 | |||
2572 | // copy the base handle over |
||
2573 | *fHandle = bHandle; |
||
2574 | } |
||
2575 | |||
2576 | if(status == FOUND) |
||
2577 | return(TRUE); |
||
2578 | else |
||
2579 | return(FALSE); |
||
2580 | } |
||
2581 | #endif |
||
2582 | |||
2583 | /************************************************************************** |
||
2584 | Function: |
||
2585 | BYTE PopulateEntries(FILEOBJ fo, char *name , WORD *fHandle) |
||
2586 | Summary: |
||
2587 | Populate a dir entry with data |
||
2588 | Conditions: |
||
2589 | Should not be called by the user. |
||
2590 | Input: |
||
2591 | fo - Pointer to file structure |
||
2592 | name - Name of the file |
||
2593 | fHandle - Location of the file |
||
2594 | Return Values: |
||
2595 | CE_GOOD - Population successful |
||
2596 | Side Effects: |
||
2597 | None |
||
2598 | Description: |
||
2599 | This function will write data into a new file entry. It will also |
||
2600 | load timestamp data (based on the method selected by the user) and |
||
2601 | update the timestamp variables. |
||
2602 | Remarks: |
||
2603 | None. |
||
2604 | **************************************************************************/ |
||
2605 | |||
2606 | #ifdef ALLOW_WRITES |
||
2607 | BYTE PopulateEntries(FILEOBJ fo, char *name , WORD *fHandle, BYTE mode) |
||
2608 | { |
||
2609 | BYTE error = CE_GOOD; |
||
2610 | DIRENTRY dir; |
||
2611 | |||
2612 | fo->dirccls = fo->dirclus; |
||
2613 | dir = Cache_File_Entry( fo, fHandle, TRUE); |
||
2614 | |||
2615 | if (dir == NULL) |
||
2616 | return CE_BADCACHEREAD; |
||
2617 | |||
2618 | // copy the contents over |
||
2619 | strncpy(dir->DIR_Name,name,DIR_NAMECOMP); |
||
2620 | |||
2621 | // setup no attributes |
||
2622 | if (mode == DIRECTORY) |
||
2623 | dir->DIR_Attr = ATTR_DIRECTORY; |
||
2624 | else |
||
2625 | dir->DIR_Attr = ATTR_ARCHIVE; |
||
2626 | |||
2627 | dir->DIR_NTRes = 0x00; // nt reserved |
||
2628 | dir->DIR_FstClusHI = 0x0000; // high word of this enty's first cluster number |
||
2629 | dir->DIR_FstClusLO = 0x0000; // low word of this entry's first cluster number |
||
2630 | dir->DIR_FileSize = 0x0; // file size in DWORD |
||
2631 | |||
2632 | // Timing information for uncontrolled clock mode |
||
2633 | #ifdef INCREMENTTIMESTAMP |
||
2634 | dir->DIR_CrtTimeTenth = 0xB2; // millisecond stamp |
||
2635 | dir->DIR_CrtTime = 0x7278; // time created |
||
2636 | dir->DIR_CrtDate = 0x32B0; // date created |
||
2637 | dir->DIR_LstAccDate = 0x32B0; // Last Access date |
||
2638 | dir->DIR_WrtTime = 0x7279; // last update time |
||
2639 | dir->DIR_WrtDate = 0x32B0; // last update date |
||
2640 | #endif |
||
2641 | |||
2642 | #ifdef USEREALTIMECLOCK |
||
2643 | CacheTime(); |
||
2644 | dir->DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp |
||
2645 | dir->DIR_CrtTime = gTimeCrtTime; // time created // |
||
2646 | dir->DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004) |
||
2647 | dir->DIR_LstAccDate = gTimeAccDate; // Last Access date |
||
2648 | dir->DIR_WrtTime = gTimeWrtTime; // last update time |
||
2649 | dir->DIR_WrtDate = gTimeWrtDate; // last update date |
||
2650 | #endif |
||
2651 | |||
2652 | #ifdef USERDEFINEDCLOCK |
||
2653 | // The user will have set the time before this funciton is called |
||
2654 | dir->DIR_CrtTimeTenth = gTimeCrtMS; |
||
2655 | dir->DIR_CrtTime = gTimeCrtTime; |
||
2656 | dir->DIR_CrtDate = gTimeCrtDate; |
||
2657 | dir->DIR_LstAccDate = gTimeAccDate; |
||
2658 | dir->DIR_WrtTime = gTimeWrtTime; |
||
2659 | dir->DIR_WrtDate = gTimeWrtDate; |
||
2660 | #endif |
||
2661 | |||
2662 | fo->size = dir->DIR_FileSize; |
||
2663 | fo->time = dir->DIR_CrtTime; |
||
2664 | fo->date = dir->DIR_CrtDate; |
||
2665 | fo->attributes = dir->DIR_Attr; |
||
2666 | fo->entry = *fHandle; |
||
2667 | |||
2668 | // just write the last entry in |
||
2669 | if (Write_File_Entry(fo,fHandle) != TRUE) |
||
2670 | error = CE_WRITE_ERROR; |
||
2671 | |||
2672 | return(error); |
||
2673 | } |
||
2674 | |||
2675 | #ifdef USEREALTIMECLOCK |
||
2676 | |||
2677 | /************************************************************************* |
||
2678 | Function: |
||
2679 | void CacheTime (void) |
||
2680 | Summary: |
||
2681 | Automatically store timestamp information from the RTCC |
||
2682 | Conditions: |
||
2683 | RTCC module enabled. Should not be called by the user. |
||
2684 | Return Values: |
||
2685 | None |
||
2686 | Side Effects: |
||
2687 | Modifies global timing variables |
||
2688 | Description: |
||
2689 | This function will automatically load information from an RTCC |
||
2690 | module and use it to update the global timing variables. These can |
||
2691 | then be used to update file timestamps. |
||
2692 | Remarks: |
||
2693 | None. |
||
2694 | *************************************************************************/ |
||
2695 | |||
2696 | void CacheTime (void) |
||
2697 | { |
||
2698 | WORD year, monthday, weekhour, minsec, c, result; |
||
2699 | BYTE ptr1, ptr0; |
||
2700 | |||
2701 | #if defined (__PIC32MX__) // Added support for PIC32. -Bud (3/4/2008) |
||
2702 | |||
2703 | unsigned int t0, t1; |
||
2704 | unsigned int d0, d1; |
||
2705 | |||
2706 | do // Get the time |
||
2707 | { |
||
2708 | t0=RTCTIME; |
||
2709 | t1=RTCTIME; |
||
2710 | }while(t0!=t1); |
||
2711 | |||
2712 | do // Get the date |
||
2713 | { |
||
2714 | d0=RTCDATE; |
||
2715 | d1=RTCDATE; |
||
2716 | }while(d0!=d1); |
||
2717 | |||
2718 | // Put them in place. |
||
2719 | year = (WORD)(d0 >> 24); |
||
2720 | monthday = (WORD)(d0 >> 8); |
||
2721 | weekhour = (WORD)((d0 & 0x0F) << 8); |
||
2722 | weekhour |= (WORD)(t0 >> 24); |
||
2723 | minsec = (WORD)(t0 >> 8); |
||
2724 | |||
2725 | #else |
||
2726 | |||
2727 | if(RCFGCALbits.RTCPTR0) |
||
2728 | ptr0 = 1; |
||
2729 | else |
||
2730 | ptr0 = 0; |
||
2731 | if (RCFGCALbits.RTCPTR1) |
||
2732 | ptr1 = 1; |
||
2733 | else |
||
2734 | ptr1 = 0; |
||
2735 | |||
2736 | RCFGCALbits.RTCPTR0 = 1; |
||
2737 | RCFGCALbits.RTCPTR1 = 1; |
||
2738 | year = RTCVAL; |
||
2739 | monthday = RTCVAL; |
||
2740 | weekhour = RTCVAL; |
||
2741 | minsec = RTCVAL; |
||
2742 | |||
2743 | if (ptr0 == 1) |
||
2744 | RCFGCALbits.RTCPTR0 = 1; |
||
2745 | |||
2746 | if (ptr1 == 1) |
||
2747 | RCFGCALbits.RTCPTR1 = 1; |
||
2748 | |||
2749 | #endif |
||
2750 | |||
2751 | c = 0; |
||
2752 | c += (year & 0x0F); |
||
2753 | c += ((year & 0xF0) >> 4) * 10; |
||
2754 | // c equals the last 2 digits of the year from 2000 to 2099 |
||
2755 | // Add 20 to adjust it to FAT time (from 1980 to 2107) |
||
2756 | c += 20; |
||
2757 | // shift the result to bits |
||
2758 | result = c << 9; |
||
2759 | |||
2760 | if ((monthday & 0x1000) == 0x1000) |
||
2761 | { |
||
2762 | c = 10; |
||
2763 | } |
||
2764 | else |
||
2765 | { |
||
2766 | c = 0; |
||
2767 | } |
||
2768 | c += ((monthday & 0x0F00) >> 8); |
||
2769 | c <<= 5; |
||
2770 | result |= c; |
||
2771 | |||
2772 | c = (monthday & 0x00F0) >> 4; |
||
2773 | c *= 10; |
||
2774 | c += (monthday & 0x000F); |
||
2775 | |||
2776 | result |= c; |
||
2777 | |||
2778 | gTimeCrtDate = result; |
||
2779 | gTimeWrtDate = result; |
||
2780 | gTimeAccDate = result; |
||
2781 | |||
2782 | c = ((weekhour & 0x00F0) >> 4) * 10; |
||
2783 | c += (weekhour & 0x000F); |
||
2784 | result = c << 11; |
||
2785 | c = ((minsec & 0xF000) >> 12) * 10; |
||
2786 | c += (minsec & 0x0F00) >> 8; |
||
2787 | result |= (c << 5); |
||
2788 | c = ((minsec & 0x00F0) >> 4) * 10; |
||
2789 | c += (minsec & 0x000F); |
||
2790 | |||
2791 | // If seconds mod 2 is 1, add 1000 ms |
||
2792 | if (c % 2) |
||
2793 | gTimeCrtMS = 100; |
||
2794 | else |
||
2795 | gTimeCrtMS = 0; |
||
2796 | |||
2797 | c >>= 1; |
||
2798 | result |= c; |
||
2799 | |||
2800 | gTimeCrtTime = result; |
||
2801 | gTimeWrtTime = result; |
||
2802 | } |
||
2803 | #endif |
||
2804 | |||
2805 | #ifdef USERDEFINEDCLOCK |
||
2806 | |||
2807 | /*********************************************************************************************************** |
||
2808 | Function: |
||
2809 | int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second) |
||
2810 | Summary: |
||
2811 | Manually set timestamp variables |
||
2812 | Conditions: |
||
2813 | USERDEFINEDCLOCK macro defined in FSconfig.h. |
||
2814 | Input: |
||
2815 | year - The year (1980\-2107) |
||
2816 | month - The month (1\-12) |
||
2817 | day - The day of the month (1\-31) |
||
2818 | hour - The hour (0\-23) |
||
2819 | minute - The minute (0\-59) |
||
2820 | second - The second (0\-59) |
||
2821 | Return Values: |
||
2822 | None |
||
2823 | Side Effects: |
||
2824 | Modifies global timing variables |
||
2825 | Description: |
||
2826 | Lets the user manually set the timing variables. The values passed in will be converted to the format |
||
2827 | used by the FAT timestamps. |
||
2828 | Remarks: |
||
2829 | Call this before creating a file or directory (set create time) and |
||
2830 | before closing a file (set last access time, last modified time) |
||
2831 | ***********************************************************************************************************/ |
||
2832 | |||
2833 | int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second) |
||
2834 | { |
||
2835 | unsigned int result; |
||
2836 | |||
2837 | if ((year < 1980) || (year > 2107) || (month < 1) || (month > 12) || |
||
2838 | (day < 1) || (day > 31) || (hour > 23) || (minute > 59) || (second > 59)) |
||
2839 | { |
||
2840 | FSerrno = CE_INVALID_ARGUMENT; |
||
2841 | return -1; |
||
2842 | } |
||
2843 | |||
2844 | result = (year - 1980) << 9; |
||
2845 | result |= (unsigned int)((unsigned int)month << 5); |
||
2846 | result |= (day); |
||
2847 | |||
2848 | gTimeAccDate = result; |
||
2849 | gTimeCrtDate = result; |
||
2850 | gTimeWrtDate = result; |
||
2851 | |||
2852 | result = ((unsigned int)hour << 11); |
||
2853 | result |= (unsigned int)((unsigned int)minute << 5); |
||
2854 | result |= (second/2); |
||
2855 | |||
2856 | gTimeCrtTime = result; |
||
2857 | gTimeWrtTime = result; |
||
2858 | |||
2859 | if (second % 2) |
||
2860 | gTimeCrtMS = 100; |
||
2861 | else |
||
2862 | gTimeCrtMS = 0; |
||
2863 | |||
2864 | FSerrno = CE_GOOD; |
||
2865 | return 0; |
||
2866 | } |
||
2867 | #endif |
||
2868 | |||
2869 | #endif |
||
2870 | |||
2871 | /*********************************************************************** |
||
2872 | Function: |
||
2873 | BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode) |
||
2874 | Summary; |
||
2875 | Allocate a new cluster to a file |
||
2876 | Conditions: |
||
2877 | Should not be called by the user. |
||
2878 | Input: |
||
2879 | fo - Pointer to file structure |
||
2880 | mode - |
||
2881 | - 0 - Allocate a cluster to a file |
||
2882 | - 1 - Allocate a cluster to a directory |
||
2883 | Return Values: |
||
2884 | CE_GOOD - Cluster allocated |
||
2885 | CE_DISK_FULL - No clusters available |
||
2886 | Side Effects: |
||
2887 | None |
||
2888 | Description: |
||
2889 | This function will find an empty cluster on the device using the |
||
2890 | FATfindEmptyCluster function. It will then mark it as the last |
||
2891 | cluster in the file in the FAT chain, and link the current last |
||
2892 | cluster of the passed file to the new cluster. If the new |
||
2893 | cluster is a directory cluster, it will be erased (so there are no |
||
2894 | extraneous directory entries). If it's allocated to a non-directory |
||
2895 | file, it doesn't need to be erased; extraneous data in the cluster |
||
2896 | will be unviewable because of the file size parameter. |
||
2897 | Remarks: |
||
2898 | None. |
||
2899 | ***********************************************************************/ |
||
2900 | |||
2901 | #ifdef ALLOW_WRITES |
||
2902 | BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode) |
||
2903 | { |
||
2904 | DISK * dsk; |
||
2905 | DWORD c,curcls; |
||
2906 | |||
2907 | dsk = fo->dsk; |
||
2908 | c = fo->ccls; |
||
2909 | |||
2910 | // find the next empty cluster |
||
2911 | c = FATfindEmptyCluster(fo); |
||
2912 | if (c == 0) // "0" is just an indication as Disk full in the fn "FATfindEmptyCluster()" |
||
2913 | return CE_DISK_FULL; |
||
2914 | |||
2915 | |||
2916 | // mark the cluster as taken, and last in chain |
||
2917 | if(dsk->type == FAT12) |
||
2918 | WriteFAT( dsk, c, LAST_CLUSTER_FAT12, FALSE); |
||
2919 | else if (dsk->type == FAT16) |
||
2920 | WriteFAT( dsk, c, LAST_CLUSTER_FAT16, FALSE); |
||
2921 | |||
2922 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2923 | else |
||
2924 | WriteFAT( dsk, c, LAST_CLUSTER_FAT32, FALSE); |
||
2925 | #endif |
||
2926 | |||
2927 | // link current cluster to the new one |
||
2928 | curcls = fo->ccls; |
||
2929 | |||
2930 | WriteFAT( dsk, curcls, c, FALSE); |
||
2931 | |||
2932 | // update the FILE structure |
||
2933 | fo->ccls = c; |
||
2934 | |||
2935 | // IF this is a dir, we need to erase the cluster |
||
2936 | // If it's a file, we can leave it- the file size |
||
2937 | // will limit the data we see to the data that's been |
||
2938 | // written |
||
2939 | if (mode == 1) |
||
2940 | return (EraseCluster(dsk, c)); |
||
2941 | else |
||
2942 | return CE_GOOD; |
||
2943 | |||
2944 | } // allocate new cluster |
||
2945 | #endif |
||
2946 | |||
2947 | /*********************************************** |
||
2948 | Function: |
||
2949 | DWORD FATfindEmptyCluster(FILEOBJ fo) |
||
2950 | Summary: |
||
2951 | Find the next available cluster on the device |
||
2952 | Conditions: |
||
2953 | This function should not be called by the |
||
2954 | user. |
||
2955 | Input: |
||
2956 | fo - Pointer to file structure |
||
2957 | Return Values: |
||
2958 | DWORD - Address of empty cluster |
||
2959 | |||
2960 | Side Effects: |
||
2961 | None |
||
2962 | Description: |
||
2963 | This function will search through the FAT to |
||
2964 | find the next available cluster on the device. |
||
2965 | Remarks: |
||
2966 | Should not be called by user |
||
2967 | ***********************************************/ |
||
2968 | |||
2969 | #ifdef ALLOW_WRITES |
||
2970 | DWORD FATfindEmptyCluster(FILEOBJ fo) |
||
2971 | { |
||
2972 | DISK * disk; |
||
2973 | DWORD value = 0x0; |
||
2974 | DWORD c,curcls, EndClusterLimit, ClusterFailValue; |
||
2975 | |||
2976 | disk = fo->dsk; |
||
2977 | c = fo->ccls; |
||
2978 | |||
2979 | /* Settings based on FAT type */ |
||
2980 | switch (disk->type) |
||
2981 | { |
||
2982 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
2983 | case FAT32: |
||
2984 | EndClusterLimit = END_CLUSTER_FAT32; |
||
2985 | ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
2986 | break; |
||
2987 | #endif |
||
2988 | case FAT12: |
||
2989 | EndClusterLimit = END_CLUSTER_FAT12; |
||
2990 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
2991 | break; |
||
2992 | case FAT16: |
||
2993 | default: |
||
2994 | EndClusterLimit = END_CLUSTER_FAT16; |
||
2995 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
2996 | break; |
||
2997 | } |
||
2998 | |||
2999 | // just in case |
||
3000 | if(c < 2) |
||
3001 | c = 2; |
||
3002 | |||
3003 | curcls = c; |
||
3004 | ReadFAT(disk, c); |
||
3005 | |||
3006 | // sequentially scan through the FAT looking for an empty cluster |
||
3007 | while(c) |
||
3008 | { |
||
3009 | // look at its value |
||
3010 | if ( (value = ReadFAT(disk, c)) == ClusterFailValue) |
||
3011 | { |
||
3012 | c = 0; |
||
3013 | break; |
||
3014 | } |
||
3015 | |||
3016 | // check if empty cluster found |
||
3017 | if (value == CLUSTER_EMPTY) |
||
3018 | break; |
||
3019 | |||
3020 | c++; // check next cluster in FAT |
||
3021 | // check if reached last cluster in FAT, re-start from top |
||
3022 | if (value == EndClusterLimit || c >= (disk->maxcls+2)) |
||
3023 | c = 2; |
||
3024 | |||
3025 | // check if full circle done, disk full |
||
3026 | if ( c == curcls) |
||
3027 | { |
||
3028 | c = 0; |
||
3029 | break; |
||
3030 | } |
||
3031 | } // scanning for an empty cluster |
||
3032 | |||
3033 | return(c); |
||
3034 | } |
||
3035 | #endif |
||
3036 | |||
3037 | |||
3038 | /********************************************************************************* |
||
3039 | Function: |
||
3040 | void FSGetDiskProperties(FS_DISK_PROPERTIES* properties) |
||
3041 | Summary: |
||
3042 | Allows user to get the disk properties (size of disk, free space, etc) |
||
3043 | Conditions: |
||
3044 | 1) ALLOW_GET_DISK_PROPERTIES must be defined in FSconfig.h |
||
3045 | 2) a FS_DISK_PROPERTIES object must be created before the function is called |
||
3046 | 3) the new_request member of the FS_DISK_PROPERTIES object must be set before |
||
3047 | calling the function for the first time. This will start a new search. |
||
3048 | 4) this function should not be called while there is a file open. Close all |
||
3049 | files before calling this function. |
||
3050 | Input: |
||
3051 | properties - a pointer to a FS_DISK_PROPERTIES object where the results should |
||
3052 | be stored. |
||
3053 | Return Values: |
||
3054 | This function returns void. The properties_status of the previous call of this |
||
3055 | function is located in the properties.status field. This field has the |
||
3056 | following possible values: |
||
3057 | |||
3058 | FS_GET_PROPERTIES_NO_ERRORS - operation completed without error. Results |
||
3059 | are in the properties object passed into the function. |
||
3060 | FS_GET_PROPERTIES_DISK_NOT_MOUNTED - there is no mounted disk. Results in |
||
3061 | properties object is not valid |
||
3062 | FS_GET_PROPERTIES_CLUSTER_FAILURE - there was a failure trying to read a |
||
3063 | cluster from the drive. The results in the properties object is a partial |
||
3064 | result up until the point of the failure. |
||
3065 | FS_GET_PROPERTIES_STILL_WORKING - the search for free sectors is still in |
||
3066 | process. Continue calling this function with the same properties pointer |
||
3067 | until either the function completes or until the partial results meets the |
||
3068 | application needs. The properties object contains the partial results of |
||
3069 | the search and can be used by the application. |
||
3070 | Side Effects: |
||
3071 | Can cause errors if called when files are open. Close all files before |
||
3072 | calling this function. |
||
3073 | |||
3074 | Calling this function without setting the new_request member on the first |
||
3075 | call can result in undefined behavior and results. |
||
3076 | |||
3077 | Calling this function after a result is returned other than |
||
3078 | FS_GET_PROPERTIES_STILL_WORKING can result in undefined behavior and results. |
||
3079 | Description: |
||
3080 | This function returns the information about the mounted drive. The results |
||
3081 | member of the properties object passed into the function is populated with |
||
3082 | the information about the drive. |
||
3083 | |||
3084 | Before starting a new request, the new_request member of the properties |
||
3085 | input parameter should be set to TRUE. This will initiate a new search |
||
3086 | request. |
||
3087 | |||
3088 | This function will return before the search is complete with partial results. |
||
3089 | All of the results except the free_clusters will be correct after the first |
||
3090 | call. The free_clusters will contain the number of free clusters found up |
||
3091 | until that point, thus the free_clusters result will continue to grow until |
||
3092 | the entire drive is searched. If an application only needs to know that a |
||
3093 | certain number of bytes is available and doesn't need to know the total free |
||
3094 | size, then this function can be called until the required free size is |
||
3095 | verified. To continue a search, pass a pointer to the same FS_DISK_PROPERTIES |
||
3096 | object that was passed in to create the search. |
||
3097 | |||
3098 | A new search request sould be made once this function has returned a value |
||
3099 | other than FS_GET_PROPERTIES_STILL_WORKING. Continuing a completed search |
||
3100 | can result in undefined behavior or results. |
||
3101 | |||
3102 | Typical Usage: |
||
3103 | <code> |
||
3104 | FS_DISK_PROPERTIES disk_properties; |
||
3105 | |||
3106 | disk_properties.new_request = TRUE; |
||
3107 | |||
3108 | do |
||
3109 | { |
||
3110 | FSGetDiskProperties(&disk_properties); |
||
3111 | } while (disk_properties.properties_status == FS_GET_PROPERTIES_STILL_WORKING); |
||
3112 | </code> |
||
3113 | |||
3114 | results.disk_format - contains the format of the drive. Valid results are |
||
3115 | FAT12(1), FAT16(2), or FAT32(3). |
||
3116 | |||
3117 | results.sector_size - the sector size of the mounted drive. Valid values are |
||
3118 | 512, 1024, 2048, and 4096. |
||
3119 | |||
3120 | results.sectors_per_cluster - the number sectors per cluster. |
||
3121 | |||
3122 | results.total_clusters - the number of total clusters on the drive. This |
||
3123 | can be used to calculate the total disk size (total_clusters * |
||
3124 | sectors_per_cluster * sector_size = total size of drive in bytes) |
||
3125 | |||
3126 | results.free_clusters - the number of free (unallocated) clusters on the drive. |
||
3127 | This can be used to calculate the total free disk size (free_clusters * |
||
3128 | sectors_per_cluster * sector_size = total size of drive in bytes) |
||
3129 | |||
3130 | Remarks: |
||
3131 | PIC24F size estimates: |
||
3132 | Flash - 400 bytes (-Os setting) |
||
3133 | |||
3134 | PIC24F speed estimates: |
||
3135 | Search takes approximately 7 seconds per Gigabyte of drive space. Speed |
||
3136 | will vary based on the number of sectors per cluster and the sector size. |
||
3137 | *********************************************************************************/ |
||
3138 | #if defined(ALLOW_GET_DISK_PROPERTIES) |
||
3139 | void FSGetDiskProperties(FS_DISK_PROPERTIES* properties) |
||
3140 | { |
||
3141 | BYTE i; |
||
3142 | DWORD value = 0x0; |
||
3143 | |||
3144 | if(properties->new_request == TRUE) |
||
3145 | { |
||
3146 | properties->disk = &gDiskData; |
||
3147 | properties->results.free_clusters = 0; |
||
3148 | properties->new_request = FALSE; |
||
3149 | |||
3150 | if(properties->disk->mount != TRUE) |
||
3151 | { |
||
3152 | properties->properties_status = FS_GET_PROPERTIES_DISK_NOT_MOUNTED; |
||
3153 | return; |
||
3154 | } |
||
3155 | |||
3156 | properties->properties_status = FS_GET_PROPERTIES_STILL_WORKING; |
||
3157 | |||
3158 | properties->results.disk_format = properties->disk->type; |
||
3159 | properties->results.sector_size = properties->disk->sectorSize; |
||
3160 | properties->results.sectors_per_cluster = properties->disk->SecPerClus; |
||
3161 | properties->results.total_clusters = properties->disk->maxcls; |
||
3162 | |||
3163 | /* Settings based on FAT type */ |
||
3164 | switch (properties->disk->type) |
||
3165 | { |
||
3166 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
3167 | case FAT32: |
||
3168 | properties->private.EndClusterLimit = END_CLUSTER_FAT32; |
||
3169 | properties->private.ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
3170 | break; |
||
3171 | #endif |
||
3172 | case FAT16: |
||
3173 | properties->private.EndClusterLimit = END_CLUSTER_FAT16; |
||
3174 | properties->private.ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
3175 | break; |
||
3176 | case FAT12: |
||
3177 | properties->private.EndClusterLimit = END_CLUSTER_FAT12; |
||
3178 | properties->private.ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
3179 | break; |
||
3180 | } |
||
3181 | |||
3182 | properties->private.c = 2; |
||
3183 | |||
3184 | properties->private.curcls = properties->private.c; |
||
3185 | ReadFAT(properties->disk, properties->private.c); |
||
3186 | } |
||
3187 | |||
3188 | if(properties->disk == NULL) |
||
3189 | { |
||
3190 | properties->properties_status = FS_GET_PROPERTIES_DISK_NOT_MOUNTED; |
||
3191 | return; |
||
3192 | } |
||
3193 | |||
3194 | if(properties->properties_status != FS_GET_PROPERTIES_STILL_WORKING) |
||
3195 | { |
||
3196 | return; |
||
3197 | } |
||
3198 | |||
3199 | // sequentially scan through the FAT looking for an empty cluster |
||
3200 | for(i=0;i<255;i++) |
||
3201 | { |
||
3202 | // look at its value |
||
3203 | if ( (value = ReadFAT(properties->disk, properties->private.c)) == properties->private.ClusterFailValue) |
||
3204 | { |
||
3205 | properties->properties_status = FS_GET_PROPERTIES_CLUSTER_FAILURE; |
||
3206 | return; |
||
3207 | } |
||
3208 | |||
3209 | // check if empty cluster found |
||
3210 | if (value == CLUSTER_EMPTY) |
||
3211 | { |
||
3212 | properties->results.free_clusters++; |
||
3213 | } |
||
3214 | |||
3215 | properties->private.c++; // check next cluster in FAT |
||
3216 | // check if reached last cluster in FAT, re-start from top |
||
3217 | if (value == properties->private.EndClusterLimit || properties->private.c >= (properties->results.total_clusters + 2)) |
||
3218 | properties->private.c = 2; |
||
3219 | |||
3220 | // check if full circle done, disk full |
||
3221 | if ( properties->private.c == properties->private.curcls) |
||
3222 | { |
||
3223 | properties->properties_status = FS_GET_PROPERTIES_NO_ERRORS; |
||
3224 | return; |
||
3225 | } |
||
3226 | } // scanning for an empty cluster |
||
3227 | |||
3228 | properties->properties_status = FS_GET_PROPERTIES_STILL_WORKING; |
||
3229 | return; |
||
3230 | } |
||
3231 | #endif |
||
3232 | |||
3233 | /************************************************************ |
||
3234 | Function: |
||
3235 | int FSfclose(FSFILE *fo) |
||
3236 | Summary: |
||
3237 | Update file information and free FSFILE objects |
||
3238 | Conditions: |
||
3239 | File opened |
||
3240 | Input: |
||
3241 | fo - Pointer to the file to close |
||
3242 | Return Values: |
||
3243 | |||
3244 | EOF - Error closing the file |
||
3245 | Side Effects: |
||
3246 | The FSerrno variable will be changed. |
||
3247 | Description: |
||
3248 | This function will update the directory entry for the |
||
3249 | file pointed to by 'fo' with the information contained |
||
3250 | in 'fo,' including the new file size and attributes. |
||
3251 | Timestamp information will also be loaded based on the |
||
3252 | method selected by the user and written to the entry |
||
3253 | as the last modified time and date. The file entry will |
||
3254 | then be written to the device. Finally, the memory |
||
3255 | used for the specified file object will be freed from |
||
3256 | the dynamic heap or the array of FSFILE objects. |
||
3257 | Remarks: |
||
3258 | A function to flush data to the device without closing the |
||
3259 | file can be created by removing the portion of this |
||
3260 | function that frees the memory and the line that clears |
||
3261 | the write flag. |
||
3262 | ************************************************************/ |
||
3263 | |||
3264 | int FSfclose(FSFILE *fo) |
||
3265 | { |
||
3266 | WORD fHandle; |
||
3267 | #ifndef FS_DYNAMIC_MEM |
||
3268 | WORD fIndex; |
||
3269 | #endif |
||
3270 | int error = 72; |
||
3271 | #ifdef ALLOW_WRITES |
||
3272 | DIRENTRY dir; |
||
3273 | #endif |
||
3274 | |||
3275 | FSerrno = CE_GOOD; |
||
3276 | fHandle = fo->entry; |
||
3277 | |||
3278 | #ifdef ALLOW_WRITES |
||
3279 | if(fo->flags.write) |
||
3280 | { |
||
3281 | if (gNeedDataWrite) |
||
3282 | if (flushData()) |
||
3283 | { |
||
3284 | FSerrno = CE_WRITE_ERROR; |
||
3285 | return EOF; |
||
3286 | } |
||
3287 | |||
3288 | // Write the current FAT sector to the disk |
||
3289 | WriteFAT (fo->dsk, 0, 0, TRUE); |
||
3290 | |||
3291 | // Get the file entry |
||
3292 | dir = LoadDirAttrib(fo, &fHandle); |
||
3293 | |||
3294 | if (dir == NULL) |
||
3295 | { |
||
3296 | FSerrno = CE_BADCACHEREAD; |
||
3297 | error = EOF; |
||
3298 | return error; |
||
3299 | } |
||
3300 | |||
3301 | // update the time |
||
3302 | #ifdef INCREMENTTIMESTAMP |
||
3303 | IncrementTimeStamp(dir); |
||
3304 | #elif defined USERDEFINEDCLOCK |
||
3305 | dir->DIR_WrtTime = gTimeWrtTime; |
||
3306 | dir->DIR_WrtDate = gTimeWrtDate; |
||
3307 | #elif defined USEREALTIMECLOCK |
||
3308 | CacheTime(); |
||
3309 | dir->DIR_WrtTime = gTimeWrtTime; |
||
3310 | dir->DIR_WrtDate = gTimeWrtDate; |
||
3311 | #endif |
||
3312 | |||
3313 | dir->DIR_FileSize = fo->size; |
||
3314 | |||
3315 | dir->DIR_Attr = fo->attributes; |
||
3316 | |||
3317 | // just write the last entry in |
||
3318 | if(Write_File_Entry(fo,&fHandle)) |
||
3319 | error = 0; |
||
3320 | else |
||
3321 | { |
||
3322 | FSerrno = CE_WRITE_ERROR; |
||
3323 | error = EOF; |
||
3324 | } |
||
3325 | |||
3326 | // it's now closed |
||
3327 | fo->flags.write = FALSE; |
||
3328 | } |
||
3329 | #endif |
||
3330 | |||
3331 | #ifdef FS_DYNAMIC_MEM |
||
3332 | FS_free((unsigned char *)fo); |
||
3333 | #else |
||
3334 | |||
3335 | for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ ) |
||
3336 | { |
||
3337 | if( fo == &gFileArray[fIndex] ) |
||
3338 | { |
||
3339 | gFileSlotOpen[fIndex] = TRUE; |
||
3340 | break; |
||
3341 | } |
||
3342 | } |
||
3343 | #endif |
||
3344 | |||
3345 | // File opened in read mode |
||
3346 | if (error == 72) |
||
3347 | error = 0; |
||
3348 | |||
3349 | return(error); |
||
3350 | } // FSfclose |
||
3351 | |||
3352 | |||
3353 | |||
3354 | |||
3355 | /******************************************************* |
||
3356 | Function: |
||
3357 | void IncrementTimeStamp(DIRENTRY dir) |
||
3358 | Summary: |
||
3359 | Automatically set the timestamp to "don't care" data |
||
3360 | Conditions: |
||
3361 | Should not be called by the user. |
||
3362 | Input: |
||
3363 | dir - Pointer to directory structure |
||
3364 | Return Values: |
||
3365 | None |
||
3366 | Side Effects: |
||
3367 | None |
||
3368 | Description: |
||
3369 | This function will increment the timestamp variable in |
||
3370 | the 'dir' directory entry. This is used for the |
||
3371 | don't-care timing method. |
||
3372 | Remarks: |
||
3373 | None |
||
3374 | *******************************************************/ |
||
3375 | #ifdef INCREMENTTIMESTAMP |
||
3376 | void IncrementTimeStamp(DIRENTRY dir) |
||
3377 | { |
||
3378 | BYTE seconds; |
||
3379 | BYTE minutes; |
||
3380 | BYTE hours; |
||
3381 | |||
3382 | BYTE day; |
||
3383 | BYTE month; |
||
3384 | BYTE year; |
||
3385 | |||
3386 | seconds = (dir->DIR_WrtTime & 0x1f); |
||
3387 | minutes = ((dir->DIR_WrtTime & 0x07E0) >> 5); |
||
3388 | hours = ((dir->DIR_WrtTime & 0xF800) >> 11); |
||
3389 | |||
3390 | day = (dir->DIR_WrtDate & 0x1f); |
||
3391 | month = ((dir->DIR_WrtDate & 0x01E0) >> 5); |
||
3392 | year = ((dir->DIR_WrtDate & 0xFE00) >> 9); |
||
3393 | |||
3394 | if(seconds < 29) |
||
3395 | { |
||
3396 | // Increment number of seconds by 2 |
||
3397 | // This clock method isn't intended to be accurate anyway |
||
3398 | seconds++; |
||
3399 | } |
||
3400 | else |
||
3401 | { |
||
3402 | seconds = 0x00; |
||
3403 | |||
3404 | if(minutes < 59) |
||
3405 | { |
||
3406 | minutes++; |
||
3407 | } |
||
3408 | else |
||
3409 | { |
||
3410 | minutes = 0; |
||
3411 | |||
3412 | if(hours < 23) |
||
3413 | { |
||
3414 | hours++; |
||
3415 | } |
||
3416 | else |
||
3417 | { |
||
3418 | hours = 0; |
||
3419 | if(day < 30) |
||
3420 | { |
||
3421 | day++; |
||
3422 | } |
||
3423 | else |
||
3424 | { |
||
3425 | day = 1; |
||
3426 | |||
3427 | if(month < 12) |
||
3428 | { |
||
3429 | month++; |
||
3430 | } |
||
3431 | else |
||
3432 | { |
||
3433 | month = 1; |
||
3434 | // new year |
||
3435 | year++; |
||
3436 | // This is only valid until 2107 |
||
3437 | } |
||
3438 | } |
||
3439 | } |
||
3440 | } |
||
3441 | } |
||
3442 | |||
3443 | dir->DIR_WrtTime = (WORD)(seconds); |
||
3444 | dir->DIR_WrtTime |= ((WORD)(minutes) << 5); |
||
3445 | dir->DIR_WrtTime |= ((WORD)(hours) << 11); |
||
3446 | |||
3447 | dir->DIR_WrtDate = (WORD)(day); |
||
3448 | dir->DIR_WrtDate |= ((WORD)(month) << 5); |
||
3449 | dir->DIR_WrtDate |= ((WORD)(year) << 9); |
||
3450 | } |
||
3451 | #endif |
||
3452 | |||
3453 | /***************************************************************** |
||
3454 | Function: |
||
3455 | BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle) |
||
3456 | Summary: |
||
3457 | Fill a file object with specified dir entry data |
||
3458 | Conditions: |
||
3459 | This function should not be called by the user. |
||
3460 | Input: |
||
3461 | fo - Pointer to file structure |
||
3462 | fHandle - Passed member's location |
||
3463 | Return Values: |
||
3464 | FOUND - Operation successful |
||
3465 | NOT_FOUND - Operation failed |
||
3466 | Side Effects: |
||
3467 | None |
||
3468 | Description: |
||
3469 | This function will cache the sector of directory entries |
||
3470 | in the directory pointed to by the dirclus value in |
||
3471 | the FSFILE object 'fo' that contains the entry that |
||
3472 | corresponds to the fHandle offset. It will then copy |
||
3473 | the file information for that entry into the 'fo' FSFILE |
||
3474 | object. |
||
3475 | Remarks: |
||
3476 | None. |
||
3477 | *****************************************************************/ |
||
3478 | |||
3479 | BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle) |
||
3480 | { |
||
3481 | DIRENTRY dir; |
||
3482 | BYTE index, a; |
||
3483 | BYTE character; |
||
3484 | BYTE status; |
||
3485 | BYTE test = 0; |
||
3486 | |||
3487 | // Get the entry |
||
3488 | if (((*fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) == 0) && (*fHandle != 0)) // 4-bit mask because 16-root entries max per sector |
||
3489 | { |
||
3490 | fo->dirccls = fo->dirclus; |
||
3491 | dir = Cache_File_Entry(fo, fHandle, TRUE); |
||
3492 | } |
||
3493 | else |
||
3494 | { |
||
3495 | dir = Cache_File_Entry (fo, fHandle, FALSE); |
||
3496 | } |
||
3497 | |||
3498 | |||
3499 | // Make sure there is a directory left |
||
3500 | if(dir == (DIRENTRY)NULL) |
||
3501 | { |
||
3502 | status = NO_MORE; |
||
3503 | } |
||
3504 | else |
||
3505 | { |
||
3506 | // Read the first char of the file name |
||
3507 | a = dir->DIR_Name[0]; |
||
3508 | |||
3509 | // Check for empty or deleted directory |
||
3510 | if ( a == DIR_DEL) |
||
3511 | { |
||
3512 | status = NOT_FOUND; |
||
3513 | } |
||
3514 | else if ( a == DIR_EMPTY) |
||
3515 | { |
||
3516 | status = NO_MORE; |
||
3517 | } |
||
3518 | else |
||
3519 | { |
||
3520 | // Get the attributes |
||
3521 | a = dir->DIR_Attr; |
||
3522 | |||
3523 | // print the file name and extension |
||
3524 | for (index=0; index < DIR_NAMESIZE; index++) |
||
3525 | { |
||
3526 | character = dir->DIR_Name[index]; |
||
3527 | character = (BYTE)toupper(character); |
||
3528 | fo->name[test++] = character; |
||
3529 | } |
||
3530 | |||
3531 | // Get the attributes |
||
3532 | a = dir->DIR_Attr; |
||
3533 | |||
3534 | // its possible to have an extension in a directory |
||
3535 | character = dir->DIR_Extension[0]; |
||
3536 | |||
3537 | // Get the file extension if its there |
||
3538 | for (index=0; index < DIR_EXTENSION; index++) |
||
3539 | { |
||
3540 | character = dir->DIR_Extension[index]; |
||
3541 | character = (BYTE)toupper(character); |
||
3542 | fo->name[test++] = character; |
||
3543 | } |
||
3544 | |||
3545 | // done and done with the name |
||
3546 | // fo->name[++test] = (BYTE)'\0'; |
||
3547 | |||
3548 | // Now store the identifier |
||
3549 | fo->entry = *fHandle; |
||
3550 | |||
3551 | // see if we are still a good file |
||
3552 | a = dir->DIR_Name[0]; |
||
3553 | |||
3554 | if(a == DIR_DEL) |
||
3555 | status = NOT_FOUND; |
||
3556 | else |
||
3557 | status = FOUND; |
||
3558 | |||
3559 | // Now store the size |
||
3560 | fo->size = (dir->DIR_FileSize); |
||
3561 | |||
3562 | fo->cluster = GetFullClusterNumber(dir); // Get Complete Cluster number. |
||
3563 | |||
3564 | /// -Get and store the attributes |
||
3565 | a = dir->DIR_Attr; |
||
3566 | fo->attributes = a; |
||
3567 | |||
3568 | // get the date and time |
||
3569 | if ((a & ATTR_DIRECTORY) != 0) |
||
3570 | { |
||
3571 | fo->time = dir->DIR_CrtTime; |
||
3572 | fo->date = dir->DIR_CrtDate; |
||
3573 | } |
||
3574 | else |
||
3575 | { |
||
3576 | fo->time = dir->DIR_WrtTime; |
||
3577 | fo->date = dir->DIR_WrtDate; |
||
3578 | } |
||
3579 | |||
3580 | }// deleted directory |
||
3581 | }// Ensure we are still good |
||
3582 | return(status); |
||
3583 | } // Fill_File_Object |
||
3584 | |||
3585 | |||
3586 | /************************************************************************ |
||
3587 | Function: |
||
3588 | DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle) |
||
3589 | Summary: |
||
3590 | Load file information from a directory entry and cache the entry |
||
3591 | Conditions: |
||
3592 | This function should not be called by the user. |
||
3593 | Input: |
||
3594 | fo - Pointer to file structure |
||
3595 | fHandle - Information location |
||
3596 | Return Values: |
||
3597 | DIRENTRY - Pointer to the directory entry |
||
3598 | NULL - Directory entry could not be loaded |
||
3599 | Side Effects: |
||
3600 | None |
||
3601 | Description: |
||
3602 | This function will cache the sector of directory entries |
||
3603 | in the directory pointed to by the dirclus value in |
||
3604 | the FSFILE object 'fo' that contains the entry that |
||
3605 | corresponds to the fHandle offset. It will then return a pointer |
||
3606 | to the directory entry in the global data buffer. |
||
3607 | Remarks: |
||
3608 | None. |
||
3609 | ************************************************************************/ |
||
3610 | |||
3611 | DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle) |
||
3612 | { |
||
3613 | DIRENTRY dir; |
||
3614 | BYTE a; |
||
3615 | |||
3616 | fo->dirccls = fo->dirclus; |
||
3617 | // Get the entry |
||
3618 | dir = Cache_File_Entry( fo, fHandle, TRUE); |
||
3619 | if (dir == NULL) |
||
3620 | return NULL; |
||
3621 | |||
3622 | // Read the first char of the file name |
||
3623 | a = dir->DIR_Name[0]; |
||
3624 | |||
3625 | // Make sure there is a directory left |
||
3626 | if(a == DIR_EMPTY) |
||
3627 | dir = (DIRENTRY)NULL; |
||
3628 | |||
3629 | if(dir != (DIRENTRY)NULL) |
||
3630 | { |
||
3631 | // Check for empty or deleted directory |
||
3632 | if ( a == DIR_DEL) |
||
3633 | dir = (DIRENTRY)NULL; |
||
3634 | else |
||
3635 | { |
||
3636 | // Get the attributes |
||
3637 | a = dir->DIR_Attr; |
||
3638 | |||
3639 | // scan through all the long dir entries |
||
3640 | while(a == ATTR_LONG_NAME) |
||
3641 | { |
||
3642 | (*fHandle)++; |
||
3643 | dir = Cache_File_Entry( fo, fHandle, FALSE); |
||
3644 | if (dir == NULL) |
||
3645 | return NULL; |
||
3646 | a = dir->DIR_Attr; |
||
3647 | } // long file name while loop |
||
3648 | } // deleted dir |
||
3649 | }// Ensure we are still good |
||
3650 | |||
3651 | return(dir); |
||
3652 | } // LoadDirAttrib |
||
3653 | |||
3654 | |||
3655 | /************************************************************************** |
||
3656 | Function: |
||
3657 | CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters) |
||
3658 | Summary: |
||
3659 | Erase a file |
||
3660 | Conditions: |
||
3661 | This function should not be called by the user. |
||
3662 | Input: |
||
3663 | fo - Pointer to file structure |
||
3664 | fHandle - Location of file information |
||
3665 | EraseClusters - Remove cluster allocation from FAT? |
||
3666 | Return Values: |
||
3667 | CE_GOOD - File erased successfully |
||
3668 | CE_FILE_NOT_FOUND - Could not find the file on the card |
||
3669 | CE_ERASE_FAIL - Internal Card erase failed |
||
3670 | Side Effects: |
||
3671 | None |
||
3672 | Description: |
||
3673 | This function will cache the sector of directory entries in the directory |
||
3674 | pointed to by the dirclus value in the FSFILE object 'fo' that contains |
||
3675 | the entry that corresponds to the fHandle offset. It will then mark that |
||
3676 | entry as deleted. If the EraseClusters argument is TRUE, the chain of |
||
3677 | clusters for that file will be marked as unused in the FAT by the |
||
3678 | FAT_erase_cluster_chain function. |
||
3679 | Remarks: |
||
3680 | None. |
||
3681 | **************************************************************************/ |
||
3682 | |||
3683 | #ifdef ALLOW_WRITES |
||
3684 | CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters) |
||
3685 | { |
||
3686 | DIRENTRY dir; |
||
3687 | BYTE a; |
||
3688 | CETYPE status = CE_GOOD; |
||
3689 | DWORD clus; |
||
3690 | DISK * disk; |
||
3691 | |||
3692 | disk = fo->dsk; |
||
3693 | |||
3694 | // reset the cluster |
||
3695 | clus = fo->dirclus; |
||
3696 | fo->dirccls = clus; |
||
3697 | |||
3698 | // load the sector |
||
3699 | dir = Cache_File_Entry(fo, fHandle, TRUE); |
||
3700 | if (dir == NULL) |
||
3701 | { |
||
3702 | FSerrno = CE_ERASE_FAIL; |
||
3703 | return CE_BADCACHEREAD; |
||
3704 | } |
||
3705 | |||
3706 | // Fill up the File Object with the information pointed to by fHandle |
||
3707 | a = dir->DIR_Name[0]; |
||
3708 | |||
3709 | // see if there is something in the dir |
||
3710 | if(dir == (DIRENTRY)NULL || a == DIR_EMPTY) |
||
3711 | { |
||
3712 | status = CE_FILE_NOT_FOUND; |
||
3713 | } |
||
3714 | else |
||
3715 | { |
||
3716 | // Check for empty or deleted directory |
||
3717 | if ( a == DIR_DEL) |
||
3718 | { |
||
3719 | status = CE_FILE_NOT_FOUND; |
||
3720 | } |
||
3721 | else |
||
3722 | { |
||
3723 | // Get the attributes |
||
3724 | a = dir->DIR_Attr; |
||
3725 | |||
3726 | /* 8.3 File Name - entry*/ |
||
3727 | dir->DIR_Name[0] = DIR_DEL; // mark as deleted |
||
3728 | |||
3729 | // Get the starting cluster |
||
3730 | clus = GetFullClusterNumber(dir); // Get Complete Cluster number. |
||
3731 | |||
3732 | // Now write it |
||
3733 | if(status != CE_GOOD || !(Write_File_Entry( fo, fHandle))) |
||
3734 | { |
||
3735 | status = CE_ERASE_FAIL; |
||
3736 | } |
||
3737 | else |
||
3738 | { |
||
3739 | if (clus != FatRootDirClusterValue) // |
||
3740 | { |
||
3741 | if(EraseClusters) |
||
3742 | { |
||
3743 | /* Now remove the cluster allocation from the FAT */ |
||
3744 | status = ((FAT_erase_cluster_chain(clus, disk)) ? CE_GOOD : CE_ERASE_FAIL); |
||
3745 | } |
||
3746 | } |
||
3747 | } |
||
3748 | } // Not already deleted |
||
3749 | }// Not existant |
||
3750 | |||
3751 | if (status == CE_GOOD) |
||
3752 | FSerrno = CE_GOOD; |
||
3753 | else |
||
3754 | FSerrno = CE_ERASE_FAIL; |
||
3755 | |||
3756 | return (status); |
||
3757 | } |
||
3758 | #endif |
||
3759 | |||
3760 | /*************************************************************** |
||
3761 | Function: |
||
3762 | int FSrename (const rom char * fileName, FSFILE * fo) |
||
3763 | Summary: |
||
3764 | Change the name of a file or directory |
||
3765 | Conditions: |
||
3766 | File opened. |
||
3767 | Input: |
||
3768 | fileName - The new name of the file |
||
3769 | fo - The file to rename |
||
3770 | Return Values: |
||
3771 | |||
3772 | EOF - File was not renamed |
||
3773 | Side Effects: |
||
3774 | The FSerrno variable will be changed. |
||
3775 | Description: |
||
3776 | The FSrename function will rename a file. First, it will |
||
3777 | search through the current working directory to ensure the |
||
3778 | specified new filename is not already in use. If it isn't, |
||
3779 | the new filename will be written to the file entry of the |
||
3780 | file pointed to by 'fo.' |
||
3781 | Remarks: |
||
3782 | None |
||
3783 | ***************************************************************/ |
||
3784 | |||
3785 | #ifdef ALLOW_WRITES |
||
3786 | |||
3787 | int FSrename (const char * fileName, FSFILE * fo) |
||
3788 | { |
||
3789 | unsigned char j, k = 0; |
||
3790 | char string[12]; |
||
3791 | WORD fHandle = 1, goodHandle; |
||
3792 | DIRENTRY dir; |
||
3793 | |||
3794 | FSerrno = CE_GOOD; |
||
3795 | |||
3796 | if (fo == NULL) |
||
3797 | { |
||
3798 | FSerrno = CE_FILENOTOPENED; |
||
3799 | return -1; |
||
3800 | } |
||
3801 | // If fo != NULL, rename the file |
||
3802 | if (FormatFileName (fileName, fo->name, 0) == FALSE) |
||
3803 | { |
||
3804 | FSerrno = CE_INVALID_FILENAME; |
||
3805 | return -1; |
||
3806 | } |
||
3807 | else |
||
3808 | { |
||
3809 | for (j = 0; j < 11; j++) |
||
3810 | { |
||
3811 | string[j] = fo->name[j]; |
||
3812 | } |
||
3813 | goodHandle = fo->entry; |
||
3814 | |||
3815 | fHandle = 0; |
||
3816 | fo->dirccls = fo->dirclus; |
||
3817 | dir = Cache_File_Entry (fo, &fHandle, TRUE); |
||
3818 | if (dir == NULL) |
||
3819 | { |
||
3820 | FSerrno = CE_BADCACHEREAD; |
||
3821 | return -1; |
||
3822 | } |
||
3823 | // Check if the file name is already used |
||
3824 | for (j = 0; j < 11; j++) |
||
3825 | { |
||
3826 | if (dir->DIR_Name[j] != string[j]) |
||
3827 | k = 1; |
||
3828 | } |
||
3829 | if (k == 0) |
||
3830 | { |
||
3831 | FSerrno = CE_FILENAME_EXISTS; |
||
3832 | return -1; |
||
3833 | } |
||
3834 | else |
||
3835 | k = 0; |
||
3836 | |||
3837 | nextClusterIsLast = FALSE; |
||
3838 | while (1) |
||
3839 | { |
||
3840 | // Look through the entries until we get to the end |
||
3841 | // to make sure the name isn't taken |
||
3842 | dir = Cache_File_Entry (fo, &fHandle, FALSE); |
||
3843 | if (dir == NULL) |
||
3844 | { |
||
3845 | if (nextClusterIsLast == TRUE) |
||
3846 | { |
||
3847 | break; |
||
3848 | } |
||
3849 | else |
||
3850 | { |
||
3851 | FSerrno = CE_BADCACHEREAD; |
||
3852 | return -1; |
||
3853 | } |
||
3854 | } |
||
3855 | if (dir->DIR_Name[0] == 0) |
||
3856 | break; |
||
3857 | for (j = 0; j < 11; j++) |
||
3858 | { |
||
3859 | if (dir->DIR_Name[j] != string[j]) |
||
3860 | k = 1; |
||
3861 | } |
||
3862 | if (k == 0) |
||
3863 | { |
||
3864 | FSerrno = CE_FILENAME_EXISTS; |
||
3865 | return -1; |
||
3866 | } |
||
3867 | else |
||
3868 | k = 0; |
||
3869 | fHandle++; |
||
3870 | } |
||
3871 | |||
3872 | fHandle = goodHandle; |
||
3873 | fo->dirccls = fo->dirclus; |
||
3874 | |||
3875 | // Get the file entry |
||
3876 | dir = LoadDirAttrib(fo, &fHandle); |
||
3877 | |||
3878 | if (dir == NULL) |
||
3879 | { |
||
3880 | FSerrno = CE_BADCACHEREAD; |
||
3881 | return -1; |
||
3882 | } |
||
3883 | |||
3884 | for (j = 0; j < 11; j++) |
||
3885 | { |
||
3886 | dir->DIR_Name[j] = fo->name[j]; |
||
3887 | } |
||
3888 | |||
3889 | // just write the last entry in |
||
3890 | if(!Write_File_Entry(fo,&fHandle)) |
||
3891 | { |
||
3892 | FSerrno = CE_WRITE_ERROR; |
||
3893 | return -1; |
||
3894 | } |
||
3895 | } |
||
3896 | |||
3897 | return 0; |
||
3898 | } |
||
3899 | |||
3900 | #endif // Allow writes |
||
3901 | |||
3902 | |||
3903 | |||
3904 | /********************************************************************* |
||
3905 | Function: |
||
3906 | FSFILE * FSfopen (const char * fileName, const char *mode) |
||
3907 | Summary: |
||
3908 | Open a file |
||
3909 | Conditions: |
||
3910 | For read modes, file exists; FSInit performed |
||
3911 | Input: |
||
3912 | fileName - The name of the file to open |
||
3913 | mode - |
||
3914 | - WRITE - Create a new file or replace an existing file |
||
3915 | - READ - Read data from an existing file |
||
3916 | - APPEND - Append data to an existing file |
||
3917 | - WRITEPLUS - Create a new file or replace an existing file (reads also enabled) |
||
3918 | - READPLUS - Read data from an existing file (writes also enabled) |
||
3919 | - APPENDPLUS - Append data to an existing file (reads also enabled) |
||
3920 | Return Values: |
||
3921 | FSFILE * - The pointer to the file object |
||
3922 | NULL - The file could not be opened |
||
3923 | Side Effects: |
||
3924 | The FSerrno variable will be changed. |
||
3925 | Description: |
||
3926 | This function will open a file or directory. First, RAM in the |
||
3927 | dynamic heap or static array will be allocated to a new FSFILE object. |
||
3928 | Then, the specified file name will be formatted to ensure that it's |
||
3929 | in 8.3 format. Next, the FILEfind function will be used to search |
||
3930 | for the specified file name. If the name is found, one of three |
||
3931 | things will happen: if the file was opened in read mode, its file |
||
3932 | info will be loaded using the FILEopen function; if it was opened in |
||
3933 | write mode, it will be erased, and a new file will be constructed in |
||
3934 | its place; if it was opened in append mode, its file info will be |
||
3935 | loaded with FILEopen and the current location will be moved to the |
||
3936 | end of the file using the FSfseek function. If the file was not |
||
3937 | found by FILEfind, it will be created if the mode was specified as |
||
3938 | a write or append mode. In these cases, a pointer to the heap or |
||
3939 | static FSFILE object array will be returned. If the file was not |
||
3940 | found and the mode was specified as a read mode, the memory |
||
3941 | allocated to the file will be freed and the NULL pointer value |
||
3942 | will be returned. |
||
3943 | Remarks: |
||
3944 | None. |
||
3945 | *********************************************************************/ |
||
3946 | |||
3947 | FSFILE * FSfopen( const char * fileName, const char *mode ) |
||
3948 | { |
||
3949 | FILEOBJ filePtr; |
||
3950 | #ifndef FS_DYNAMIC_MEM |
||
3951 | int fIndex; |
||
3952 | #endif |
||
3953 | BYTE ModeC; |
||
3954 | WORD fHandle; |
||
3955 | CETYPE final; |
||
3956 | |||
3957 | #ifdef FS_DYNAMIC_MEM |
||
3958 | filePtr = (FILEOBJ) FS_malloc(sizeof(FSFILE)); |
||
3959 | #else |
||
3960 | |||
3961 | filePtr = NULL; |
||
3962 | |||
3963 | //Pick available file structure |
||
3964 | for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ ) |
||
3965 | { |
||
3966 | if( gFileSlotOpen[fIndex] ) //this slot is available |
||
3967 | { |
||
3968 | gFileSlotOpen[fIndex] = FALSE; |
||
3969 | filePtr = &gFileArray[fIndex]; |
||
3970 | break; |
||
3971 | } |
||
3972 | } |
||
3973 | |||
3974 | if( filePtr == NULL ) |
||
3975 | { |
||
3976 | FSerrno = CE_TOO_MANY_FILES_OPEN; |
||
3977 | return NULL; //no file structure slot available |
||
3978 | } |
||
3979 | #endif |
||
3980 | |||
3981 | //Format the source string. |
||
3982 | if( !FormatFileName(fileName, filePtr->name, 0) ) |
||
3983 | { |
||
3984 | #ifdef FS_DYNAMIC_MEM |
||
3985 | FS_free( (unsigned char *)filePtr ); |
||
3986 | #else |
||
3987 | gFileSlotOpen[fIndex] = TRUE; //put this slot back to the pool |
||
3988 | #endif |
||
3989 | FSerrno = CE_INVALID_FILENAME; |
||
3990 | return NULL; //bad filename |
||
3991 | } |
||
3992 | |||
3993 | //Read the mode character |
||
3994 | ModeC = mode[0]; |
||
3995 | |||
3996 | filePtr->dsk = &gDiskData; |
||
3997 | filePtr->cluster = 0; |
||
3998 | filePtr->ccls = 0; |
||
3999 | filePtr->entry = 0; |
||
4000 | filePtr->attributes = ATTR_ARCHIVE; |
||
4001 | |||
4002 | // start at the current directory |
||
4003 | #ifdef ALLOW_DIRS |
||
4004 | filePtr->dirclus = cwdptr->dirclus; |
||
4005 | filePtr->dirccls = cwdptr->dirccls; |
||
4006 | #else |
||
4007 | filePtr->dirclus = FatRootDirClusterValue; |
||
4008 | filePtr->dirccls = FatRootDirClusterValue; |
||
4009 | #endif |
||
4010 | |||
4011 | // copy file object over |
||
4012 | FileObjectCopy(&gFileTemp, filePtr); |
||
4013 | |||
4014 | // See if the file is found |
||
4015 | if(FILEfind (filePtr, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0) == CE_GOOD) |
||
4016 | { |
||
4017 | // File is Found |
||
4018 | switch(ModeC) |
||
4019 | { |
||
4020 | #ifdef ALLOW_WRITES |
||
4021 | case 'w': |
||
4022 | case 'W': |
||
4023 | { |
||
4024 | // File exists, we want to create a new one, remove it first |
||
4025 | fHandle = filePtr->entry; |
||
4026 | final = FILEerase(filePtr, &fHandle, TRUE); |
||
4027 | |||
4028 | if (final == CE_GOOD) |
||
4029 | { |
||
4030 | // now create a new one |
||
4031 | final = CreateFileEntry (filePtr, &fHandle, 0); |
||
4032 | |||
4033 | if (final == CE_GOOD) |
||
4034 | { |
||
4035 | final = FILEopen (filePtr, &fHandle, 'w'); |
||
4036 | |||
4037 | if (filePtr->attributes & ATTR_DIRECTORY) |
||
4038 | { |
||
4039 | FSerrno = CE_INVALID_ARGUMENT; |
||
4040 | final = 0xFF; |
||
4041 | } |
||
4042 | |||
4043 | if (final == CE_GOOD) |
||
4044 | { |
||
4045 | final = FSfseek (filePtr, 0, SEEK_END); |
||
4046 | if (mode[1] == '+') |
||
4047 | filePtr->flags.read = 1; |
||
4048 | } |
||
4049 | } |
||
4050 | } |
||
4051 | break; |
||
4052 | } |
||
4053 | |||
4054 | case 'A': |
||
4055 | case 'a': |
||
4056 | { |
||
4057 | if(filePtr->size != 0) |
||
4058 | { |
||
4059 | fHandle = filePtr->entry; |
||
4060 | |||
4061 | final = FILEopen (filePtr, &fHandle, 'w'); |
||
4062 | |||
4063 | if (filePtr->attributes & ATTR_DIRECTORY) |
||
4064 | { |
||
4065 | FSerrno = CE_INVALID_ARGUMENT; |
||
4066 | final = 0xFF; |
||
4067 | } |
||
4068 | |||
4069 | if (final == CE_GOOD) |
||
4070 | { |
||
4071 | final = FSfseek (filePtr, 0, SEEK_END); |
||
4072 | if (final != CE_GOOD) |
||
4073 | FSerrno = CE_SEEK_ERROR; |
||
4074 | else |
||
4075 | ReadFAT (&gDiskData, filePtr->ccls); |
||
4076 | if (mode[1] == '+') |
||
4077 | filePtr->flags.read = 1; |
||
4078 | } |
||
4079 | } |
||
4080 | else |
||
4081 | { |
||
4082 | fHandle = filePtr->entry; |
||
4083 | final = FILEerase(filePtr, &fHandle, TRUE); |
||
4084 | |||
4085 | if (final == CE_GOOD) |
||
4086 | { |
||
4087 | // now create a new one |
||
4088 | final = CreateFileEntry (filePtr, &fHandle, 0); |
||
4089 | |||
4090 | if (final == CE_GOOD) |
||
4091 | { |
||
4092 | final = FILEopen (filePtr, &fHandle, 'w'); |
||
4093 | |||
4094 | if (filePtr->attributes & ATTR_DIRECTORY) |
||
4095 | { |
||
4096 | FSerrno = CE_INVALID_ARGUMENT; |
||
4097 | final = 0xFF; |
||
4098 | } |
||
4099 | |||
4100 | if (final == CE_GOOD) |
||
4101 | { |
||
4102 | final = FSfseek (filePtr, 0, SEEK_END); |
||
4103 | if (final != CE_GOOD) |
||
4104 | FSerrno = CE_SEEK_ERROR; |
||
4105 | if (mode[1] == '+') |
||
4106 | filePtr->flags.read = 1; |
||
4107 | } |
||
4108 | } |
||
4109 | } |
||
4110 | } |
||
4111 | break; |
||
4112 | } |
||
4113 | #endif |
||
4114 | case 'R': |
||
4115 | case 'r': |
||
4116 | { |
||
4117 | fHandle = filePtr->entry; |
||
4118 | |||
4119 | final = FILEopen (filePtr, &fHandle, 'r'); |
||
4120 | #ifdef ALLOW_WRITES |
||
4121 | if ((mode[1] == '+') && !(filePtr->attributes & ATTR_DIRECTORY)) |
||
4122 | filePtr->flags.write = 1; |
||
4123 | #endif |
||
4124 | break; |
||
4125 | } |
||
4126 | |||
4127 | default: |
||
4128 | FSerrno = CE_INVALID_ARGUMENT; |
||
4129 | final = 0xFF;; //indicate error condition |
||
4130 | break; |
||
4131 | } |
||
4132 | } |
||
4133 | else |
||
4134 | { |
||
4135 | #ifdef ALLOW_WRITES |
||
4136 | // the file was not found, reset to the default asked |
||
4137 | FileObjectCopy(filePtr, &gFileTemp); |
||
4138 | |||
4139 | // File is not Found |
||
4140 | if(ModeC == 'w' || ModeC == 'W' || ModeC == 'a' || ModeC == 'A') |
||
4141 | { |
||
4142 | // use the user requested name |
||
4143 | fHandle = 0; |
||
4144 | final = CreateFileEntry (filePtr, &fHandle, 0); |
||
4145 | |||
4146 | if (final == CE_GOOD) |
||
4147 | { |
||
4148 | final = FILEopen (filePtr, &fHandle, 'w'); |
||
4149 | if (filePtr->attributes & ATTR_DIRECTORY) |
||
4150 | { |
||
4151 | FSerrno = CE_INVALID_ARGUMENT; |
||
4152 | final = 0xFF; |
||
4153 | } |
||
4154 | |||
4155 | if (final == CE_GOOD) |
||
4156 | { |
||
4157 | final = FSfseek (filePtr, 0, SEEK_END); |
||
4158 | if (final != CE_GOOD) |
||
4159 | FSerrno = CE_SEEK_ERROR; |
||
4160 | if (mode[1] == '+') |
||
4161 | filePtr->flags.read = 1; |
||
4162 | } |
||
4163 | } |
||
4164 | } |
||
4165 | else |
||
4166 | #endif |
||
4167 | final = CE_FILE_NOT_FOUND; |
||
4168 | } |
||
4169 | |||
4170 | if (MDD_WriteProtectState()) |
||
4171 | { |
||
4172 | filePtr->flags.write = 0;; |
||
4173 | } |
||
4174 | |||
4175 | #ifdef FS_DYNAMIC_MEM |
||
4176 | if( final != CE_GOOD ) |
||
4177 | { |
||
4178 | FS_free( (unsigned char *)filePtr ); |
||
4179 | filePtr = NULL; |
||
4180 | } |
||
4181 | #else |
||
4182 | if( final != CE_GOOD ) |
||
4183 | { |
||
4184 | gFileSlotOpen[fIndex] = TRUE; //put this slot back to the pool |
||
4185 | filePtr = NULL; |
||
4186 | } |
||
4187 | #endif |
||
4188 | else |
||
4189 | { |
||
4190 | FSerrno = CE_GOOD; |
||
4191 | } |
||
4192 | |||
4193 | return filePtr; |
||
4194 | } |
||
4195 | |||
4196 | /******************************************************************* |
||
4197 | Function: |
||
4198 | long FSftell (FSFILE * fo) |
||
4199 | Summary: |
||
4200 | Determine the current location in a file |
||
4201 | Conditions: |
||
4202 | File opened |
||
4203 | Input: |
||
4204 | fo - Pointer to file structure |
||
4205 | Return: Current location in the file |
||
4206 | Side Effects: |
||
4207 | The FSerrno variable will be changed |
||
4208 | Description: |
||
4209 | The FSftell function will return the current position in the |
||
4210 | file pointed to by 'fo' by returning the 'seek' variable in the |
||
4211 | FSFILE object, which is used to keep track of the absolute |
||
4212 | location of the current position in the file. |
||
4213 | Remarks: |
||
4214 | None |
||
4215 | *******************************************************************/ |
||
4216 | |||
4217 | long FSftell (FSFILE * fo) |
||
4218 | { |
||
4219 | FSerrno = CE_GOOD; |
||
4220 | return (fo->seek); |
||
4221 | } |
||
4222 | |||
4223 | |||
4224 | #ifdef ALLOW_WRITES |
||
4225 | |||
4226 | /********************************************************************* |
||
4227 | Function: |
||
4228 | int FSremove (const char * fileName) |
||
4229 | Summary: |
||
4230 | Delete a file |
||
4231 | Conditions: |
||
4232 | File not opened, file exists |
||
4233 | Input: |
||
4234 | fileName - Name of the file to erase |
||
4235 | Return Values: |
||
4236 | |||
4237 | EOF - File was not removed |
||
4238 | Side Effects: |
||
4239 | The FSerrno variable will be changed. |
||
4240 | Description: |
||
4241 | The FSremove function will attempt to find the specified file with |
||
4242 | the FILEfind function. If the file is found, it will be erased |
||
4243 | using the FILEerase function. |
||
4244 | Remarks: |
||
4245 | None |
||
4246 | **********************************************************************/ |
||
4247 | |||
4248 | int FSremove (const char * fileName) |
||
4249 | { |
||
4250 | FILEOBJ fo = &tempCWDobj; |
||
4251 | CETYPE result; |
||
4252 | |||
4253 | FSerrno = CE_GOOD; |
||
4254 | |||
4255 | if (MDD_WriteProtectState()) |
||
4256 | { |
||
4257 | FSerrno = CE_WRITE_PROTECTED; |
||
4258 | return (-1); |
||
4259 | } |
||
4260 | |||
4261 | //Format the source string |
||
4262 | if( !FormatFileName(fileName, fo->name, 0) ) |
||
4263 | { |
||
4264 | FSerrno = CE_INVALID_FILENAME; |
||
4265 | return -1; |
||
4266 | } |
||
4267 | |||
4268 | fo->dsk = &gDiskData; |
||
4269 | fo->cluster = 0; |
||
4270 | fo->ccls = 0; |
||
4271 | fo->entry = 0; |
||
4272 | fo->attributes = ATTR_ARCHIVE; |
||
4273 | |||
4274 | #ifndef ALLOW_DIRS |
||
4275 | // start at the root directory |
||
4276 | fo->dirclus = FatRootDirClusterValue; |
||
4277 | fo->dirccls = FatRootDirClusterValue; |
||
4278 | #else |
||
4279 | fo->dirclus = cwdptr->dirclus; |
||
4280 | fo->dirccls = cwdptr->dirccls; |
||
4281 | #endif |
||
4282 | |||
4283 | // copy file object over |
||
4284 | FileObjectCopy(&gFileTemp, fo); |
||
4285 | |||
4286 | // See if the file is found |
||
4287 | result = FILEfind (fo, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0); |
||
4288 | |||
4289 | if (result != CE_GOOD) |
||
4290 | { |
||
4291 | FSerrno = CE_FILE_NOT_FOUND; |
||
4292 | return -1; |
||
4293 | } |
||
4294 | |||
4295 | if (fo->attributes & ATTR_DIRECTORY) |
||
4296 | { |
||
4297 | FSerrno = CE_DELETE_DIR; |
||
4298 | return -1; |
||
4299 | } |
||
4300 | |||
4301 | result = FILEerase(fo, &fo->entry, TRUE); |
||
4302 | if( result == CE_GOOD ) |
||
4303 | return 0; |
||
4304 | else |
||
4305 | { |
||
4306 | FSerrno = CE_ERASE_FAIL; |
||
4307 | return -1; |
||
4308 | } |
||
4309 | } |
||
4310 | #endif |
||
4311 | |||
4312 | /********************************************************* |
||
4313 | Function: |
||
4314 | void FSrewind (FSFILE * fo) |
||
4315 | Summary: |
||
4316 | Set the current position in a file to the beginning |
||
4317 | Conditions: |
||
4318 | File opened. |
||
4319 | Input: |
||
4320 | fo - Pointer to file structure |
||
4321 | Return Values: |
||
4322 | None |
||
4323 | Side Effects: |
||
4324 | None. |
||
4325 | Description: |
||
4326 | The FSrewind funciton will reset the position of the |
||
4327 | specified file to the beginning of the file. This |
||
4328 | functionality is faster than using FSfseek to reset |
||
4329 | the position in the file. |
||
4330 | Remarks: |
||
4331 | None. |
||
4332 | *********************************************************/ |
||
4333 | |||
4334 | void FSrewind (FSFILE * fo) |
||
4335 | { |
||
4336 | #ifdef ALLOW_WRITES |
||
4337 | if (gNeedDataWrite) |
||
4338 | flushData(); |
||
4339 | #endif |
||
4340 | fo->seek = 0; |
||
4341 | fo->pos = 0; |
||
4342 | fo->sec = 0; |
||
4343 | fo->ccls = fo->cluster; |
||
4344 | gBufferOwner = NULL; |
||
4345 | return; |
||
4346 | } |
||
4347 | |||
4348 | /************************************************************************** |
||
4349 | Function: |
||
4350 | int FSerror (void) |
||
4351 | Summary: |
||
4352 | Return an error code for the last function call |
||
4353 | Conditions: |
||
4354 | The return value depends on the last function called. |
||
4355 | Input: |
||
4356 | None |
||
4357 | Side Effects: |
||
4358 | None. |
||
4359 | Return Values: |
||
4360 | FSInit - |
||
4361 | - CE_GOOD No Error |
||
4362 | - CE_INIT_ERROR The physical media could not be initialized |
||
4363 | - CE_BAD_SECTOR_READ The MBR or the boot sector could not be |
||
4364 | read correctly |
||
4365 | - CE_BAD_PARITION The MBR signature code was incorrect. |
||
4366 | - CE_NOT_FORMATTED The boot sector signature code was incorrect or |
||
4367 | indicates an invalid number of bytes per sector. |
||
4368 | - CE_UNSUPPORTED_SECTOR_SIZE - The number of bytes per sector is unsupported |
||
4369 | - CE_CARDFAT32 The physical media is FAT32 type (only an error |
||
4370 | when FAT32 support is disabled). |
||
4371 | - CE_UNSUPPORTED_FS The device is formatted with an unsupported file |
||
4372 | system (not FAT12 or 16). |
||
4373 | FSfopen - |
||
4374 | - CE_GOOD No Error |
||
4375 | - CE_NOT_INIT The device has not been initialized. |
||
4376 | - CE_TOO_MANY_FILES_OPEN The function could not allocate any |
||
4377 | additional file information to the array |
||
4378 | of FSFILE structures or the heap. |
||
4379 | - CE_INVALID_FILENAME The file name argument was invalid. |
||
4380 | - CE_INVALID_ARGUMENT The user attempted to open a directory in a |
||
4381 | write mode or specified an invalid mode argument. |
||
4382 | - CE_FILE_NOT_FOUND The specified file (which was to be opened in read |
||
4383 | mode) does not exist on the device. |
||
4384 | - CE_BADCACHEREAD A read from the device failed. |
||
4385 | - CE_ERASE_FAIL The existing file could not be erased (when opening |
||
4386 | a file in WRITE mode). |
||
4387 | - CE_DIR_FULL The directory is full. |
||
4388 | - CE_DISK_FULL The data memory section is full. |
||
4389 | - CE_WRITE_ERROR A write to the device failed. |
||
4390 | - CE_SEEK_ERROR The current position in the file could not be set to |
||
4391 | the end (when the file was opened in APPEND mode). |
||
4392 | FSfclose - |
||
4393 | - CE_GOOD No Error |
||
4394 | - CE_WRITE_ERROR The existing data in the data buffer or the new file |
||
4395 | entry information could not be written to the device. |
||
4396 | - CE_BADCACHEREAD The file entry information could not be cached |
||
4397 | FSfread - |
||
4398 | - CE_GOOD No Error |
||
4399 | - CE_WRITEONLY The file was opened in a write-only mode. |
||
4400 | - CE_WRITE_ERROR The existing data in the data buffer could not be |
||
4401 | written to the device. |
||
4402 | - CE_BAD_SECTOR_READ The data sector could not be read. |
||
4403 | - CE_EOF The end of the file was reached. |
||
4404 | - CE_COULD_NOT_GET_CLUSTER Additional clusters in the file could not be loaded. |
||
4405 | FSfwrite - |
||
4406 | - CE_GOOD No Error |
||
4407 | - CE_READONLY The file was opened in a read-only mode. |
||
4408 | - CE_WRITE_PROTECTED The device write-protect check function indicated |
||
4409 | that the device has been write-protected. |
||
4410 | - CE_WRITE_ERROR There was an error writing data to the device. |
||
4411 | - CE_BADCACHEREAD The data sector to be modified could not be read from |
||
4412 | the device. |
||
4413 | - CE_DISK_FULL All data clusters on the device are in use. |
||
4414 | FSfseek - |
||
4415 | - CE_GOOD No Error |
||
4416 | - CE_WRITE_ERROR The existing data in the data buffer could not be |
||
4417 | written to the device. |
||
4418 | - CE_INVALID_ARGUMENT The specified offset exceeds the size of the file. |
||
4419 | - CE_BADCACHEREAD The sector that contains the new current position |
||
4420 | could not be loaded. |
||
4421 | - CE_COULD_NOT_GET_CLUSTER Additional clusters in the file could not be |
||
4422 | loaded/allocated. |
||
4423 | FSftell - |
||
4424 | - CE_GOOD No Error |
||
4425 | FSattrib - |
||
4426 | - CE_GOOD No Error |
||
4427 | - CE_INVALID_ARGUMENT The attribute argument was invalid. |
||
4428 | - CE_BADCACHEREAD The existing file entry information could not be |
||
4429 | loaded. |
||
4430 | - CE_WRITE_ERROR The file entry information could not be written to |
||
4431 | the device. |
||
4432 | FSrename - |
||
4433 | - CE_GOOD No Error |
||
4434 | - CE_FILENOTOPENED A null file pointer was passed into the function. |
||
4435 | - CE_INVALID_FILENAME The file name passed into the function was invalid. |
||
4436 | - CE_BADCACHEREAD A read from the device failed. |
||
4437 | - CE_FILENAME_EXISTS A file with the specified name already exists. |
||
4438 | - CE_WRITE_ERROR The new file entry data could not be written to the |
||
4439 | device. |
||
4440 | FSfeof - |
||
4441 | - CE_GOOD No Error |
||
4442 | FSformat - |
||
4443 | - CE_GOOD No Error |
||
4444 | - CE_INIT_ERROR The device could not be initialized. |
||
4445 | - CE_BADCACHEREAD The master boot record or boot sector could not be |
||
4446 | loaded successfully. |
||
4447 | - CE_INVALID_ARGUMENT The user selected to create their own boot sector on |
||
4448 | a device that has no master boot record, or the mode |
||
4449 | argument was invalid. |
||
4450 | - CE_WRITE_ERROR The updated MBR/Boot sector could not be written to |
||
4451 | the device. |
||
4452 | - CE_BAD_PARTITION The calculated number of sectors per clusters was |
||
4453 | invalid. |
||
4454 | - CE_NONSUPPORTED_SIZE The card has too many sectors to be formatted as |
||
4455 | FAT12 or FAT16. |
||
4456 | FSremove - |
||
4457 | - CE_GOOD No Error |
||
4458 | - CE_WRITE_PROTECTED The device write-protect check function indicated |
||
4459 | that the device has been write-protected. |
||
4460 | - CE_INVALID_FILENAME The specified filename was invalid. |
||
4461 | - CE_FILE_NOT_FOUND The specified file could not be found. |
||
4462 | - CE_ERASE_FAIL The file could not be erased. |
||
4463 | FSchdir - |
||
4464 | - CE_GOOD No Error |
||
4465 | - CE_INVALID_ARGUMENT The path string was mis-formed or the user tried to |
||
4466 | change to a non-directory file. |
||
4467 | - CE_BADCACHEREAD A directory entry could not be cached. |
||
4468 | - CE_DIR_NOT_FOUND Could not find a directory in the path. |
||
4469 | FSgetcwd - |
||
4470 | - CE_GOOD No Error |
||
4471 | - CE_INVALID_ARGUMENT The user passed a 0-length buffer into the function. |
||
4472 | - CE_BADCACHEREAD A directory entry could not be cached. |
||
4473 | - CE_BAD_SECTOR_READ The function could not determine a previous directory |
||
4474 | of the current working directory. |
||
4475 | FSmkdir - |
||
4476 | - CE_GOOD No Error |
||
4477 | - CE_WRITE_PROTECTED The device write-protect check function indicated |
||
4478 | that the device has been write-protected. |
||
4479 | - CE_INVALID_ARGUMENT The path string was mis-formed. |
||
4480 | - CE_BADCACHEREAD Could not successfully change to a recently created |
||
4481 | directory to store its dir entry information, or |
||
4482 | could not cache directory entry information. |
||
4483 | - CE_INVALID_FILENAME One or more of the directory names has an invalid |
||
4484 | format. |
||
4485 | - CE_WRITE_ERROR The existing data in the data buffer could not be |
||
4486 | written to the device or the dot/dotdot entries could |
||
4487 | not be written to a newly created directory. |
||
4488 | - CE_DIR_FULL There are no available dir entries in the CWD. |
||
4489 | - CE_DISK_FULL There are no available clusters in the data region of |
||
4490 | the device. |
||
4491 | FSrmdir - |
||
4492 | - CE_GOOD No Error |
||
4493 | - CE_DIR_NOT_FOUND The directory specified could not be found or the |
||
4494 | function could not change to a subdirectory within |
||
4495 | the directory to be deleted (when recursive delete is |
||
4496 | enabled). |
||
4497 | - CE_INVALID_ARGUMENT The user tried to remove the CWD or root directory. |
||
4498 | - CE_BADCACHEREAD A directory entry could not be cached. |
||
4499 | - CE_DIR_NOT_EMPTY The directory to be deleted was not empty and |
||
4500 | recursive subdirectory removal was disabled. |
||
4501 | - CE_ERASE_FAIL The directory or one of the directories or files |
||
4502 | within it could not be deleted. |
||
4503 | - CE_BAD_SECTOR_READ The function could not determine a previous directory |
||
4504 | of the CWD. |
||
4505 | SetClockVars - |
||
4506 | - CE_GOOD No Error |
||
4507 | - CE_INVALID_ARGUMENT The time values passed into the function were |
||
4508 | invalid. |
||
4509 | FindFirst - |
||
4510 | - CE_GOOD No Error |
||
4511 | - CE_INVALID_FILENAME The specified filename was invalid. |
||
4512 | - CE_FILE_NOT_FOUND No file matching the specified criteria was found. |
||
4513 | - CE_BADCACHEREAD The file information for the file that was found |
||
4514 | could not be cached. |
||
4515 | FindNext - |
||
4516 | - CE_GOOD No Error |
||
4517 | - CE_NOT_INIT The SearchRec object was not initialized by a call to |
||
4518 | FindFirst. |
||
4519 | - CE_INVALID_ARGUMENT The SearchRec object was initialized in a different |
||
4520 | directory from the CWD. |
||
4521 | - CE_INVALID_FILENAME The filename is invalid. |
||
4522 | - CE_FILE_NOT_FOUND No file matching the specified criteria was found. |
||
4523 | FSfprintf - |
||
4524 | - CE_GOOD No Error |
||
4525 | - CE_WRITE_ERROR Characters could not be written to the file. |
||
4526 | Description: |
||
4527 | The FSerror function will return the FSerrno variable. This global |
||
4528 | variable will have been set to an error value during the last call of a |
||
4529 | library function. |
||
4530 | Remarks: |
||
4531 | None |
||
4532 | **************************************************************************/ |
||
4533 | |||
4534 | int FSerror (void) |
||
4535 | { |
||
4536 | return FSerrno; |
||
4537 | } |
||
4538 | |||
4539 | |||
4540 | /************************************************************** |
||
4541 | Function: |
||
4542 | void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource) |
||
4543 | Summary: |
||
4544 | Copy a file object |
||
4545 | Conditions: |
||
4546 | This function should not be called by the user. |
||
4547 | Input: |
||
4548 | foDest - The destination |
||
4549 | foSource - the source |
||
4550 | Return: |
||
4551 | None |
||
4552 | Side Effects: |
||
4553 | None |
||
4554 | Description: |
||
4555 | The FileObjectCopy function will make an exacy copy of |
||
4556 | a specified FSFILE object. |
||
4557 | Remarks: |
||
4558 | None |
||
4559 | **************************************************************/ |
||
4560 | |||
4561 | void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource) |
||
4562 | { |
||
4563 | BYTE size; |
||
4564 | BYTE *dest; |
||
4565 | BYTE *source; |
||
4566 | BYTE Index; |
||
4567 | |||
4568 | dest = (BYTE *)foDest; |
||
4569 | source = (BYTE *)foSource; |
||
4570 | |||
4571 | size = sizeof(FSFILE); |
||
4572 | |||
4573 | for(Index=0;Index< size; Index++) |
||
4574 | { |
||
4575 | dest[Index] = source[Index]; |
||
4576 | } |
||
4577 | } |
||
4578 | |||
4579 | /************************************************************************* |
||
4580 | Function: |
||
4581 | CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster) |
||
4582 | Summary: |
||
4583 | Create the first cluster of a file |
||
4584 | Conditions: |
||
4585 | This function should not be called by the user. |
||
4586 | Input: |
||
4587 | fo - Pointer to file structure |
||
4588 | cluster - Cluster location |
||
4589 | Return Values: |
||
4590 | CE_GOOD - File closed successfully |
||
4591 | CE_WRITE_ERROR - Could not write to the sector |
||
4592 | CE_DISK_FULL - All clusters in partition are taken |
||
4593 | Side Effects: |
||
4594 | None |
||
4595 | Description: |
||
4596 | The FILECreateHeadCluster function will create the first cluster |
||
4597 | of a file. First, it will find an empty cluster with the |
||
4598 | FATfindEmptyCluster function and mark it as the last cluster in the |
||
4599 | file. It will then erase the cluster using the EraseCluster function. |
||
4600 | Remarks: |
||
4601 | None. |
||
4602 | *************************************************************************/ |
||
4603 | |||
4604 | #ifdef ALLOW_WRITES |
||
4605 | CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster) |
||
4606 | { |
||
4607 | DISK * disk; |
||
4608 | CETYPE error = CE_GOOD; |
||
4609 | |||
4610 | disk = fo->dsk; |
||
4611 | |||
4612 | // find the next empty cluster |
||
4613 | *cluster = FATfindEmptyCluster(fo); |
||
4614 | |||
4615 | if(*cluster == 0) // "0" is just an indication as Disk full in the fn "FATfindEmptyCluster()" |
||
4616 | { |
||
4617 | error = CE_DISK_FULL; |
||
4618 | } |
||
4619 | else |
||
4620 | { |
||
4621 | // mark the cluster as taken, and last in chain |
||
4622 | if(disk->type == FAT12) |
||
4623 | { |
||
4624 | if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT12, FALSE) == CLUSTER_FAIL_FAT16) |
||
4625 | { |
||
4626 | error = CE_WRITE_ERROR; |
||
4627 | } |
||
4628 | } |
||
4629 | else if(disk->type == FAT16) |
||
4630 | { |
||
4631 | if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT16, FALSE) == CLUSTER_FAIL_FAT16) |
||
4632 | { |
||
4633 | error = CE_WRITE_ERROR; |
||
4634 | } |
||
4635 | } |
||
4636 | |||
4637 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
4638 | else |
||
4639 | { |
||
4640 | if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT32, FALSE) == CLUSTER_FAIL_FAT32) |
||
4641 | { |
||
4642 | error = CE_WRITE_ERROR; |
||
4643 | } |
||
4644 | } |
||
4645 | #endif |
||
4646 | |||
4647 | // lets erase this cluster |
||
4648 | if(error == CE_GOOD) |
||
4649 | { |
||
4650 | error = EraseCluster(disk,*cluster); |
||
4651 | } |
||
4652 | } |
||
4653 | |||
4654 | return(error); |
||
4655 | } // allocate head cluster |
||
4656 | #endif |
||
4657 | |||
4658 | /************************************************************************* |
||
4659 | Function: |
||
4660 | BYTE EraseCluster(DISK *disk, DWORD cluster) |
||
4661 | Summary: |
||
4662 | Erase a cluster |
||
4663 | Conditions: |
||
4664 | This function should not be called by the user. |
||
4665 | Input: |
||
4666 | dsk - Disk structure |
||
4667 | cluster - Cluster to be erased |
||
4668 | Return Values: |
||
4669 | CE_GOOD - File closed successfully |
||
4670 | CE_WRITE_ERROR - Could not write to the sector |
||
4671 | Side Effects: |
||
4672 | None |
||
4673 | Description: |
||
4674 | The EraseCluster function will write a 0 value into every byte of |
||
4675 | the specified cluster. |
||
4676 | Remarks: |
||
4677 | None. |
||
4678 | *************************************************************************/ |
||
4679 | |||
4680 | #ifdef ALLOW_WRITES |
||
4681 | BYTE EraseCluster(DISK *disk, DWORD cluster) |
||
4682 | { |
||
4683 | BYTE index; |
||
4684 | DWORD SectorAddress; |
||
4685 | BYTE error = CE_GOOD; |
||
4686 | |||
4687 | SectorAddress = Cluster2Sector(disk,cluster); |
||
4688 | if (gNeedDataWrite) |
||
4689 | if (flushData()) |
||
4690 | return CE_WRITE_ERROR; |
||
4691 | |||
4692 | gBufferOwner = NULL; |
||
4693 | |||
4694 | if (gBufferZeroed == FALSE) |
||
4695 | { |
||
4696 | // clear out the memory first |
||
4697 | memset(disk->buffer, 0x00, MEDIA_SECTOR_SIZE); |
||
4698 | gBufferZeroed = TRUE; |
||
4699 | } |
||
4700 | |||
4701 | // Now clear them out |
||
4702 | for(index = 0; index < disk->SecPerClus && error == CE_GOOD; index++) |
||
4703 | { |
||
4704 | if (MDD_SectorWrite( SectorAddress++, disk->buffer, FALSE) != TRUE) |
||
4705 | error = CE_WRITE_ERROR; |
||
4706 | } |
||
4707 | |||
4708 | return(error); |
||
4709 | } |
||
4710 | #endif |
||
4711 | |||
4712 | |||
4713 | #if defined (__C30__) || defined (__PIC32MX__) |
||
4714 | |||
4715 | /*************************************************** |
||
4716 | Function: |
||
4717 | BYTE ReadByte(BYTE * pBuffer, WORD index) |
||
4718 | Summary: |
||
4719 | Read a byte from a buffer |
||
4720 | Conditions: |
||
4721 | This function should not be called by the user. |
||
4722 | Input: |
||
4723 | pBuffer - pointer to a buffer to read from |
||
4724 | index - index in the buffer to read to |
||
4725 | Return: |
||
4726 | BYTE - the byte read |
||
4727 | Side Effects: |
||
4728 | None |
||
4729 | Description: |
||
4730 | Reads a byte from a buffer |
||
4731 | Remarks: |
||
4732 | None. |
||
4733 | ***************************************************/ |
||
4734 | |||
4735 | BYTE ReadByte( BYTE* pBuffer, WORD index ) |
||
4736 | { |
||
4737 | return( pBuffer[index] ); |
||
4738 | } |
||
4739 | |||
4740 | |||
4741 | /*************************************************** |
||
4742 | Function: |
||
4743 | BYTE ReadWord(BYTE * pBuffer, WORD index) |
||
4744 | Summary: |
||
4745 | Read a 16-bit word from a buffer |
||
4746 | Conditions: |
||
4747 | This function should not be called by the user. |
||
4748 | Input: |
||
4749 | pBuffer - pointer to a buffer to read from |
||
4750 | index - index in the buffer to read to |
||
4751 | Return: |
||
4752 | WORD - the word read |
||
4753 | Side Effects: |
||
4754 | None |
||
4755 | Description: |
||
4756 | Reads a 16-bit word from a buffer |
||
4757 | Remarks: |
||
4758 | None. |
||
4759 | ***************************************************/ |
||
4760 | |||
4761 | WORD ReadWord( BYTE* pBuffer, WORD index ) |
||
4762 | { |
||
4763 | BYTE loByte, hiByte; |
||
4764 | WORD res; |
||
4765 | |||
4766 | loByte = pBuffer[index]; |
||
4767 | hiByte = pBuffer[index+1]; |
||
4768 | res = hiByte; |
||
4769 | res *= 0x100; |
||
4770 | res |= loByte; |
||
4771 | return( res ); |
||
4772 | } |
||
4773 | |||
4774 | |||
4775 | /**************************************************** |
||
4776 | Function: |
||
4777 | BYTE ReadDWord(BYTE * pBuffer, WORD index) |
||
4778 | Summary: |
||
4779 | Read a 32-bit double word from a buffer |
||
4780 | Conditions: |
||
4781 | This function should not be called by the user. |
||
4782 | Input: |
||
4783 | pBuffer - pointer to a buffer to read from |
||
4784 | index - index in the buffer to read to |
||
4785 | Return: |
||
4786 | DWORD - the double word read |
||
4787 | Side Effects: |
||
4788 | None |
||
4789 | Description: |
||
4790 | Reads a 32-bit double word from a buffer |
||
4791 | Remarks: |
||
4792 | None. |
||
4793 | ****************************************************/ |
||
4794 | |||
4795 | DWORD ReadDWord( BYTE* pBuffer, WORD index ) |
||
4796 | { |
||
4797 | WORD loWord, hiWord; |
||
4798 | DWORD result; |
||
4799 | |||
4800 | loWord = ReadWord( pBuffer, index ); |
||
4801 | hiWord = ReadWord( pBuffer, index+2 ); |
||
4802 | |||
4803 | result = hiWord; |
||
4804 | result *= 0x10000; |
||
4805 | result |= loWord; |
||
4806 | return result; |
||
4807 | } |
||
4808 | |||
4809 | #endif |
||
4810 | |||
4811 | |||
4812 | |||
4813 | /**************************************************** |
||
4814 | Function: |
||
4815 | DWORD Cluster2Sector(DISK * dsk, DWORD cluster) |
||
4816 | Summary: |
||
4817 | Convert a cluster number to the corresponding sector |
||
4818 | Conditions: |
||
4819 | This function should not be called by the user. |
||
4820 | Input: |
||
4821 | disk - Disk structure |
||
4822 | cluster - Cluster to be converted |
||
4823 | Return: |
||
4824 | sector - Sector that corresponds to given cluster |
||
4825 | Side Effects: |
||
4826 | None |
||
4827 | Description: |
||
4828 | The Cluster2Sector function will calculate the |
||
4829 | sector number that corresponds to the first sector |
||
4830 | of the cluster whose value was passed into the |
||
4831 | function. |
||
4832 | Remarks: |
||
4833 | None. |
||
4834 | ****************************************************/ |
||
4835 | |||
4836 | DWORD Cluster2Sector(DISK * dsk, DWORD cluster) |
||
4837 | { |
||
4838 | DWORD sector; |
||
4839 | |||
4840 | /* Rt: Settings based on FAT type */ |
||
4841 | switch (dsk->type) |
||
4842 | { |
||
4843 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
4844 | case FAT32: |
||
4845 | /* In FAT32, there is no separate ROOT region. It is as well stored in DATA region */ |
||
4846 | sector = (((DWORD)cluster-2) * dsk->SecPerClus) + dsk->data; |
||
4847 | break; |
||
4848 | #endif |
||
4849 | case FAT12: |
||
4850 | case FAT16: |
||
4851 | default: |
||
4852 | // The root dir takes up cluster 0 and 1 |
||
4853 | if(cluster == 0 ||cluster == 1) |
||
4854 | sector = dsk->root + cluster; |
||
4855 | else |
||
4856 | sector = (((DWORD)cluster-2) * dsk->SecPerClus) + dsk->data; |
||
4857 | break; |
||
4858 | } |
||
4859 | |||
4860 | return(sector); |
||
4861 | |||
4862 | } |
||
4863 | |||
4864 | |||
4865 | /*************************************************************************** |
||
4866 | Function: |
||
4867 | int FSattrib (FSFILE * file, unsigned char attributes) |
||
4868 | Summary: |
||
4869 | Change the attributes of a file |
||
4870 | Conditions: |
||
4871 | File opened |
||
4872 | Input: |
||
4873 | file - Pointer to file structure |
||
4874 | attributes - The attributes to set for the file |
||
4875 | - Attribute - Value - Indications |
||
4876 | - ATTR_READ_ONLY - 0x01 - The read-only attribute |
||
4877 | - ATTR_HIDDEN - 0x02 - The hidden attribute |
||
4878 | - ATTR_SYSTEM - 0x04 - The system attribute |
||
4879 | - ATTR_ARCHIVE - 0x20 - The archive attribute |
||
4880 | Return Values: |
||
4881 | |||
4882 | -1 - Attribute change was unsuccessful |
||
4883 | Side Effects: |
||
4884 | The FSerrno variable will be changed. |
||
4885 | Description: |
||
4886 | The FSattrib funciton will set the attributes of the specified file |
||
4887 | to the attributes passed in by the user. This function will load the |
||
4888 | file entry, replace the attributes with the ones specified, and write |
||
4889 | the attributes back. If the specified file is a directory, the |
||
4890 | directory attribute will be preserved. |
||
4891 | Remarks: |
||
4892 | None |
||
4893 | ***************************************************************************/ |
||
4894 | |||
4895 | #ifdef ALLOW_WRITES |
||
4896 | int FSattrib (FSFILE * file, unsigned char attributes) |
||
4897 | { |
||
4898 | WORD fHandle; |
||
4899 | DIRENTRY dir; |
||
4900 | |||
4901 | FSerrno = CE_GOOD; |
||
4902 | |||
4903 | // Check for valid attributes |
||
4904 | if ((attributes & ~0x27) != 0) |
||
4905 | { |
||
4906 | FSerrno = CE_INVALID_ARGUMENT; |
||
4907 | return -1; |
||
4908 | } |
||
4909 | |||
4910 | fHandle = file->entry; |
||
4911 | |||
4912 | file->dirccls = file->dirclus; |
||
4913 | |||
4914 | // Get the file entry |
||
4915 | dir = LoadDirAttrib(file, &fHandle); |
||
4916 | |||
4917 | if (dir == NULL) |
||
4918 | { |
||
4919 | FSerrno = CE_BADCACHEREAD; |
||
4920 | return -1; |
||
4921 | } |
||
4922 | |||
4923 | // Ensure that we aren't trying to change the |
||
4924 | // attributes of a volume entry |
||
4925 | if (dir->DIR_Attr & ATTR_VOLUME) |
||
4926 | { |
||
4927 | FSerrno = CE_INVALID_ARGUMENT; |
||
4928 | return -1; |
||
4929 | } |
||
4930 | |||
4931 | // Don't remove the directory attribute from DIR files |
||
4932 | if (file->attributes & ATTR_DIRECTORY) |
||
4933 | file->attributes = attributes | ATTR_DIRECTORY; |
||
4934 | else |
||
4935 | file->attributes = attributes; |
||
4936 | |||
4937 | // just write the last entry in |
||
4938 | if(!Write_File_Entry(file,&fHandle)) |
||
4939 | { |
||
4940 | FSerrno = CE_WRITE_ERROR; |
||
4941 | return -1; |
||
4942 | } |
||
4943 | |||
4944 | return 0; |
||
4945 | } |
||
4946 | #endif |
||
4947 | |||
4948 | |||
4949 | /********************************************************************************* |
||
4950 | Function: |
||
4951 | size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream) |
||
4952 | Summary: |
||
4953 | Write data to a file |
||
4954 | Conditions: |
||
4955 | File opened in WRITE, APPEND, WRITE+, APPEND+, READ+ mode |
||
4956 | Input: |
||
4957 | ptr - Pointer to source buffer |
||
4958 | size - Size of units in bytes |
||
4959 | n - Number of units to transfer |
||
4960 | stream - Pointer to file structure |
||
4961 | Return: |
||
4962 | size_t - number of units written |
||
4963 | Side Effects: |
||
4964 | The FSerrno variable will be changed. |
||
4965 | Description: |
||
4966 | The FSfwrite function will write data to a file. First, the sector that |
||
4967 | corresponds to the current position in the file will be loaded (if it hasn't |
||
4968 | already been cached in the global data buffer). Data will then be written to |
||
4969 | the device from the specified buffer until the specified amount has been written. |
||
4970 | If the end of a cluster is reached, the next cluster will be loaded, unless |
||
4971 | the end-of-file flag for the specified file has been set. If it has, a new |
||
4972 | cluster will be allocated to the file. Finally, the new position and filezize |
||
4973 | will be stored in the FSFILE object. The parameters 'size' and 'n' indicate how |
||
4974 | much data to write. 'Size' refers to the size of one object to write (in bytes), |
||
4975 | and 'n' will refer to the number of these objects to write. The value returned |
||
4976 | will be equal to 'n' unless an error occured. |
||
4977 | Remarks: |
||
4978 | None. |
||
4979 | *********************************************************************************/ |
||
4980 | |||
4981 | #ifdef ALLOW_WRITES |
||
4982 | size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream) |
||
4983 | { |
||
4984 | DWORD count = size * n; |
||
4985 | BYTE * src = (BYTE *) ptr; |
||
4986 | DISK * dsk; // pointer to disk structure |
||
4987 | CETYPE error = CE_GOOD; |
||
4988 | WORD pos; |
||
4989 | DWORD l; // absolute lba of sector to load |
||
4990 | DWORD seek, filesize; |
||
4991 | WORD writeCount = 0; |
||
4992 | |||
4993 | // see if the file was opened in a write mode |
||
4994 | if(!(stream->flags.write)) |
||
4995 | { |
||
4996 | FSerrno = CE_READONLY; |
||
4997 | error = CE_WRITE_ERROR; |
||
4998 | return 0; |
||
4999 | } |
||
5000 | |||
5001 | if (count == 0) |
||
5002 | return 0; |
||
5003 | |||
5004 | if (MDD_WriteProtectState()) |
||
5005 | { |
||
5006 | FSerrno = CE_WRITE_PROTECTED; |
||
5007 | error = CE_WRITE_PROTECTED; |
||
5008 | return 0; |
||
5009 | } |
||
5010 | |||
5011 | gBufferZeroed = FALSE; |
||
5012 | dsk = stream->dsk; |
||
5013 | // get the stated position |
||
5014 | pos = stream->pos; |
||
5015 | seek = stream->seek; |
||
5016 | l = Cluster2Sector(dsk,stream->ccls); |
||
5017 | l += (WORD)stream->sec; // add the sector number to it |
||
5018 | |||
5019 | // Check if the current stream was the last one to use the |
||
5020 | // buffer. If not, check if we need to write data from the |
||
5021 | // old stream |
||
5022 | if (gBufferOwner != stream) |
||
5023 | { |
||
5024 | if (gNeedDataWrite) |
||
5025 | { |
||
5026 | if (flushData()) |
||
5027 | { |
||
5028 | FSerrno = CE_WRITE_ERROR; |
||
5029 | return 0; |
||
5030 | } |
||
5031 | } |
||
5032 | gBufferOwner = stream; |
||
5033 | } |
||
5034 | if (gLastDataSectorRead != l) |
||
5035 | { |
||
5036 | if (gNeedDataWrite) |
||
5037 | { |
||
5038 | if (flushData()) |
||
5039 | { |
||
5040 | FSerrno = CE_WRITE_ERROR; |
||
5041 | return 0; |
||
5042 | } |
||
5043 | } |
||
5044 | |||
5045 | gBufferZeroed = FALSE; |
||
5046 | if(!MDD_SectorRead( l, dsk->buffer) ) |
||
5047 | { |
||
5048 | FSerrno = CE_BADCACHEREAD; |
||
5049 | error = CE_BAD_SECTOR_READ; |
||
5050 | } |
||
5051 | gLastDataSectorRead = l; |
||
5052 | } |
||
5053 | // exit loop if EOF reached |
||
5054 | filesize = stream->size; |
||
5055 | |||
5056 | // Loop while writing bytes |
||
5057 | while (error == CE_GOOD && count > 0) |
||
5058 | { |
||
5059 | if( seek == filesize ) |
||
5060 | stream->flags.FileWriteEOF = TRUE; |
||
5061 | |||
5062 | // load a new sector if necessary, multiples of sector |
||
5063 | if (pos == dsk->sectorSize) |
||
5064 | { |
||
5065 | BYTE needRead = TRUE; |
||
5066 | |||
5067 | if (gNeedDataWrite) |
||
5068 | if (flushData()) |
||
5069 | { |
||
5070 | FSerrno = CE_WRITE_ERROR; |
||
5071 | return 0; |
||
5072 | } |
||
5073 | |||
5074 | // reset position |
||
5075 | pos = 0; |
||
5076 | |||
5077 | // point to the next sector |
||
5078 | stream->sec++; |
||
5079 | |||
5080 | // get a new cluster if necessary |
||
5081 | if (stream->sec == dsk->SecPerClus) |
||
5082 | { |
||
5083 | stream->sec = 0; |
||
5084 | |||
5085 | if(stream->flags.FileWriteEOF) |
||
5086 | { |
||
5087 | error = FILEallocate_new_cluster(stream, 0); // add new cluster to the file |
||
5088 | needRead = FALSE; |
||
5089 | } |
||
5090 | else |
||
5091 | error = FILEget_next_cluster( stream, 1); |
||
5092 | } |
||
5093 | |||
5094 | if (error == CE_DISK_FULL) |
||
5095 | { |
||
5096 | FSerrno = CE_DISK_FULL; |
||
5097 | return 0; |
||
5098 | } |
||
5099 | |||
5100 | if(error == CE_GOOD) |
||
5101 | { |
||
5102 | l = Cluster2Sector(dsk,stream->ccls); |
||
5103 | l += (WORD)stream->sec; // add the sector number to it |
||
5104 | gBufferOwner = stream; |
||
5105 | // If we just allocated a new cluster, then the cluster will |
||
5106 | // contain garbage data, so it doesn't matter what we write to it |
||
5107 | // Whatever is in the buffer will work fine |
||
5108 | if (needRead) |
||
5109 | { |
||
5110 | if( !MDD_SectorRead( l, dsk->buffer) ) |
||
5111 | { |
||
5112 | FSerrno = CE_BADCACHEREAD; |
||
5113 | error = CE_BAD_SECTOR_READ; |
||
5114 | gLastDataSectorRead = 0xFFFFFFFF; |
||
5115 | return 0; |
||
5116 | } |
||
5117 | else |
||
5118 | { |
||
5119 | gLastDataSectorRead = l; |
||
5120 | } |
||
5121 | } |
||
5122 | else |
||
5123 | gLastDataSectorRead = l; |
||
5124 | } |
||
5125 | } // load new sector |
||
5126 | |||
5127 | if(error == CE_GOOD) |
||
5128 | { |
||
5129 | // Write one byte at a time |
||
5130 | RAMwrite(dsk->buffer, pos++, *(char *)src); |
||
5131 | src = src + 1; // compiler bug |
||
5132 | seek++; |
||
5133 | count--; |
||
5134 | writeCount++; |
||
5135 | // now increment the size of the part |
||
5136 | if(stream->flags.FileWriteEOF) |
||
5137 | filesize++; |
||
5138 | gNeedDataWrite = TRUE; |
||
5139 | } |
||
5140 | } // while count |
||
5141 | |||
5142 | // save off the positon |
||
5143 | stream->pos = pos; |
||
5144 | |||
5145 | // save off the seek |
||
5146 | stream->seek = seek; |
||
5147 | |||
5148 | // now the new size |
||
5149 | stream->size = filesize; |
||
5150 | |||
5151 | return(writeCount / size); |
||
5152 | } // fwrite |
||
5153 | #endif |
||
5154 | |||
5155 | |||
5156 | /********************************************************** |
||
5157 | Function: |
||
5158 | BYTE flushData (void) |
||
5159 | Summary: |
||
5160 | Flush unwritten data to a file |
||
5161 | Conditions: |
||
5162 | File opened in a write mode, data needs to be written |
||
5163 | Return Values: |
||
5164 | CE_GOOD - Data was updated successfully |
||
5165 | CE_WRITE_ERROR - Data could not be updated |
||
5166 | Side Effects: |
||
5167 | None |
||
5168 | Description: |
||
5169 | The flushData function is called when it is necessary to |
||
5170 | read new data into the global data buffer and the |
||
5171 | gNeedDataWrite variable indicates that there is data |
||
5172 | in the buffer that hasn't been written to the device. |
||
5173 | The flushData function will write the data from the |
||
5174 | buffer into the current cluster of the FSFILE object |
||
5175 | that is stored in the gBufferOwner global variable. |
||
5176 | Remarks: |
||
5177 | None |
||
5178 | **********************************************************/ |
||
5179 | |||
5180 | #ifdef ALLOW_WRITES |
||
5181 | BYTE flushData (void) |
||
5182 | { |
||
5183 | DWORD l; |
||
5184 | DISK * dsk; |
||
5185 | |||
5186 | // This will either be the pointer to the last file, or the handle |
||
5187 | FILEOBJ stream = gBufferOwner; |
||
5188 | |||
5189 | dsk = stream->dsk; |
||
5190 | |||
5191 | // figure out the lba |
||
5192 | l = Cluster2Sector(dsk,stream->ccls); |
||
5193 | l += (WORD)stream->sec; // add the sector number to it |
||
5194 | |||
5195 | if(!MDD_SectorWrite( l, dsk->buffer, FALSE)) |
||
5196 | { |
||
5197 | return CE_WRITE_ERROR; |
||
5198 | } |
||
5199 | |||
5200 | gNeedDataWrite = FALSE; |
||
5201 | |||
5202 | return CE_GOOD; |
||
5203 | } |
||
5204 | #endif |
||
5205 | |||
5206 | /**************************************************** |
||
5207 | Function: |
||
5208 | int FSfeof( FSFILE * stream ) |
||
5209 | Summary: |
||
5210 | Indicate whether the current file position is at the end |
||
5211 | Conditions: |
||
5212 | File is open in a read mode |
||
5213 | Input: |
||
5214 | stream - Pointer to the target file |
||
5215 | Return Values: |
||
5216 | Non-Zero - EOF reached |
||
5217 | |||
5218 | Side Effects: |
||
5219 | The FSerrno variable will be changed. |
||
5220 | Description: |
||
5221 | The FSfeof function will indicate that the end-of- |
||
5222 | file has been reached for the specified file by |
||
5223 | comparing the absolute location in the file to the |
||
5224 | size of the file. |
||
5225 | Remarks: |
||
5226 | None. |
||
5227 | ****************************************************/ |
||
5228 | |||
5229 | int FSfeof( FSFILE * stream ) |
||
5230 | { |
||
5231 | FSerrno = CE_GOOD; |
||
5232 | return( stream->seek == stream->size ); |
||
5233 | } |
||
5234 | |||
5235 | |||
5236 | /************************************************************************** |
||
5237 | Function: |
||
5238 | size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream) |
||
5239 | Summary: |
||
5240 | Read data from a file |
||
5241 | Conditions: |
||
5242 | File is opened in a read mode |
||
5243 | Input: |
||
5244 | ptr - Destination buffer for read bytes |
||
5245 | size - Size of units in bytes |
||
5246 | n - Number of units to be read |
||
5247 | stream - File to be read from |
||
5248 | Return: |
||
5249 | size_t - number of units read |
||
5250 | Side Effects: |
||
5251 | The FSerrno variable will be changed. |
||
5252 | Description: |
||
5253 | The FSfread function will read data from the specified file. First, |
||
5254 | the appropriate sector of the file is loaded. Then, data is read into |
||
5255 | the specified buffer until the specified number of bytes have been read. |
||
5256 | When a cluster boundary is reached, a new cluster will be loaded. The |
||
5257 | parameters 'size' and 'n' indicate how much data to read. 'Size' |
||
5258 | refers to the size of one object to read (in bytes), and 'n' will refer |
||
5259 | to the number of these objects to read. The value returned will be equal |
||
5260 | to 'n' unless an error occured or the user tried to read beyond the end |
||
5261 | of the file. |
||
5262 | Remarks: |
||
5263 | None. |
||
5264 | **************************************************************************/ |
||
5265 | |||
5266 | size_t FSfread (void *ptr, size_t size, size_t n, FSFILE *stream) |
||
5267 | { |
||
5268 | DWORD len = size * n; |
||
5269 | BYTE *pointer = (BYTE *) ptr; |
||
5270 | DISK *dsk; // Disk structure |
||
5271 | DWORD seek, sec_sel; |
||
5272 | WORD pos; //position within sector |
||
5273 | CETYPE error = CE_GOOD; |
||
5274 | WORD readCount = 0; |
||
5275 | |||
5276 | FSerrno = CE_GOOD; |
||
5277 | |||
5278 | dsk = (DISK *)stream->dsk; |
||
5279 | pos = stream->pos; |
||
5280 | seek = stream->seek; |
||
5281 | |||
5282 | if( !stream->flags.read ) |
||
5283 | { |
||
5284 | FSerrno = CE_WRITEONLY; |
||
5285 | return 0; // CE_WRITEONLY |
||
5286 | } |
||
5287 | |||
5288 | #ifdef ALLOW_WRITES |
||
5289 | if (gNeedDataWrite) |
||
5290 | if (flushData()) |
||
5291 | { |
||
5292 | FSerrno = CE_WRITE_ERROR; |
||
5293 | return 0; |
||
5294 | } |
||
5295 | #endif |
||
5296 | |||
5297 | // if it not my buffer, then get it from the disk. |
||
5298 | if( (gBufferOwner != stream) && (pos != dsk->sectorSize)) |
||
5299 | { |
||
5300 | gBufferOwner = stream; |
||
5301 | sec_sel = Cluster2Sector(dsk,stream->ccls); |
||
5302 | sec_sel += (WORD)stream->sec; // add the sector number to it |
||
5303 | |||
5304 | gBufferZeroed = FALSE; |
||
5305 | if( !MDD_SectorRead( sec_sel, dsk->buffer) ) |
||
5306 | { |
||
5307 | FSerrno = CE_BAD_SECTOR_READ; |
||
5308 | error = CE_BAD_SECTOR_READ; |
||
5309 | return 0; |
||
5310 | } |
||
5311 | gLastDataSectorRead = sec_sel; |
||
5312 | } |
||
5313 | |||
5314 | //loop reading (count) bytes |
||
5315 | while( len ) |
||
5316 | { |
||
5317 | if( seek == stream->size ) |
||
5318 | { |
||
5319 | FSerrno = CE_EOF; |
||
5320 | error = CE_EOF; |
||
5321 | break; |
||
5322 | } |
||
5323 | |||
5324 | // In fopen, pos is init to 0 and the sect is loaded |
||
5325 | if( pos == dsk->sectorSize ) |
||
5326 | { |
||
5327 | // reset position |
||
5328 | pos = 0; |
||
5329 | // point to the next sector |
||
5330 | stream->sec++; |
||
5331 | |||
5332 | // get a new cluster if necessary |
||
5333 | if( stream->sec == dsk->SecPerClus ) |
||
5334 | { |
||
5335 | stream->sec = 0; |
||
5336 | if( (error = FILEget_next_cluster( stream, 1)) != CE_GOOD ) |
||
5337 | { |
||
5338 | FSerrno = CE_COULD_NOT_GET_CLUSTER; |
||
5339 | break; |
||
5340 | } |
||
5341 | } |
||
5342 | |||
5343 | sec_sel = Cluster2Sector(dsk,stream->ccls); |
||
5344 | sec_sel += (WORD)stream->sec; // add the sector number to it |
||
5345 | |||
5346 | |||
5347 | gBufferOwner = stream; |
||
5348 | gBufferZeroed = FALSE; |
||
5349 | if( !MDD_SectorRead( sec_sel, dsk->buffer) ) |
||
5350 | { |
||
5351 | FSerrno = CE_BAD_SECTOR_READ; |
||
5352 | error = CE_BAD_SECTOR_READ; |
||
5353 | break; |
||
5354 | } |
||
5355 | gLastDataSectorRead = sec_sel; |
||
5356 | } |
||
5357 | |||
5358 | // copy one byte at a time |
||
5359 | *pointer = RAMread( dsk->buffer, pos++ ); |
||
5360 | pointer++; |
||
5361 | seek++; |
||
5362 | readCount++; |
||
5363 | len--; |
||
5364 | } |
||
5365 | |||
5366 | // save off the positon |
||
5367 | stream->pos = pos; |
||
5368 | // save off the seek |
||
5369 | stream->seek = seek; |
||
5370 | |||
5371 | return(readCount / size); |
||
5372 | } // fread |
||
5373 | |||
5374 | |||
5375 | /*************************************************************************** |
||
5376 | Function: |
||
5377 | BYTE FormatFileName( const char* fileName, char* fN2, BYTE mode ) |
||
5378 | Summary: |
||
5379 | Format a file name into dir entry format |
||
5380 | Conditions: |
||
5381 | This function should not be called by the user. |
||
5382 | Input: |
||
5383 | fileName - The name to be formatted |
||
5384 | fN2 - The location the formatted name will be stored |
||
5385 | mode - Non-zero if parital string search chars are allowed |
||
5386 | Return Values: |
||
5387 | TRUE - Name formatted successfully |
||
5388 | FALSE - File name could not be formatted |
||
5389 | Side Effects: |
||
5390 | None |
||
5391 | Description: |
||
5392 | Format an 8.3 filename into FSFILE structure format. If filename is less |
||
5393 | than 8 chars, then it will be padded with spaces. If the extension name is |
||
5394 | fewer than 3 chars, then it will also be oadded with spaces. The |
||
5395 | ValidateChars function is used to ensure the characters in the specified |
||
5396 | filename are valid in this filesystem. |
||
5397 | Remarks: |
||
5398 | None. |
||
5399 | ***************************************************************************/ |
||
5400 | BYTE FormatFileName( const char* fileName, char* fN2, BYTE mode) |
||
5401 | { |
||
5402 | char * pExt; |
||
5403 | WORD temp; |
||
5404 | char szName[15]; |
||
5405 | BYTE count; |
||
5406 | |||
5407 | for (count = 0; count < 11; count++) |
||
5408 | { |
||
5409 | *(fN2 + count) = ' '; // Load destination filename to be space intially. |
||
5410 | } |
||
5411 | |||
5412 | // Make sure we dont have an empty string or a name with only |
||
5413 | // an extension |
||
5414 | if (fileName[0] == '.' || fileName[0] == 0) |
||
5415 | return FALSE; |
||
5416 | |||
5417 | temp = strlen( fileName ); |
||
5418 | |||
5419 | if( temp <= TOTAL_FILE_SIZE ) // 8+3+1 |
||
5420 | strcpy( szName, fileName ); // copy to RAM in case fileName is located in flash |
||
5421 | else |
||
5422 | return FALSE; //long file name |
||
5423 | |||
5424 | // Make sure the characters are valid |
||
5425 | if ( !ValidateChars(szName, mode) ) |
||
5426 | return FALSE; |
||
5427 | |||
5428 | //Look for '.' in the szName |
||
5429 | if( (pExt = strchr( szName, '.' )) != 0 ) |
||
5430 | { |
||
5431 | *pExt = 0; // Assigning NULL here makes the "szName" to be terminated and "pExt" pointer to hold only extn characters. |
||
5432 | pExt++; // now pointing to extension |
||
5433 | |||
5434 | if( strlen( pExt ) > 3 ) // make sure the extension is 3 bytes or fewer |
||
5435 | return FALSE; |
||
5436 | } |
||
5437 | |||
5438 | if( strlen(szName) > 8 ) |
||
5439 | return FALSE; |
||
5440 | |||
5441 | //copy file name |
||
5442 | for (count = 0; count < strlen(szName); count++) |
||
5443 | { |
||
5444 | *(fN2 + count) = * (szName + count); // Destination filename initially filled with SPACE. Now copy only available chars. |
||
5445 | } |
||
5446 | |||
5447 | //copy extension |
||
5448 | if(pExt && *pExt ) |
||
5449 | { |
||
5450 | for (count = 0; count < strlen (pExt); count++) |
||
5451 | { |
||
5452 | *(fN2 + count + 8) = *(pExt + count); // Copy the extn to 8th position onwards. Ex: "FILE .Tx " |
||
5453 | } |
||
5454 | } |
||
5455 | |||
5456 | return TRUE; |
||
5457 | } |
||
5458 | |||
5459 | #ifdef ALLOW_DIRS |
||
5460 | |||
5461 | /************************************************************************* |
||
5462 | Function: |
||
5463 | BYTE FormatDirName (char * string, BYTE mode) |
||
5464 | Summary: |
||
5465 | Format a dir name into dir entry format |
||
5466 | Conditions: |
||
5467 | This function should not be called by the user. |
||
5468 | Input: |
||
5469 | string - The name to be formatted |
||
5470 | mode - |
||
5471 | - TRUE - Partial string search characters are allowed |
||
5472 | - FALSE - Partial string search characters are forbidden |
||
5473 | Return Values: |
||
5474 | TRUE - The name was formatted correctly |
||
5475 | FALSE - The name contained invalid characters |
||
5476 | Side Effects: |
||
5477 | None |
||
5478 | Description: |
||
5479 | Format an 8.3 filename into directory structure format. If the name is less |
||
5480 | than 8 chars, then it will be padded with spaces. If the extension name is |
||
5481 | fewer than 3 chars, then it will also be oadded with spaces. The |
||
5482 | ValidateChars function is used to ensure the characters in the specified |
||
5483 | directory name are valid in this filesystem. |
||
5484 | Remarks: |
||
5485 | None. |
||
5486 | *************************************************************************/ |
||
5487 | |||
5488 | BYTE FormatDirName (char * string, BYTE mode) |
||
5489 | { |
||
5490 | unsigned char i, j; |
||
5491 | char tempString [12]; |
||
5492 | |||
5493 | if (ValidateChars (string, mode) == FALSE) |
||
5494 | return FALSE; |
||
5495 | |||
5496 | for (i = 0; (i < 8) && (*(string + i) != '.') && (*(string + i) != 0); i++) |
||
5497 | { |
||
5498 | tempString[i] = *(string + i); |
||
5499 | } |
||
5500 | |||
5501 | j = i; |
||
5502 | |||
5503 | while (i < 8) |
||
5504 | { |
||
5505 | tempString [i++] = 0x20; |
||
5506 | } |
||
5507 | |||
5508 | if (*(string + j) == '.') |
||
5509 | { |
||
5510 | j++; |
||
5511 | while (*(string + j) != 0) |
||
5512 | { |
||
5513 | tempString[i++] = *(string + j++); |
||
5514 | } |
||
5515 | } |
||
5516 | |||
5517 | while (i < 11) |
||
5518 | { |
||
5519 | tempString[i++] = 0x20; |
||
5520 | } |
||
5521 | |||
5522 | tempString[11] = 0; |
||
5523 | |||
5524 | // Forbidden |
||
5525 | if (tempString[0] == 0x20) |
||
5526 | { |
||
5527 | tempString[0] = '_'; |
||
5528 | } |
||
5529 | |||
5530 | for (i = 0; i < 12; i++) |
||
5531 | { |
||
5532 | *(string + i) = tempString[i]; |
||
5533 | } |
||
5534 | |||
5535 | return TRUE; |
||
5536 | } |
||
5537 | #endif |
||
5538 | |||
5539 | |||
5540 | /************************************************************* |
||
5541 | Function: |
||
5542 | BYTE ValidateChars( char * FileName, BYTE mode) |
||
5543 | Summary: |
||
5544 | Validate the characters in a given file name |
||
5545 | Conditions: |
||
5546 | This function should not be called by the user. |
||
5547 | Input: |
||
5548 | fileName - The name to be validated |
||
5549 | mode - Determines if partial string search is allowed |
||
5550 | Return Values: |
||
5551 | TRUE - Name was validated |
||
5552 | FALSE - File name was not valid |
||
5553 | Side Effects: |
||
5554 | None |
||
5555 | Description: |
||
5556 | The ValidateChars function will compare characters in a |
||
5557 | specified filename to determine if they're permissable |
||
5558 | in the FAT file system. Lower-case characters will be |
||
5559 | converted to upper-case. If the mode argument is specifed |
||
5560 | to be 'TRUE,' partial string search characters are allowed. |
||
5561 | Remarks: |
||
5562 | None. |
||
5563 | *************************************************************/ |
||
5564 | BYTE ValidateChars( char * FileName , BYTE mode) |
||
5565 | { |
||
5566 | int StrSz, index; |
||
5567 | unsigned char radix = FALSE; |
||
5568 | |||
5569 | StrSz = strlen(FileName); |
||
5570 | |||
5571 | for( index = 0; index < StrSz; index++ ) |
||
5572 | { |
||
5573 | if (((FileName[index] <= 0x20) && (FileName[index] != 0x05)) || |
||
5574 | (FileName[index] == 0x22) || (FileName[index] == 0x2B) || |
||
5575 | (FileName[index] == 0x2C) || (FileName[index] == 0x2F) || |
||
5576 | (FileName[index] == 0x3A) || (FileName[index] == 0x3B) || |
||
5577 | (FileName[index] == 0x3C) || (FileName[index] == 0x3D) || |
||
5578 | (FileName[index] == 0x3E) || (FileName[index] == 0x5B) || |
||
5579 | (FileName[index] == 0x5C) || (FileName[index] == 0x5D) || |
||
5580 | (FileName[index] == 0x7C) || ((FileName[index] == 0x2E) && radix == TRUE)) |
||
5581 | { |
||
5582 | return FALSE; |
||
5583 | } |
||
5584 | else |
||
5585 | { |
||
5586 | // Check for partial string search chars |
||
5587 | if (mode == FALSE) |
||
5588 | { |
||
5589 | if ((FileName[index] == '*') || (FileName[index] == '?')) |
||
5590 | return FALSE; |
||
5591 | } |
||
5592 | // only one radix ('.') character is allowed |
||
5593 | if (FileName[index] == 0x2E) |
||
5594 | { |
||
5595 | radix = TRUE; |
||
5596 | } |
||
5597 | // Convert lower-case to upper-case |
||
5598 | if ((FileName[index] >= 0x61) && (FileName[index] <= 0x7A)) |
||
5599 | FileName[index] -= 0x20; |
||
5600 | } |
||
5601 | } |
||
5602 | return TRUE; |
||
5603 | } |
||
5604 | |||
5605 | |||
5606 | /********************************************************************** |
||
5607 | Function: |
||
5608 | int FSfseek(FSFILE *stream, long offset, int whence) |
||
5609 | Summary: |
||
5610 | Change the current position in a file |
||
5611 | Conditions: |
||
5612 | File opened |
||
5613 | Input: |
||
5614 | stream - Pointer to file structure |
||
5615 | offset - Offset from base location |
||
5616 | whence - |
||
5617 | - SEEK_SET - Seek from start of file |
||
5618 | - SEEK_CUR - Seek from current location |
||
5619 | - SEEK_END - Seek from end of file (subtract offset) |
||
5620 | Return Values: |
||
5621 | |||
5622 | -1 - Operation unsuccesful |
||
5623 | Side Effects: |
||
5624 | The FSerrno variable will be changed. |
||
5625 | Description: |
||
5626 | The FSfseek function will change the current position in the file to |
||
5627 | one specified by the user. First, an absolute offset is calculated |
||
5628 | using the offset and base location passed in by the user. Then, the |
||
5629 | position variables are updated, and the sector number that corresponds |
||
5630 | to the new location. That sector is then loaded. If the offset |
||
5631 | falls exactly on a cluster boundary, a new cluster will be allocated |
||
5632 | to the file and the position will be set to the first byte of that |
||
5633 | cluster. |
||
5634 | Remarks: |
||
5635 | None |
||
5636 | **********************************************************************/ |
||
5637 | |||
5638 | int FSfseek(FSFILE *stream, long offset, int whence) |
||
5639 | { |
||
5640 | DWORD numsector, temp; // lba of first sector of first cluster |
||
5641 | DISK* dsk; // pointer to disk structure |
||
5642 | BYTE test; |
||
5643 | long offset2 = offset; |
||
5644 | |||
5645 | dsk = stream->dsk; |
||
5646 | |||
5647 | switch(whence) |
||
5648 | { |
||
5649 | case SEEK_CUR: |
||
5650 | // Apply the offset to the current position |
||
5651 | offset2 += stream->seek; |
||
5652 | break; |
||
5653 | case SEEK_END: |
||
5654 | // Apply the offset to the end of the file |
||
5655 | offset2 = stream->size - offset2; |
||
5656 | break; |
||
5657 | case SEEK_SET: |
||
5658 | // automatically there |
||
5659 | default: |
||
5660 | break; |
||
5661 | } |
||
5662 | |||
5663 | #ifdef ALLOW_WRITES |
||
5664 | if (gNeedDataWrite) |
||
5665 | if (flushData()) |
||
5666 | { |
||
5667 | FSerrno = CE_WRITE_ERROR; |
||
5668 | return EOF; |
||
5669 | } |
||
5670 | #endif |
||
5671 | |||
5672 | // start from the beginning |
||
5673 | temp = stream->cluster; |
||
5674 | stream->ccls = temp; |
||
5675 | |||
5676 | temp = stream->size; |
||
5677 | |||
5678 | if (offset2 > temp) |
||
5679 | { |
||
5680 | FSerrno = CE_INVALID_ARGUMENT; |
||
5681 | return (-1); // past the limits |
||
5682 | } |
||
5683 | else |
||
5684 | { |
||
5685 | // if we are writing we are no longer at the end |
||
5686 | stream->flags.FileWriteEOF = FALSE; |
||
5687 | |||
5688 | // set the new postion |
||
5689 | stream->seek = offset2; |
||
5690 | |||
5691 | // figure out how many sectors |
||
5692 | numsector = offset2 / dsk->sectorSize; |
||
5693 | |||
5694 | // figure out how many bytes off of the offset |
||
5695 | offset2 = offset2 - (numsector * dsk->sectorSize); |
||
5696 | stream->pos = offset2; |
||
5697 | |||
5698 | // figure out how many clusters |
||
5699 | temp = numsector / dsk->SecPerClus; |
||
5700 | |||
5701 | // figure out the stranded sectors |
||
5702 | numsector = numsector - (dsk->SecPerClus * temp); |
||
5703 | stream->sec = numsector; |
||
5704 | |||
5705 | // if we are in the current cluster stay there |
||
5706 | if (temp > 0) |
||
5707 | { |
||
5708 | test = FILEget_next_cluster(stream, temp); |
||
5709 | if (test != CE_GOOD) |
||
5710 | { |
||
5711 | if (test == CE_FAT_EOF) |
||
5712 | { |
||
5713 | #ifdef ALLOW_WRITES |
||
5714 | if (stream->flags.write) |
||
5715 | { |
||
5716 | // load the previous cluster |
||
5717 | stream->ccls = stream->cluster; |
||
5718 | // Don't perform this operation if there's only one cluster |
||
5719 | if (temp != 1) |
||
5720 | test = FILEget_next_cluster(stream, temp - 1); |
||
5721 | if (FILEallocate_new_cluster(stream, 0) != CE_GOOD) |
||
5722 | { |
||
5723 | FSerrno = CE_COULD_NOT_GET_CLUSTER; |
||
5724 | return -1; |
||
5725 | } |
||
5726 | // sec and pos should already be zero |
||
5727 | } |
||
5728 | else |
||
5729 | { |
||
5730 | #endif |
||
5731 | stream->ccls = stream->cluster; |
||
5732 | test = FILEget_next_cluster(stream, temp - 1); |
||
5733 | if (test != CE_GOOD) |
||
5734 | { |
||
5735 | FSerrno = CE_COULD_NOT_GET_CLUSTER; |
||
5736 | return (-1); |
||
5737 | } |
||
5738 | stream->pos = dsk->sectorSize; |
||
5739 | stream->sec = dsk->SecPerClus - 1; |
||
5740 | #ifdef ALLOW_WRITES |
||
5741 | } |
||
5742 | #endif |
||
5743 | } |
||
5744 | else |
||
5745 | { |
||
5746 | FSerrno = CE_COULD_NOT_GET_CLUSTER; |
||
5747 | return (-1); // past the limits |
||
5748 | } |
||
5749 | } |
||
5750 | } |
||
5751 | |||
5752 | // Determine the lba of the selected sector and load |
||
5753 | temp = Cluster2Sector(dsk,stream->ccls); |
||
5754 | |||
5755 | // now the extra sectors |
||
5756 | numsector = stream->sec; |
||
5757 | temp += numsector; |
||
5758 | |||
5759 | gBufferOwner = NULL; |
||
5760 | gBufferZeroed = FALSE; |
||
5761 | if( !MDD_SectorRead(temp, dsk->buffer) ) |
||
5762 | { |
||
5763 | FSerrno = CE_BADCACHEREAD; |
||
5764 | return (-1); // Bad read |
||
5765 | } |
||
5766 | gLastDataSectorRead = temp; |
||
5767 | } |
||
5768 | |||
5769 | FSerrno = CE_GOOD; |
||
5770 | |||
5771 | return (0); |
||
5772 | } |
||
5773 | |||
5774 | |||
5775 | // FSfopenpgm, FSremovepgm, and FSrenamepgm will only work on PIC18s |
||
5776 | #ifdef __18CXX |
||
5777 | #ifdef ALLOW_PGMFUNCTIONS |
||
5778 | |||
5779 | #ifdef ALLOW_WRITES |
||
5780 | |||
5781 | /***************************************************************** |
||
5782 | Function: |
||
5783 | int FSrenamepgm(const rom char * fileName, FSFILE * fo) |
||
5784 | Summary: |
||
5785 | Rename a file named with a ROM string on PIC18 |
||
5786 | Conditions: |
||
5787 | File opened. |
||
5788 | Input: |
||
5789 | fileName - The new name of the file (in ROM) |
||
5790 | fo - The file to rename |
||
5791 | Return Values: |
||
5792 | |||
5793 | -1 - File could not be renamed |
||
5794 | Side Effects: |
||
5795 | The FSerrno variable will be changed. |
||
5796 | Description: |
||
5797 | The Fsrenamepgm function will copy the rom fileName specified |
||
5798 | by the user into a RAM array and pass that array into the |
||
5799 | FSrename function. |
||
5800 | Remarks: |
||
5801 | This function is for use with PIC18 when passing arguments in ROM. |
||
5802 | *****************************************************************/ |
||
5803 | |||
5804 | int FSrenamepgm (const rom char * fileName, FSFILE * fo) |
||
5805 | { |
||
5806 | char F[13]; |
||
5807 | BYTE count; |
||
5808 | |||
5809 | for (count = 0; count < 13; count++) |
||
5810 | { |
||
5811 | F[count] = *(fileName + count); |
||
5812 | } |
||
5813 | |||
5814 | return FSrename (F, fo); |
||
5815 | } |
||
5816 | #endif |
||
5817 | |||
5818 | /****************************************************************************** |
||
5819 | Function: |
||
5820 | FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode) |
||
5821 | Summary: |
||
5822 | Open a file named with a ROM string on PIC18 |
||
5823 | Conditions: |
||
5824 | For read modes, file exists; FSInit performed |
||
5825 | Input: |
||
5826 | fileName - The name of the file to be opened (ROM) |
||
5827 | mode - The mode the file will be opened in (ROM) |
||
5828 | Return Values: |
||
5829 | FSFILE * - A pointer to the file object |
||
5830 | NULL - File could not be opened |
||
5831 | Side Effects: |
||
5832 | The FSerrno variable will be changed. |
||
5833 | Description: |
||
5834 | The FSfopenpgm function will copy a PIC18 ROM fileName and mode argument |
||
5835 | into RAM arrays, and then pass those arrays to the FSfopen function. |
||
5836 | Remarks: |
||
5837 | This function is for use with PIC18 when passing arguments in ROM. |
||
5838 | ******************************************************************************/ |
||
5839 | |||
5840 | |||
5841 | FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode) |
||
5842 | { |
||
5843 | char F[13]; |
||
5844 | char M[2]; |
||
5845 | BYTE count; |
||
5846 | |||
5847 | for (count = 0; count < 13; count++) |
||
5848 | { |
||
5849 | F[count] = *(fileName + count); |
||
5850 | } |
||
5851 | for (count = 0; count < 2; count++) |
||
5852 | { |
||
5853 | M[count] = *(mode + count); |
||
5854 | } |
||
5855 | |||
5856 | return FSfopen(F, M); |
||
5857 | } |
||
5858 | |||
5859 | /************************************************************* |
||
5860 | Function: |
||
5861 | int FSremovepgm (const rom char * fileName) |
||
5862 | Summary: |
||
5863 | Delete a file named with a ROM string on PIC18 |
||
5864 | Conditions: |
||
5865 | File not opened; file exists |
||
5866 | Input: |
||
5867 | fileName - The name of the file to be deleted (ROM) |
||
5868 | Return Values: |
||
5869 | |||
5870 | -1 - File could not be removed |
||
5871 | Side Effects: |
||
5872 | The FSerrno variable will be changed. |
||
5873 | Description: |
||
5874 | The FSremovepgm function will copy a PIC18 ROM fileName argument |
||
5875 | into a RAM array, and then pass that array to the FSremove function. |
||
5876 | Remarks: |
||
5877 | This function is for use with PIC18 when passing arguments in ROM. |
||
5878 | *************************************************************/ |
||
5879 | #ifdef ALLOW_WRITES |
||
5880 | int FSremovepgm (const rom char * fileName) |
||
5881 | { |
||
5882 | char F[13]; |
||
5883 | BYTE count; |
||
5884 | |||
5885 | *fileName; |
||
5886 | for(count = 0; count < sizeof(F); count++) |
||
5887 | { |
||
5888 | _asm TBLRDPOSTINC _endasm |
||
5889 | F[count] = TABLAT; |
||
5890 | }//end for(...) |
||
5891 | |||
5892 | return FSremove (F); |
||
5893 | } |
||
5894 | #endif |
||
5895 | |||
5896 | /************************************************************************************** |
||
5897 | Function: |
||
5898 | int FindFirstpgm (const char * fileName, unsigned int attr, SearchRec * rec) |
||
5899 | Summary: |
||
5900 | Find a file named with a ROM string on PIC18 |
||
5901 | Conditions: |
||
5902 | None |
||
5903 | Input: |
||
5904 | fileName - The name of the file to be found (ROM) |
||
5905 | attr - The attributes of the file to be found |
||
5906 | rec - Pointer to a search record to store the file info in |
||
5907 | Return Values: |
||
5908 | |||
5909 | -1 - No file matching the given parameters was found |
||
5910 | Side Effects: |
||
5911 | Search criteria from previous FindFirst call on passed SearchRec object will be lost. |
||
5912 | The FSerrno variable will be changed. |
||
5913 | Description: |
||
5914 | The FindFirstpgm function will copy a PIC18 ROM fileName argument |
||
5915 | into a RAM array, and then pass that array to the FindFirst function. |
||
5916 | Remarks: |
||
5917 | Call FindFirstpgm or FindFirst before calling FindNext. |
||
5918 | This function is for use with PIC18 when passing arguments in ROM. |
||
5919 | **************************************************************************************/ |
||
5920 | #ifdef ALLOW_FILESEARCH |
||
5921 | int FindFirstpgm (const rom char * fileName, unsigned int attr, SearchRec * rec) |
||
5922 | { |
||
5923 | char F[13]; |
||
5924 | BYTE count; |
||
5925 | |||
5926 | *fileName; |
||
5927 | for(count = 0; count < sizeof(F); count++) |
||
5928 | { |
||
5929 | _asm TBLRDPOSTINC _endasm |
||
5930 | F[count] = TABLAT; |
||
5931 | }//end for |
||
5932 | |||
5933 | return FindFirst (F,attr,rec); |
||
5934 | } |
||
5935 | #endif |
||
5936 | #endif |
||
5937 | #endif |
||
5938 | |||
5939 | |||
5940 | /*********************************************** |
||
5941 | Function: |
||
5942 | DWORD ReadFAT (DISK *dsk, DWORD ccls) |
||
5943 | Summary: |
||
5944 | Read the next entry from the FAT |
||
5945 | Conditions: |
||
5946 | This function should not be called by the user. |
||
5947 | Input: |
||
5948 | dsk - The disk structure |
||
5949 | ccls - The current cluster |
||
5950 | Return: |
||
5951 | DWORD - The next cluster in a file chain |
||
5952 | Side Effects: |
||
5953 | None |
||
5954 | Description: |
||
5955 | The ReadFAT function will read the FAT and |
||
5956 | determine the next cluster value after the |
||
5957 | cluster specified by 'ccls.' Note that the |
||
5958 | FAT sector that is read is stored in the |
||
5959 | global FAT cache buffer. |
||
5960 | Remarks: |
||
5961 | None. |
||
5962 | ***********************************************/ |
||
5963 | |||
5964 | DWORD ReadFAT (DISK *dsk, DWORD ccls) |
||
5965 | { |
||
5966 | BYTE q; |
||
5967 | DWORD p, l; // "l" is the sector Address |
||
5968 | DWORD c = 0, d, ClusterFailValue,LastClusterLimit; // ClusterEntries |
||
5969 | |||
5970 | gBufferZeroed = FALSE; |
||
5971 | |||
5972 | /* Settings based on FAT type */ |
||
5973 | switch (dsk->type) |
||
5974 | { |
||
5975 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
5976 | case FAT32: |
||
5977 | p = (DWORD)ccls * 4; |
||
5978 | q = 0; // "q" not used for FAT32, only initialized to remove a warning |
||
5979 | ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
5980 | LastClusterLimit = LAST_CLUSTER_FAT32; |
||
5981 | break; |
||
5982 | #endif |
||
5983 | case FAT12: |
||
5984 | p = (DWORD) ccls *3; // Mulby1.5 to find cluster pos in FAT |
||
5985 | q = p&1; |
||
5986 | p >>= 1; |
||
5987 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
5988 | LastClusterLimit = LAST_CLUSTER_FAT12; |
||
5989 | break; |
||
5990 | case FAT16: |
||
5991 | default: |
||
5992 | p = (DWORD)ccls *2; // Mulby 2 to find cluster pos in FAT |
||
5993 | q = 0; // "q" not used for FAT16, only initialized to remove a warning |
||
5994 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
5995 | LastClusterLimit = LAST_CLUSTER_FAT16; |
||
5996 | break; |
||
5997 | } |
||
5998 | |||
5999 | l = dsk->fat + (p / dsk->sectorSize); // |
||
6000 | p &= dsk->sectorSize - 1; // Restrict 'p' within the FATbuffer size |
||
6001 | |||
6002 | // Check if the appropriate FAT sector is already loaded |
||
6003 | if (gLastFATSectorRead == l) |
||
6004 | { |
||
6005 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6006 | if (dsk->type == FAT32) |
||
6007 | c = RAMreadD (gFATBuffer, p); |
||
6008 | else |
||
6009 | #endif |
||
6010 | if(dsk->type == FAT16) |
||
6011 | c = RAMreadW (gFATBuffer, p); |
||
6012 | else if(dsk->type == FAT12) |
||
6013 | { |
||
6014 | c = RAMread (gFATBuffer, p); |
||
6015 | if (q) |
||
6016 | { |
||
6017 | c >>= 4; |
||
6018 | } |
||
6019 | // Check if the MSB is across the sector boundry |
||
6020 | p = (p +1) & (dsk->sectorSize-1); |
||
6021 | if (p == 0) |
||
6022 | { |
||
6023 | // Start by writing the sector we just worked on to the card |
||
6024 | // if we need to |
||
6025 | #ifdef ALLOW_WRITES |
||
6026 | if (gNeedFATWrite) |
||
6027 | if(WriteFAT (dsk, 0, 0, TRUE)) |
||
6028 | return ClusterFailValue; |
||
6029 | #endif |
||
6030 | if (!MDD_SectorRead (l+1, gFATBuffer)) |
||
6031 | { |
||
6032 | gLastFATSectorRead = 0xFFFF; |
||
6033 | return ClusterFailValue; |
||
6034 | } |
||
6035 | else |
||
6036 | { |
||
6037 | gLastFATSectorRead = l +1; |
||
6038 | } |
||
6039 | } |
||
6040 | d = RAMread (gFATBuffer, p); |
||
6041 | if (q) |
||
6042 | { |
||
6043 | c += (d <<4); |
||
6044 | } |
||
6045 | else |
||
6046 | { |
||
6047 | c += ((d & 0x0F)<<8); |
||
6048 | } |
||
6049 | } |
||
6050 | } |
||
6051 | else |
||
6052 | { |
||
6053 | // If there's a currently open FAT sector, |
||
6054 | // write it back before reading into the buffer |
||
6055 | #ifdef ALLOW_WRITES |
||
6056 | if (gNeedFATWrite) |
||
6057 | { |
||
6058 | if(WriteFAT (dsk, 0, 0, TRUE)) |
||
6059 | return ClusterFailValue; |
||
6060 | } |
||
6061 | #endif |
||
6062 | if (!MDD_SectorRead (l, gFATBuffer)) |
||
6063 | { |
||
6064 | gLastFATSectorRead = 0xFFFF; // Note: It is Sector not Cluster. |
||
6065 | return ClusterFailValue; |
||
6066 | } |
||
6067 | else |
||
6068 | { |
||
6069 | gLastFATSectorRead = l; |
||
6070 | |||
6071 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6072 | if (dsk->type == FAT32) |
||
6073 | c = RAMreadD (gFATBuffer, p); |
||
6074 | else |
||
6075 | #endif |
||
6076 | if(dsk->type == FAT16) |
||
6077 | c = RAMreadW (gFATBuffer, p); |
||
6078 | else if (dsk->type == FAT12) |
||
6079 | { |
||
6080 | c = RAMread (gFATBuffer, p); |
||
6081 | if (q) |
||
6082 | { |
||
6083 | c >>= 4; |
||
6084 | } |
||
6085 | p = (p +1) & (dsk->sectorSize-1); |
||
6086 | d = RAMread (gFATBuffer, p); |
||
6087 | if (q) |
||
6088 | { |
||
6089 | c += (d <<4); |
||
6090 | } |
||
6091 | else |
||
6092 | { |
||
6093 | c += ((d & 0x0F)<<8); |
||
6094 | } |
||
6095 | } |
||
6096 | } |
||
6097 | } |
||
6098 | |||
6099 | // Normalize it so 0xFFFF is an error |
||
6100 | if (c >= LastClusterLimit) |
||
6101 | c = LastClusterLimit; |
||
6102 | |||
6103 | return c; |
||
6104 | } // ReadFAT |
||
6105 | |||
6106 | |||
6107 | |||
6108 | /**************************************************************************** |
||
6109 | Function: |
||
6110 | WORD WriteFAT (DISK *dsk, DWORD ccls, WORD value, BYTE forceWrite) |
||
6111 | Summary: |
||
6112 | Write an entry to the FAT |
||
6113 | Conditions: |
||
6114 | This function should not be called by the user. |
||
6115 | Input: |
||
6116 | dsk - The disk structure |
||
6117 | ccls - The current cluster |
||
6118 | value - The value to write in |
||
6119 | forceWrite - Force the function to write the current FAT sector |
||
6120 | Return: |
||
6121 | |||
6122 | FAIL - The FAT could not be written |
||
6123 | Side Effects: |
||
6124 | None |
||
6125 | Description: |
||
6126 | The WriteFAT function writes an entry to the FAT. If the function |
||
6127 | is called and the 'forceWrite' argument is TRUE, the function will |
||
6128 | write the existing FAT data to the device. Otherwise, the function |
||
6129 | will replace a single entry in the FAT buffer (indicated by 'ccls') |
||
6130 | with a new value (indicated by 'value.') |
||
6131 | Remarks: |
||
6132 | None. |
||
6133 | ****************************************************************************/ |
||
6134 | |||
6135 | #ifdef ALLOW_WRITES |
||
6136 | DWORD WriteFAT (DISK *dsk, DWORD ccls, DWORD value, BYTE forceWrite) |
||
6137 | { |
||
6138 | BYTE i, q, c; |
||
6139 | DWORD p, li, l, ClusterFailValue; |
||
6140 | |||
6141 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6142 | if (dsk->type != FAT32 && dsk->type != FAT16 && dsk->type != FAT12) |
||
6143 | return CLUSTER_FAIL_FAT32; |
||
6144 | #else // If FAT32 support not enabled |
||
6145 | if (dsk->type != FAT16 && dsk->type != FAT12) |
||
6146 | return CLUSTER_FAIL_FAT16; |
||
6147 | #endif |
||
6148 | |||
6149 | /* Settings based on FAT type */ |
||
6150 | switch (dsk->type) |
||
6151 | { |
||
6152 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6153 | case FAT32: |
||
6154 | ClusterFailValue = CLUSTER_FAIL_FAT32; |
||
6155 | break; |
||
6156 | #endif |
||
6157 | case FAT12: |
||
6158 | case FAT16: |
||
6159 | default: |
||
6160 | ClusterFailValue = CLUSTER_FAIL_FAT16; |
||
6161 | break; |
||
6162 | } |
||
6163 | |||
6164 | gBufferZeroed = FALSE; |
||
6165 | |||
6166 | // The only purpose for calling this function with forceWrite |
||
6167 | // is to write the current FAT sector to the card |
||
6168 | if (forceWrite) |
||
6169 | { |
||
6170 | for (i = 0, li = gLastFATSectorRead; i < dsk->fatcopy; i++, li += dsk->fatsize) |
||
6171 | { |
||
6172 | if (!MDD_SectorWrite (li, gFATBuffer, FALSE)) |
||
6173 | { |
||
6174 | return ClusterFailValue; |
||
6175 | } |
||
6176 | } |
||
6177 | |||
6178 | gNeedFATWrite = FALSE; |
||
6179 | |||
6180 | return 0; |
||
6181 | } |
||
6182 | |||
6183 | /* Settings based on FAT type */ |
||
6184 | switch (dsk->type) |
||
6185 | { |
||
6186 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6187 | case FAT32: |
||
6188 | p = (DWORD)ccls *4; // "p" is the position in "gFATBuffer" for corresponding cluster. |
||
6189 | q = 0; // "q" not used for FAT32, only initialized to remove a warning |
||
6190 | break; |
||
6191 | #endif |
||
6192 | case FAT12: |
||
6193 | p = (DWORD) ccls * 3; // "p" is the position in "gFATBuffer" for corresponding cluster. |
||
6194 | q = p & 1; // Odd or even? |
||
6195 | p >>= 1; |
||
6196 | break; |
||
6197 | case FAT16: |
||
6198 | default: |
||
6199 | p = (DWORD) ccls *2; // "p" is the position in "gFATBuffer" for corresponding cluster. |
||
6200 | q = 0; // "q" not used for FAT16, only initialized to remove a warning |
||
6201 | break; |
||
6202 | } |
||
6203 | |||
6204 | l = dsk->fat + (p / dsk->sectorSize); // |
||
6205 | p &= dsk->sectorSize - 1; // Restrict 'p' within the FATbuffer size |
||
6206 | |||
6207 | if (gLastFATSectorRead != l) |
||
6208 | { |
||
6209 | // If we are loading a new sector then write |
||
6210 | // the current one to the card if we need to |
||
6211 | if (gNeedFATWrite) |
||
6212 | { |
||
6213 | for (i = 0, li = gLastFATSectorRead; i < dsk->fatcopy; i++, li += dsk->fatsize) |
||
6214 | { |
||
6215 | if (!MDD_SectorWrite (li, gFATBuffer, FALSE)) |
||
6216 | { |
||
6217 | return ClusterFailValue; |
||
6218 | } |
||
6219 | } |
||
6220 | |||
6221 | gNeedFATWrite = FALSE; |
||
6222 | } |
||
6223 | |||
6224 | // Load the new sector |
||
6225 | if (!MDD_SectorRead (l, gFATBuffer)) |
||
6226 | { |
||
6227 | gLastFATSectorRead = 0xFFFF; |
||
6228 | return ClusterFailValue; |
||
6229 | } |
||
6230 | else |
||
6231 | { |
||
6232 | gLastFATSectorRead = l; |
||
6233 | } |
||
6234 | } |
||
6235 | |||
6236 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
6237 | if (dsk->type == FAT32) // Refer page 16 of FAT requirement. |
||
6238 | { |
||
6239 | RAMwrite (gFATBuffer, p, ((value & 0x000000ff))); // lsb,1st byte of cluster value |
||
6240 | RAMwrite (gFATBuffer, p+1, ((value & 0x0000ff00) >> 8)); |
||
6241 | RAMwrite (gFATBuffer, p+2, ((value & 0x00ff0000) >> 16)); |
||
6242 | RAMwrite (gFATBuffer, p+3, ((value & 0x0f000000) >> 24)); // the MSB nibble is supposed to be "0" in FAT32. So mask it. |
||
6243 | } |
||
6244 | else |
||
6245 | |||
6246 | #endif |
||
6247 | { |
||
6248 | if (dsk->type == FAT16) |
||
6249 | { |
||
6250 | RAMwrite (gFATBuffer, p, value); //lsB |
||
6251 | RAMwrite (gFATBuffer, p+1, ((value&0x0000ff00) >> 8)); // msB |
||
6252 | } |
||
6253 | else if (dsk->type == FAT12) |
||
6254 | { |
||
6255 | // Get the current byte from the FAT |
||
6256 | c = RAMread (gFATBuffer, p); |
||
6257 | if (q) |
||
6258 | { |
||
6259 | c = ((value & 0x0F) << 4) | ( c & 0x0F); |
||
6260 | } |
||
6261 | else |
||
6262 | { |
||
6263 | c = (value & 0xFF); |
||
6264 | } |
||
6265 | // Write in those bits |
||
6266 | RAMwrite (gFATBuffer, p, c); |
||
6267 | |||
6268 | // FAT12 entries can cross sector boundaries |
||
6269 | // Check if we need to load a new sector |
||
6270 | p = (p +1) & (dsk->sectorSize-1); |
||
6271 | if (p == 0) |
||
6272 | { |
||
6273 | // call this function to update the FAT on the card |
||
6274 | if (WriteFAT (dsk, 0,0,TRUE)) |
||
6275 | return ClusterFailValue; |
||
6276 | |||
6277 | // Load the next sector |
||
6278 | if (!MDD_SectorRead (l +1, gFATBuffer)) |
||
6279 | { |
||
6280 | gLastFATSectorRead = 0xFFFF; |
||
6281 | return ClusterFailValue; |
||
6282 | } |
||
6283 | else |
||
6284 | { |
||
6285 | gLastFATSectorRead = l + 1; |
||
6286 | } |
||
6287 | } |
||
6288 | |||
6289 | // Get the second byte of the table entry |
||
6290 | c = RAMread (gFATBuffer, p); |
||
6291 | if (q) |
||
6292 | { |
||
6293 | c = (value >> 4); |
||
6294 | } |
||
6295 | else |
||
6296 | { |
||
6297 | c = ((value >> 8) & 0x0F) | (c & 0xF0); |
||
6298 | } |
||
6299 | RAMwrite (gFATBuffer, p, c); |
||
6300 | } |
||
6301 | } |
||
6302 | gNeedFATWrite = TRUE; |
||
6303 | |||
6304 | return 0; |
||
6305 | } |
||
6306 | #endif |
||
6307 | |||
6308 | |||
6309 | #ifdef ALLOW_DIRS |
||
6310 | |||
6311 | // This string is used by dir functions to hold dir names temporarily |
||
6312 | char defaultString [13]; |
||
6313 | |||
6314 | |||
6315 | |||
6316 | /************************************************************************** |
||
6317 | Function: |
||
6318 | int FSchdir (char * path) |
||
6319 | Summary: |
||
6320 | Change the current working directory |
||
6321 | Conditions: |
||
6322 | None |
||
6323 | Input: |
||
6324 | path - The path of the directory to change to. |
||
6325 | Return Values: |
||
6326 | |||
6327 | EOF - The current working directory could not be changed |
||
6328 | Side Effects: |
||
6329 | The current working directory may be changed. The FSerrno variable will |
||
6330 | be changed. |
||
6331 | Description: |
||
6332 | The FSchdir function passes a RAM pointer to the path to the |
||
6333 | chdirhelper function. |
||
6334 | Remarks: |
||
6335 | None |
||
6336 | **************************************************************************/ |
||
6337 | |||
6338 | int FSchdir (char * path) |
||
6339 | { |
||
6340 | return chdirhelper (0, path, NULL); |
||
6341 | } |
||
6342 | |||
6343 | /************************************************************************** |
||
6344 | Function: |
||
6345 | int FSchdirpgm (const rom char * path) |
||
6346 | Summary: |
||
6347 | Changed the CWD with a path in ROM on PIC18 |
||
6348 | Conditions: |
||
6349 | None |
||
6350 | Input: |
||
6351 | path - The path of the directory to change to (ROM) |
||
6352 | Return Values: |
||
6353 | |||
6354 | EOF - The current working directory could not be changed |
||
6355 | Side Effects: |
||
6356 | The current working directory may be changed. The FSerrno variable will |
||
6357 | be changed. |
||
6358 | Description: |
||
6359 | The FSchdirpgm function passes a PIC18 ROM path pointer to the |
||
6360 | chdirhelper function. |
||
6361 | Remarks: |
||
6362 | This function is for use with PIC18 when passing arguments in ROM |
||
6363 | **************************************************************************/ |
||
6364 | |||
6365 | #ifdef ALLOW_PGMFUNCTIONS |
||
6366 | int FSchdirpgm (const rom char * path) |
||
6367 | { |
||
6368 | return chdirhelper (1, NULL, path); |
||
6369 | } |
||
6370 | #endif |
||
6371 | |||
6372 | |||
6373 | /************************************************************************* |
||
6374 | Function: |
||
6375 | // PIC24/30/33/32 |
||
6376 | int chdirhelper (BYTE mode, char * ramptr, char * romptr); |
||
6377 | // PIC18 |
||
6378 | int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr); |
||
6379 | Summary: |
||
6380 | Helper function for FSchdir |
||
6381 | Conditions: |
||
6382 | None |
||
6383 | Input: |
||
6384 | mode - Indicates which path pointer to use |
||
6385 | ramptr - Pointer to the path specified in RAM |
||
6386 | romptr - Pointer to the path specified in ROM |
||
6387 | Return Values: |
||
6388 | |||
6389 | EOF - Directory could not be changed. |
||
6390 | Side Effects: |
||
6391 | The current working directory will be changed. The FSerrno variable |
||
6392 | will be changed. Any unwritten data in the data buffer will be written |
||
6393 | to the device. |
||
6394 | Description: |
||
6395 | This helper function is used by the FSchdir function. If the path |
||
6396 | argument is specified in ROM for PIC18 this function will be able to |
||
6397 | parse it correctly. The function will loop through a switch statement |
||
6398 | to process the tokens in the path string. Dot or dotdot entries are |
||
6399 | handled in the first case statement. A backslash character is handled |
||
6400 | in the second case statement (note that this case statement will only |
||
6401 | be used if backslash is the first character in the path; backslash |
||
6402 | token delimiters will automatically be skipped after each token in the |
||
6403 | path is processed). The third case statement will handle actual |
||
6404 | directory name strings. |
||
6405 | Remarks: |
||
6406 | None. |
||
6407 | *************************************************************************/ |
||
6408 | |||
6409 | #ifdef ALLOW_PGMFUNCTIONS |
||
6410 | int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr) |
||
6411 | #else |
||
6412 | int chdirhelper (BYTE mode, char * ramptr, char * romptr) |
||
6413 | #endif |
||
6414 | { |
||
6415 | BYTE i, j; |
||
6416 | WORD curent = 1; |
||
6417 | DIRENTRY entry; |
||
6418 | char * temppath = ramptr; |
||
6419 | #ifdef ALLOW_PGMFUNCTIONS |
||
6420 | rom char * temppath2 = romptr; |
||
6421 | #endif |
||
6422 | FSFILE tempCWDobj2; |
||
6423 | char tempArray[12]; |
||
6424 | FILEOBJ tempCWD = &tempCWDobj2; |
||
6425 | FileObjectCopy (tempCWD, cwdptr); |
||
6426 | |||
6427 | FSerrno = CE_GOOD; |
||
6428 | |||
6429 | // Check the first char of the path |
||
6430 | #ifdef ALLOW_PGMFUNCTIONS |
||
6431 | if (mode) |
||
6432 | i = *temppath2; |
||
6433 | else |
||
6434 | #endif |
||
6435 | i = *temppath; |
||
6436 | if (i == 0) |
||
6437 | { |
||
6438 | FSerrno = CE_INVALID_ARGUMENT; |
||
6439 | return -1; |
||
6440 | } |
||
6441 | |||
6442 | while(1) |
||
6443 | { |
||
6444 | switch (i) |
||
6445 | { |
||
6446 | // First case: dot or dotdot entry |
||
6447 | case '.': |
||
6448 | // Move past the dot |
||
6449 | #ifdef ALLOW_PGMFUNCTIONS |
||
6450 | if (mode) |
||
6451 | { |
||
6452 | temppath2++; |
||
6453 | i = *temppath2; |
||
6454 | } |
||
6455 | else |
||
6456 | { |
||
6457 | #endif |
||
6458 | temppath++; |
||
6459 | i = *temppath; |
||
6460 | #ifdef ALLOW_PGMFUNCTIONS |
||
6461 | } |
||
6462 | #endif |
||
6463 | // Check if it's a dotdot entry |
||
6464 | if (i == '.') |
||
6465 | { |
||
6466 | // Increment the path variable |
||
6467 | #ifdef ALLOW_PGMFUNCTIONS |
||
6468 | if (mode) |
||
6469 | { |
||
6470 | temppath2++; |
||
6471 | i = *temppath2; |
||
6472 | } |
||
6473 | else |
||
6474 | { |
||
6475 | #endif |
||
6476 | temppath++; |
||
6477 | i = *temppath; |
||
6478 | #ifdef ALLOW_PGMFUNCTIONS |
||
6479 | } |
||
6480 | #endif |
||
6481 | // Check if we're in the root |
||
6482 | if (tempCWD->dirclus == FatRootDirClusterValue) |
||
6483 | { |
||
6484 | // Fails if there's a dotdot chdir from the root |
||
6485 | FSerrno = CE_INVALID_ARGUMENT; |
||
6486 | return -1; |
||
6487 | } |
||
6488 | else |
||
6489 | { |
||
6490 | // Cache the dotdot entry |
||
6491 | tempCWD->dirccls = tempCWD->dirclus; |
||
6492 | curent = 1; |
||
6493 | entry = Cache_File_Entry (tempCWD, &curent, TRUE); |
||
6494 | if (entry == NULL) |
||
6495 | { |
||
6496 | FSerrno = CE_BADCACHEREAD; |
||
6497 | return -1; |
||
6498 | } |
||
6499 | |||
6500 | // Get the cluster |
||
6501 | tempCWD->dirclus = GetFullClusterNumber(entry); // Get Complete Cluster number. |
||
6502 | tempCWD->dirccls = tempCWD->dirclus; |
||
6503 | |||
6504 | // If we changed to root, record the name |
||
6505 | if (tempCWD->dirclus == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT) // "0" is the value of Dotdot entry for Root in both FAT types. |
||
6506 | { |
||
6507 | tempCWD->name[0] = '\\'; |
||
6508 | for (j = 1; j < 11; j++) |
||
6509 | { |
||
6510 | tempCWD->name[j] = 0x20; |
||
6511 | } |
||
6512 | |||
6513 | /* While moving to Root, get the Root cluster value */ |
||
6514 | tempCWD->dirccls = FatRootDirClusterValue; |
||
6515 | tempCWD->dirclus = FatRootDirClusterValue; |
||
6516 | } |
||
6517 | else |
||
6518 | { |
||
6519 | // Otherwise set the name to .. |
||
6520 | tempCWD->name[0] = '.'; |
||
6521 | tempCWD->name[1] = '.'; |
||
6522 | for (j = 2; j < 11; j++) |
||
6523 | { |
||
6524 | tempCWD->name[j] = 0x20; |
||
6525 | } |
||
6526 | } |
||
6527 | // Cache the dot entry |
||
6528 | curent = 0; |
||
6529 | if (Cache_File_Entry(tempCWD, &curent, TRUE) == NULL) |
||
6530 | { |
||
6531 | FSerrno = CE_BADCACHEREAD; |
||
6532 | return -1; |
||
6533 | } |
||
6534 | // Move past the next backslash, if necessary |
||
6535 | while (i == '\\') |
||
6536 | { |
||
6537 | #ifdef ALLOW_PGMFUNCTIONS |
||
6538 | if (mode) |
||
6539 | { |
||
6540 | temppath2++; |
||
6541 | i = *temppath2; |
||
6542 | } |
||
6543 | else |
||
6544 | { |
||
6545 | #endif |
||
6546 | temppath++; |
||
6547 | i = *temppath; |
||
6548 | #ifdef ALLOW_PGMFUNCTIONS |
||
6549 | } |
||
6550 | #endif |
||
6551 | } |
||
6552 | // Copy and return, if we're at the end |
||
6553 | if (i == 0) |
||
6554 | { |
||
6555 | FileObjectCopy (cwdptr, tempCWD); |
||
6556 | return 0; |
||
6557 | } |
||
6558 | } |
||
6559 | } |
||
6560 | else |
||
6561 | { |
||
6562 | // If we ended with a . entry, |
||
6563 | // just return what we have |
||
6564 | if (i == 0) |
||
6565 | { |
||
6566 | FileObjectCopy (cwdptr, tempCWD); |
||
6567 | return 0; |
||
6568 | } |
||
6569 | else |
||
6570 | { |
||
6571 | if (i == '\\') |
||
6572 | { |
||
6573 | while (i == '\\') |
||
6574 | { |
||
6575 | #ifdef ALLOW_PGMFUNCTIONS |
||
6576 | if (mode) |
||
6577 | { |
||
6578 | temppath2++; |
||
6579 | i = *temppath2; |
||
6580 | } |
||
6581 | else |
||
6582 | { |
||
6583 | #endif |
||
6584 | temppath++; |
||
6585 | i = *temppath; |
||
6586 | #ifdef ALLOW_PGMFUNCTIONS |
||
6587 | } |
||
6588 | #endif |
||
6589 | } |
||
6590 | if (i == 0) |
||
6591 | { |
||
6592 | FileObjectCopy (cwdptr, tempCWD); |
||
6593 | return 0; |
||
6594 | } |
||
6595 | } |
||
6596 | else |
||
6597 | { |
||
6598 | // Anything else after a dot doesn't make sense |
||
6599 | FSerrno = CE_INVALID_ARGUMENT; |
||
6600 | return -1; |
||
6601 | } |
||
6602 | } |
||
6603 | } |
||
6604 | |||
6605 | break; |
||
6606 | |||
6607 | // Second case: the first char is the root backslash |
||
6608 | // We will ONLY switch to this case if the first char |
||
6609 | // of the path is a backslash |
||
6610 | case '\\': |
||
6611 | // Increment pointer to second char |
||
6612 | #ifdef ALLOW_PGMFUNCTIONS |
||
6613 | if (mode) |
||
6614 | { |
||
6615 | temppath2++; |
||
6616 | i = *temppath2; |
||
6617 | } |
||
6618 | else |
||
6619 | { |
||
6620 | #endif |
||
6621 | temppath++; |
||
6622 | i = *temppath; |
||
6623 | #ifdef ALLOW_PGMFUNCTIONS |
||
6624 | } |
||
6625 | #endif |
||
6626 | // Can't start the path with multiple backslashes |
||
6627 | if (i == '\\') |
||
6628 | { |
||
6629 | FSerrno = CE_INVALID_ARGUMENT; |
||
6630 | return -1; |
||
6631 | } |
||
6632 | |||
6633 | if (i == 0) |
||
6634 | { |
||
6635 | // The user is changing directory to |
||
6636 | // the root |
||
6637 | cwdptr->dirclus = FatRootDirClusterValue; |
||
6638 | cwdptr->dirccls = FatRootDirClusterValue; |
||
6639 | cwdptr->name[0] = '\\'; |
||
6640 | for (j = 1; j < 11; j++) |
||
6641 | { |
||
6642 | cwdptr->name[j] = 0x20; |
||
6643 | } |
||
6644 | return 0; |
||
6645 | } |
||
6646 | else |
||
6647 | { |
||
6648 | // Our first char is the root dir switch |
||
6649 | tempCWD->dirclus = FatRootDirClusterValue; |
||
6650 | tempCWD->dirccls = FatRootDirClusterValue; |
||
6651 | tempCWD->name[0] = '\\'; |
||
6652 | for (j = 1; j < 11; j++) |
||
6653 | { |
||
6654 | tempCWD->name[j] = 0x20; |
||
6655 | } |
||
6656 | } |
||
6657 | break; |
||
6658 | |||
6659 | default: |
||
6660 | // We should be at the beginning of a string of letters/numbers |
||
6661 | j = 0; |
||
6662 | #ifdef ALLOW_PGMFUNCTIONS |
||
6663 | if (mode) |
||
6664 | { |
||
6665 | while ((i != 0) && (i != '\\') && (j < 12)) |
||
6666 | { |
||
6667 | defaultString[j++] = i; |
||
6668 | i = *(++temppath2); |
||
6669 | } |
||
6670 | } |
||
6671 | else |
||
6672 | { |
||
6673 | #endif |
||
6674 | while ((i != 0) && (i != '\\') && (j < 12)) |
||
6675 | { |
||
6676 | defaultString[j++] = i; |
||
6677 | i = *(++temppath); |
||
6678 | } |
||
6679 | #ifdef ALLOW_PGMFUNCTIONS |
||
6680 | } |
||
6681 | #endif |
||
6682 | // We got a whole 12 chars |
||
6683 | // There could be more- truncate it |
||
6684 | if (j == 12) |
||
6685 | { |
||
6686 | while ((i != 0) && (i != '\\')) |
||
6687 | { |
||
6688 | #ifdef ALLOW_PGMFUNCTIONS |
||
6689 | if (mode) |
||
6690 | { |
||
6691 | i = *(++temppath2); |
||
6692 | } |
||
6693 | else |
||
6694 | { |
||
6695 | #endif |
||
6696 | i = *(++temppath); |
||
6697 | #ifdef ALLOW_PGMFUNCTIONS |
||
6698 | } |
||
6699 | #endif |
||
6700 | } |
||
6701 | } |
||
6702 | |||
6703 | defaultString[j] = 0; |
||
6704 | |||
6705 | if (FormatDirName (defaultString, 0) == FALSE) |
||
6706 | return -1; |
||
6707 | |||
6708 | for (j = 0; j < 11; j++) |
||
6709 | { |
||
6710 | tempArray[j] = tempCWD->name[j]; |
||
6711 | tempCWD->name[j] = defaultString[j]; |
||
6712 | } |
||
6713 | |||
6714 | // copy file object over |
||
6715 | FileObjectCopy(&gFileTemp, tempCWD); |
||
6716 | |||
6717 | // See if the directory is there |
||
6718 | if(FILEfind (&gFileTemp, tempCWD, LOOK_FOR_MATCHING_ENTRY, 0) != CE_GOOD) |
||
6719 | { |
||
6720 | // Couldn't find the DIR |
||
6721 | FSerrno = CE_DIR_NOT_FOUND; |
||
6722 | return -1; |
||
6723 | } |
||
6724 | else |
||
6725 | { |
||
6726 | // Found the file |
||
6727 | // Check to make sure it's actually a directory |
||
6728 | if (gFileTemp.attributes != ATTR_DIRECTORY) |
||
6729 | { |
||
6730 | FSerrno = CE_INVALID_ARGUMENT; |
||
6731 | return -1; |
||
6732 | } |
||
6733 | |||
6734 | // Get the new name |
||
6735 | for (j = 0; j < 11; j++) |
||
6736 | { |
||
6737 | tempCWD->name[j] = gFileTemp.name[j]; |
||
6738 | } |
||
6739 | tempCWD->dirclus = gFileTemp.cluster; |
||
6740 | tempCWD->dirccls = tempCWD->dirclus; |
||
6741 | } |
||
6742 | |||
6743 | if (i == 0) |
||
6744 | { |
||
6745 | // If we're at the end of the string, we're done |
||
6746 | FileObjectCopy (cwdptr, tempCWD); |
||
6747 | return 0; |
||
6748 | } |
||
6749 | else |
||
6750 | { |
||
6751 | while (i == '\\') |
||
6752 | { |
||
6753 | // If we get to another backslash, increment past it |
||
6754 | #ifdef ALLOW_PGMFUNCTIONS |
||
6755 | if (mode) |
||
6756 | { |
||
6757 | temppath2++; |
||
6758 | i = *temppath2; |
||
6759 | } |
||
6760 | else |
||
6761 | { |
||
6762 | #endif |
||
6763 | temppath++; |
||
6764 | i = *temppath; |
||
6765 | #ifdef ALLOW_PGMFUNCTIONS |
||
6766 | } |
||
6767 | #endif |
||
6768 | if (i == 0) |
||
6769 | { |
||
6770 | FileObjectCopy (cwdptr, tempCWD); |
||
6771 | return 0; |
||
6772 | } |
||
6773 | } |
||
6774 | } |
||
6775 | break; |
||
6776 | } |
||
6777 | } // loop |
||
6778 | } |
||
6779 | |||
6780 | |||
6781 | |||
6782 | // This string is used by FSgetcwd to return the cwd name if the path |
||
6783 | // passed into the function is NULL |
||
6784 | char defaultArray [10]; |
||
6785 | |||
6786 | |||
6787 | /************************************************************** |
||
6788 | Function: |
||
6789 | char * FSgetcwd (char * path, int numchars) |
||
6790 | Summary: |
||
6791 | Get the current working directory name |
||
6792 | Conditions: |
||
6793 | None |
||
6794 | Input: |
||
6795 | path - Pointer to the array to return the cwd name in |
||
6796 | numchars - Number of chars in the path |
||
6797 | Return Values: |
||
6798 | char * - The cwd name string pointer (path or defaultArray) |
||
6799 | NULL - The current working directory name could not be loaded. |
||
6800 | Side Effects: |
||
6801 | The FSerrno variable will be changed |
||
6802 | Description: |
||
6803 | The FSgetcwd function will get the name of the current |
||
6804 | working directory and return it to the user. The name |
||
6805 | will be copied into the buffer pointed to by 'path,' |
||
6806 | starting at the root directory and copying as many chars |
||
6807 | as possible before the end of the buffer. The buffer |
||
6808 | size is indicated by the 'numchars' argument. The first |
||
6809 | thing this function will do is load the name of the current |
||
6810 | working directory, if it isn't already present. This could |
||
6811 | occur if the user switched to the dotdot entry of a |
||
6812 | subdirectory immediately before calling this function. The |
||
6813 | function will then copy the current working directory name |
||
6814 | into the buffer backwards, and insert a backslash character. |
||
6815 | Next, the function will continuously switch to the previous |
||
6816 | directories and copy their names backwards into the buffer |
||
6817 | until it reaches the root. If the buffer overflows, it |
||
6818 | will be treated as a circular buffer, and data will be |
||
6819 | copied over existing characters, starting at the beginning. |
||
6820 | Once the root directory is reached, the text in the buffer |
||
6821 | will be swapped, so that the buffer contains as much of the |
||
6822 | current working directory name as possible, starting at the |
||
6823 | root. |
||
6824 | Remarks: |
||
6825 | None |
||
6826 | **************************************************************/ |
||
6827 | char * FSgetcwd (char * path, int numchars) |
||
6828 | { |
||
6829 | // If path is passed in as null, set up a default |
||
6830 | // array with 10 characters |
||
6831 | char totalchars = (path == NULL) ? 10 : numchars; |
||
6832 | char * returnPointer; |
||
6833 | char * bufferEnd; |
||
6834 | FILEOBJ tempCWD = &gFileTemp; |
||
6835 | BYTE bufferOverflow = FALSE; |
||
6836 | signed char j; |
||
6837 | DWORD curclus; |
||
6838 | WORD fHandle, tempindex; |
||
6839 | signed int i, index = 0; |
||
6840 | char aChar; |
||
6841 | DIRENTRY entry; |
||
6842 | |||
6843 | FSerrno = CE_GOOD; |
||
6844 | |||
6845 | // Set up the return value |
||
6846 | if (path == NULL) |
||
6847 | returnPointer = defaultArray; |
||
6848 | else |
||
6849 | { |
||
6850 | returnPointer = path; |
||
6851 | if (numchars == 0) |
||
6852 | { |
||
6853 | FSerrno = CE_INVALID_ARGUMENT; |
||
6854 | return NULL; |
||
6855 | } |
||
6856 | } |
||
6857 | |||
6858 | bufferEnd = returnPointer + totalchars - 1; |
||
6859 | |||
6860 | FileObjectCopy (tempCWD, cwdptr); |
||
6861 | |||
6862 | if ((tempCWD->name[0] == '.') && |
||
6863 | (tempCWD->name[1] == '.')) |
||
6864 | { |
||
6865 | // We last changed directory into a dotdot entry |
||
6866 | // Save the value of the current directory |
||
6867 | curclus = tempCWD->dirclus; |
||
6868 | // Put this dir's dotdot entry into the dirclus |
||
6869 | // Our cwd absolutely is not the root |
||
6870 | fHandle = 1; |
||
6871 | tempCWD->dirccls = tempCWD->dirclus; |
||
6872 | entry = Cache_File_Entry (tempCWD,&fHandle, TRUE); |
||
6873 | if (entry == NULL) |
||
6874 | { |
||
6875 | FSerrno = CE_BADCACHEREAD; |
||
6876 | return NULL; |
||
6877 | } |
||
6878 | |||
6879 | |||
6880 | // Get the cluster |
||
6881 | TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number. |
||
6882 | |||
6883 | // For FAT32, if the .. entry is 0, the cluster won't be 0 |
||
6884 | #ifdef SUPPORT_FAT32 |
||
6885 | if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT) |
||
6886 | { |
||
6887 | tempCWD->dirclus = FatRootDirClusterValue; |
||
6888 | } |
||
6889 | else |
||
6890 | #endif |
||
6891 | tempCWD->dirclus = TempClusterCalc; |
||
6892 | |||
6893 | tempCWD->dirccls = tempCWD->dirclus; |
||
6894 | |||
6895 | // Find the direntry for the entry we were just in |
||
6896 | fHandle = 0; |
||
6897 | entry = Cache_File_Entry (tempCWD, &fHandle, TRUE); |
||
6898 | if (entry == NULL) |
||
6899 | { |
||
6900 | FSerrno = CE_BADCACHEREAD; |
||
6901 | return NULL; |
||
6902 | } |
||
6903 | |||
6904 | // Get the cluster |
||
6905 | TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number. |
||
6906 | |||
6907 | while ((TempClusterCalc != curclus) || |
||
6908 | ((TempClusterCalc == curclus) && |
||
6909 | (((unsigned char)entry->DIR_Name[0] == 0xE5) || (entry->DIR_Attr == ATTR_VOLUME) || (entry->DIR_Attr == ATTR_LONG_NAME)))) |
||
6910 | { |
||
6911 | fHandle++; |
||
6912 | entry = Cache_File_Entry (tempCWD, &fHandle, FALSE); |
||
6913 | if (entry == NULL) |
||
6914 | { |
||
6915 | FSerrno = CE_BADCACHEREAD; |
||
6916 | return NULL; |
||
6917 | } |
||
6918 | |||
6919 | // Get the cluster |
||
6920 | TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number in a loop. |
||
6921 | } |
||
6922 | // We've found the entry for the dir we were in |
||
6923 | for (i = 0; i < 11; i++) |
||
6924 | { |
||
6925 | tempCWD->name[i] = entry->DIR_Name[i]; |
||
6926 | cwdptr->name[i] = entry->DIR_Name[i]; |
||
6927 | } |
||
6928 | // Reset our temp dir back to that cluster |
||
6929 | tempCWD->dirclus = curclus; |
||
6930 | tempCWD->dirccls = curclus; |
||
6931 | // This will set us at the cwd, but it will actually |
||
6932 | // have the name in the name field this time |
||
6933 | } |
||
6934 | // There's actually some kind of name value in the cwd |
||
6935 | if (tempCWD->name[0] == '\\') |
||
6936 | { |
||
6937 | // Easy, our CWD is the root |
||
6938 | *returnPointer = '\\'; |
||
6939 | *(returnPointer + 1) = 0; |
||
6940 | return returnPointer; |
||
6941 | } |
||
6942 | else |
||
6943 | { |
||
6944 | // Loop until we get back to the root |
||
6945 | while (tempCWD->dirclus != FatRootDirClusterValue) |
||
6946 | { |
||
6947 | j = 10; |
||
6948 | while (tempCWD->name[j] == 0x20) |
||
6949 | j--; |
||
6950 | if (j >= 8) |
||
6951 | { |
||
6952 | while (j >= 8) |
||
6953 | { |
||
6954 | *(returnPointer + index++) = tempCWD->name[j--]; |
||
6955 | // This is a circular buffer |
||
6956 | // Any unnecessary values will be overwritten |
||
6957 | if (index == totalchars) |
||
6958 | { |
||
6959 | index = 0; |
||
6960 | bufferOverflow = TRUE; |
||
6961 | } |
||
6962 | } |
||
6963 | *(returnPointer + index++) = '.'; |
||
6964 | if (index == totalchars) |
||
6965 | { |
||
6966 | index = 0; |
||
6967 | bufferOverflow = TRUE; |
||
6968 | } |
||
6969 | } |
||
6970 | |||
6971 | while (tempCWD->name[j] == 0x20) |
||
6972 | j--; |
||
6973 | |||
6974 | while (j >= 0) |
||
6975 | { |
||
6976 | *(returnPointer + index++) = tempCWD->name[j--]; |
||
6977 | // This is a circular buffer |
||
6978 | // Any unnecessary values will be overwritten |
||
6979 | if (index == totalchars) |
||
6980 | { |
||
6981 | index = 0; |
||
6982 | bufferOverflow = TRUE; |
||
6983 | } |
||
6984 | } |
||
6985 | |||
6986 | // Put a backslash delimiter in front of the dir name |
||
6987 | *(returnPointer + index++) = '\\'; |
||
6988 | if (index == totalchars) |
||
6989 | { |
||
6990 | index = 0; |
||
6991 | bufferOverflow = TRUE; |
||
6992 | } |
||
6993 | |||
6994 | // Load the previous entry |
||
6995 | tempCWD->dirccls = tempCWD->dirclus; |
||
6996 | if (GetPreviousEntry (tempCWD)) |
||
6997 | { |
||
6998 | FSerrno = CE_BAD_SECTOR_READ; |
||
6999 | return NULL; |
||
7000 | } |
||
7001 | } |
||
7002 | } |
||
7003 | |||
7004 | // Point the index back at the last char in the string |
||
7005 | index--; |
||
7006 | |||
7007 | i = 0; |
||
7008 | // Swap the chars in the buffer so they are in the right places |
||
7009 | if (bufferOverflow) |
||
7010 | { |
||
7011 | tempindex = index; |
||
7012 | // Swap the overflowed values in the buffer |
||
7013 | while ((index - i) > 0) |
||
7014 | { |
||
7015 | aChar = *(returnPointer + i); |
||
7016 | *(returnPointer + i) = * (returnPointer + index); |
||
7017 | *(returnPointer + index) = aChar; |
||
7018 | index--; |
||
7019 | i++; |
||
7020 | } |
||
7021 | |||
7022 | // Point at the non-overflowed values |
||
7023 | i = tempindex + 1; |
||
7024 | index = bufferEnd - returnPointer; |
||
7025 | |||
7026 | // Swap the non-overflowed values into the right places |
||
7027 | while ((index - i) > 0) |
||
7028 | { |
||
7029 | aChar = *(returnPointer + i); |
||
7030 | *(returnPointer + i) = * (returnPointer + index); |
||
7031 | *(returnPointer + index) = aChar; |
||
7032 | index--; |
||
7033 | i++; |
||
7034 | } |
||
7035 | // All the values should be in the right place now |
||
7036 | // Null-terminate the string |
||
7037 | *(bufferEnd) = 0; |
||
7038 | } |
||
7039 | else |
||
7040 | { |
||
7041 | // There was no overflow, just do one set of swaps |
||
7042 | tempindex = index; |
||
7043 | while ((index - i) > 0) |
||
7044 | { |
||
7045 | aChar = *(returnPointer + i); |
||
7046 | *(returnPointer + i) = * (returnPointer + index); |
||
7047 | *(returnPointer + index) = aChar; |
||
7048 | index--; |
||
7049 | i++; |
||
7050 | } |
||
7051 | *(returnPointer + tempindex + 1) = 0; |
||
7052 | } |
||
7053 | |||
7054 | return returnPointer; |
||
7055 | } |
||
7056 | |||
7057 | |||
7058 | /************************************************************************** |
||
7059 | Function: |
||
7060 | void GetPreviousEntry (FSFILE * fo) |
||
7061 | Summary: |
||
7062 | Get the file entry info for the parent dir of the specified dir |
||
7063 | Conditions: |
||
7064 | Should not be called by the user. |
||
7065 | Input: |
||
7066 | fo - The file to get the previous entry of |
||
7067 | Return Values: |
||
7068 | |||
7069 | -1 - The previous entry could not be retrieved |
||
7070 | Side Effects: |
||
7071 | None |
||
7072 | Description: |
||
7073 | The GetPreviousEntry function is used by the FSgetcwd function to |
||
7074 | load the previous (parent) directory. This function will load the |
||
7075 | parent directory and then search through the file entries in that |
||
7076 | directory for one that matches the cluster number of the original |
||
7077 | directory. When the matching entry is found, the name of the |
||
7078 | original directory is copied into the 'fo' FSFILE object. |
||
7079 | Remarks: |
||
7080 | None. |
||
7081 | **************************************************************************/ |
||
7082 | |||
7083 | BYTE GetPreviousEntry (FSFILE * fo) |
||
7084 | { |
||
7085 | BYTE i; |
||
7086 | WORD fHandle = 1; |
||
7087 | DWORD dirclus; |
||
7088 | DIRENTRY dirptr; |
||
7089 | |||
7090 | // Load the previous entry |
||
7091 | dirptr = Cache_File_Entry (fo, &fHandle, TRUE); |
||
7092 | if (dirptr == NULL) |
||
7093 | return -1; |
||
7094 | |||
7095 | // Get the cluster |
||
7096 | TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number. |
||
7097 | |||
7098 | if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT) |
||
7099 | { |
||
7100 | // The previous directory is the root |
||
7101 | fo->name[0] = '\\'; |
||
7102 | for (i = 0; i < 11; i++) |
||
7103 | { |
||
7104 | fo->name[i] = 0x20; |
||
7105 | } |
||
7106 | fo->dirclus = FatRootDirClusterValue; |
||
7107 | fo->dirccls = FatRootDirClusterValue; |
||
7108 | } |
||
7109 | else |
||
7110 | { |
||
7111 | // Get the directory name |
||
7112 | // Save the previous cluster value |
||
7113 | // Get the cluster |
||
7114 | |||
7115 | dirclus = TempClusterCalc; |
||
7116 | fo->dirclus = TempClusterCalc; |
||
7117 | fo->dirccls = TempClusterCalc; |
||
7118 | |||
7119 | |||
7120 | // Load the previous previous cluster |
||
7121 | dirptr = Cache_File_Entry (fo, &fHandle, TRUE); |
||
7122 | if (dirptr == NULL) |
||
7123 | return -1; |
||
7124 | |||
7125 | // Get the cluster |
||
7126 | TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number. |
||
7127 | #ifdef SUPPORT_FAT32 |
||
7128 | // If we're using FAT32 and the previous previous cluster is the root, the |
||
7129 | // value in the dotdot entry will be 0, but the actual cluster won't |
||
7130 | if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT) |
||
7131 | { |
||
7132 | fo->dirclus = FatRootDirClusterValue; |
||
7133 | } |
||
7134 | else |
||
7135 | #endif |
||
7136 | fo->dirclus = TempClusterCalc; |
||
7137 | |||
7138 | fo->dirccls = fo->dirclus; |
||
7139 | |||
7140 | fHandle = 0; |
||
7141 | dirptr = Cache_File_Entry (fo, &fHandle, TRUE); |
||
7142 | if (dirptr == NULL) |
||
7143 | return -1; |
||
7144 | // Look through it until we get the name |
||
7145 | // of the previous cluster |
||
7146 | // Get the cluster |
||
7147 | TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number. |
||
7148 | while ((TempClusterCalc != dirclus) || |
||
7149 | ((TempClusterCalc == dirclus) && |
||
7150 | (((unsigned char)dirptr->DIR_Name[0] == 0xE5) || (dirptr->DIR_Attr == ATTR_VOLUME) || (dirptr->DIR_Attr == ATTR_LONG_NAME)))) |
||
7151 | { |
||
7152 | // Look through the entries until we get the |
||
7153 | // right one |
||
7154 | dirptr = Cache_File_Entry (fo, &fHandle, FALSE); |
||
7155 | if (dirptr == NULL) |
||
7156 | return -1; |
||
7157 | fHandle++; |
||
7158 | |||
7159 | TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number in a loop. |
||
7160 | } |
||
7161 | |||
7162 | // The name should be in the entry now |
||
7163 | // Copy the actual directory location back |
||
7164 | for (i = 0; i < 11; i++) |
||
7165 | { |
||
7166 | fo->name[i] = dirptr->DIR_Name[i]; |
||
7167 | } |
||
7168 | fo->dirclus = dirclus; |
||
7169 | fo->dirccls = dirclus; |
||
7170 | } |
||
7171 | return 0; |
||
7172 | } |
||
7173 | |||
7174 | |||
7175 | /************************************************************************** |
||
7176 | Function: |
||
7177 | int FSmkdir (char * path) |
||
7178 | Summary: |
||
7179 | Create a directory |
||
7180 | Conditions: |
||
7181 | None |
||
7182 | Input: |
||
7183 | path - The path of directories to create. |
||
7184 | Return Values: |
||
7185 | |||
7186 | EOF - The specified directory could not be created |
||
7187 | Side Effects: |
||
7188 | Will create all non-existent directories in the path. The FSerrno |
||
7189 | variable will be changed. |
||
7190 | Description: |
||
7191 | The FSmkdir function passes a RAM pointer to the path to the |
||
7192 | mkdirhelper function. |
||
7193 | Remarks: |
||
7194 | None |
||
7195 | **************************************************************************/ |
||
7196 | |||
7197 | #ifdef ALLOW_WRITES |
||
7198 | int FSmkdir (char * path) |
||
7199 | { |
||
7200 | return mkdirhelper (0, path, NULL); |
||
7201 | } |
||
7202 | |||
7203 | /************************************************************************** |
||
7204 | Function: |
||
7205 | int FSmkdirpgm (const rom char * path) |
||
7206 | Summary: |
||
7207 | Create a directory with a path in ROM on PIC18 |
||
7208 | Conditions: |
||
7209 | None |
||
7210 | Input: |
||
7211 | path - The path of directories to create (ROM) |
||
7212 | Return Values: |
||
7213 | |||
7214 | EOF - The specified directory could not be created |
||
7215 | Side Effects: |
||
7216 | Will create all non-existent directories in the path. The FSerrno |
||
7217 | variable will be changed. |
||
7218 | Description: |
||
7219 | The FSmkdirpgm function passes a PIC18 ROM path pointer to the |
||
7220 | mkdirhelper function. |
||
7221 | Remarks: |
||
7222 | This function is for use with PIC18 when passing arugments in ROM |
||
7223 | **************************************************************************/ |
||
7224 | |||
7225 | #ifdef ALLOW_PGMFUNCTIONS |
||
7226 | int FSmkdirpgm (const rom char * path) |
||
7227 | { |
||
7228 | return mkdirhelper (1, NULL, path); |
||
7229 | } |
||
7230 | #endif |
||
7231 | |||
7232 | |||
7233 | /************************************************************************* |
||
7234 | Function: |
||
7235 | // PIC24/30/33/32 |
||
7236 | int mkdirhelper (BYTE mode, char * ramptr, char * romptr) |
||
7237 | // PIC18 |
||
7238 | int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr) |
||
7239 | Summary: |
||
7240 | Helper function for FSmkdir |
||
7241 | Conditions: |
||
7242 | None |
||
7243 | Input: |
||
7244 | mode - Indicates which path pointer to use |
||
7245 | ramptr - Pointer to the path specified in RAM |
||
7246 | romptr - Pointer to the path specified in ROM |
||
7247 | Return Values: |
||
7248 | |||
7249 | -1 - Directory could not be created |
||
7250 | Side Effects: |
||
7251 | Will create all non-existant directories in the path. |
||
7252 | The FSerrno variable will be changed. |
||
7253 | Description: |
||
7254 | This helper function is used by the FSchdir function. If the path |
||
7255 | argument is specified in ROM for PIC18 this function will be able |
||
7256 | to parse it correctly. This function will first scan through the path |
||
7257 | to ensure that any DIR names don't exceed 11 characters. It will then |
||
7258 | backup the current working directory and begin changing directories |
||
7259 | through the path until it reaches a directory than can't be changed to. |
||
7260 | It will then create the specified directory and change directories to |
||
7261 | the new directory. The function will continue creating and changing to |
||
7262 | directories until the end of the path is reached. The function will |
||
7263 | then restore the original current working directory. |
||
7264 | Remarks: |
||
7265 | None |
||
7266 | **************************************************************************/ |
||
7267 | |||
7268 | #ifdef ALLOW_PGMFUNCTIONS |
||
7269 | int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr) |
||
7270 | #else |
||
7271 | int mkdirhelper (BYTE mode, char * ramptr, char * romptr) |
||
7272 | #endif |
||
7273 | { |
||
7274 | BYTE i, j; |
||
7275 | char * temppath = ramptr; |
||
7276 | #ifdef ALLOW_PGMFUNCTIONS |
||
7277 | rom char * temppath2 = romptr; |
||
7278 | #endif |
||
7279 | char tempArray[13]; |
||
7280 | FILEOBJ tempCWD = &tempCWDobj; |
||
7281 | |||
7282 | #ifdef __18CXX |
||
7283 | char dotdotPath[] = ".."; |
||
7284 | #endif |
||
7285 | |||
7286 | FSerrno = CE_GOOD; |
||
7287 | |||
7288 | if (MDD_WriteProtectState()) |
||
7289 | { |
||
7290 | FSerrno = CE_WRITE_PROTECTED; |
||
7291 | return (-1); |
||
7292 | } |
||
7293 | |||
7294 | #ifdef ALLOW_PGMFUNCTIONS |
||
7295 | if (mode == 1) |
||
7296 | { |
||
7297 | // Scan for too-long file names |
||
7298 | while (1) |
||
7299 | { |
||
7300 | i = 0; |
||
7301 | while((*temppath2 != 0) && (*temppath2 != '.')&& (*temppath2 != '\\')) |
||
7302 | { |
||
7303 | temppath2++; |
||
7304 | i++; |
||
7305 | } |
||
7306 | if (i > 8) |
||
7307 | { |
||
7308 | FSerrno = CE_INVALID_ARGUMENT; |
||
7309 | return -1; |
||
7310 | } |
||
7311 | if (*temppath2 == '.') |
||
7312 | { |
||
7313 | temppath2++; |
||
7314 | i = 0; |
||
7315 | while ((*temppath2 != 0) && (*temppath2 != '\\')) |
||
7316 | { |
||
7317 | temppath2++; |
||
7318 | i++; |
||
7319 | } |
||
7320 | if (i > 3) |
||
7321 | { |
||
7322 | FSerrno = CE_INVALID_ARGUMENT; |
||
7323 | return -1; |
||
7324 | } |
||
7325 | } |
||
7326 | while (*temppath2 == '\\') |
||
7327 | temppath2++; |
||
7328 | if (*temppath2 == 0) |
||
7329 | break; |
||
7330 | } |
||
7331 | } |
||
7332 | else |
||
7333 | #endif |
||
7334 | // Scan for too-long file names |
||
7335 | while (1) |
||
7336 | { |
||
7337 | i = 0; |
||
7338 | while((*temppath != 0) && (*temppath != '.')&& (*temppath != '\\')) |
||
7339 | { |
||
7340 | temppath++; |
||
7341 | i++; |
||
7342 | } |
||
7343 | if (i > 8) |
||
7344 | { |
||
7345 | FSerrno = CE_INVALID_ARGUMENT; |
||
7346 | return -1; |
||
7347 | } |
||
7348 | if (*temppath == '.') |
||
7349 | { |
||
7350 | temppath++; |
||
7351 | i = 0; |
||
7352 | while ((*temppath != 0) && (*temppath != '\\')) |
||
7353 | { |
||
7354 | temppath++; |
||
7355 | i++; |
||
7356 | } |
||
7357 | if (i > 3) |
||
7358 | { |
||
7359 | FSerrno = CE_INVALID_ARGUMENT; |
||
7360 | return -1; |
||
7361 | } |
||
7362 | } |
||
7363 | while (*temppath == '\\') |
||
7364 | temppath++; |
||
7365 | if (*temppath == 0) |
||
7366 | break; |
||
7367 | } |
||
7368 | |||
7369 | temppath = ramptr; |
||
7370 | #ifdef ALLOW_PGMFUNCTIONS |
||
7371 | temppath2 = romptr; |
||
7372 | #endif |
||
7373 | |||
7374 | // We're going to be moving the CWD |
||
7375 | // Back up the CWD |
||
7376 | FileObjectCopy (tempCWD, cwdptr); |
||
7377 | |||
7378 | // get to the target directory |
||
7379 | while (1) |
||
7380 | { |
||
7381 | #ifdef ALLOW_PGMFUNCTIONS |
||
7382 | if (mode == 1) |
||
7383 | i = *temppath2; |
||
7384 | else |
||
7385 | #endif |
||
7386 | i = *temppath; |
||
7387 | |||
7388 | if (i == '.') |
||
7389 | { |
||
7390 | #ifdef ALLOW_PGMFUNCTIONS |
||
7391 | if (mode == 1) |
||
7392 | { |
||
7393 | temppath2++; |
||
7394 | i = *temppath2; |
||
7395 | } |
||
7396 | else |
||
7397 | { |
||
7398 | #endif |
||
7399 | temppath++; |
||
7400 | i = *temppath; |
||
7401 | #ifdef ALLOW_PGMFUNCTIONS |
||
7402 | } |
||
7403 | #endif |
||
7404 | |||
7405 | if ((i != '.') && (i != 0) && (i != '\\')) |
||
7406 | { |
||
7407 | FSerrno = CE_INVALID_ARGUMENT; |
||
7408 | return -1; |
||
7409 | } |
||
7410 | |||
7411 | if (i == '.') |
||
7412 | { |
||
7413 | if (cwdptr->dirclus == FatRootDirClusterValue) |
||
7414 | { |
||
7415 | // If we try to change to the .. from the |
||
7416 | // root, operation fails |
||
7417 | FSerrno = CE_INVALID_ARGUMENT; |
||
7418 | return -1; |
||
7419 | } |
||
7420 | #ifdef ALLOW_PGMFUNCTIONS |
||
7421 | if (mode == 1) |
||
7422 | { |
||
7423 | temppath2++; |
||
7424 | i = *temppath2; |
||
7425 | } |
||
7426 | else |
||
7427 | { |
||
7428 | #endif |
||
7429 | temppath++; |
||
7430 | i = *temppath; |
||
7431 | #ifdef ALLOW_PGMFUNCTIONS |
||
7432 | } |
||
7433 | #endif |
||
7434 | if ((i != '\\') && (i != 0)) |
||
7435 | { |
||
7436 | FSerrno = CE_INVALID_ARGUMENT; |
||
7437 | return -1; |
||
7438 | } |
||
7439 | // dotdot entry |
||
7440 | #ifndef __18CXX |
||
7441 | FSchdir (".."); |
||
7442 | #else |
||
7443 | FSchdir (dotdotPath); |
||
7444 | #endif |
||
7445 | } |
||
7446 | // Skip past any backslashes |
||
7447 | while (i == '\\') |
||
7448 | { |
||
7449 | #ifdef ALLOW_PGMFUNCTIONS |
||
7450 | if (mode == 1) |
||
7451 | { |
||
7452 | temppath2++; |
||
7453 | i = *temppath2; |
||
7454 | } |
||
7455 | else |
||
7456 | { |
||
7457 | #endif |
||
7458 | temppath++; |
||
7459 | i = *temppath; |
||
7460 | #ifdef ALLOW_PGMFUNCTIONS |
||
7461 | } |
||
7462 | #endif |
||
7463 | } |
||
7464 | if (i == 0) |
||
7465 | { |
||
7466 | // No point in creating a dot or dotdot entry directly |
||
7467 | FileObjectCopy (cwdptr, tempCWD); |
||
7468 | FSerrno = CE_INVALID_ARGUMENT; |
||
7469 | return -1; |
||
7470 | } |
||
7471 | } |
||
7472 | else |
||
7473 | { |
||
7474 | if (i == '\\') |
||
7475 | { |
||
7476 | // Start at the root |
||
7477 | cwdptr->dirclus = FatRootDirClusterValue; |
||
7478 | cwdptr->dirccls = FatRootDirClusterValue; |
||
7479 | cwdptr->name[0] = '\\'; |
||
7480 | for (i = 1; i < 11; i++) |
||
7481 | { |
||
7482 | cwdptr->name[i] = 0x20; |
||
7483 | } |
||
7484 | |||
7485 | #ifdef ALLOW_PGMFUNCTIONS |
||
7486 | if (mode == 1) |
||
7487 | { |
||
7488 | temppath2++; |
||
7489 | i = *temppath2; |
||
7490 | } |
||
7491 | else |
||
7492 | { |
||
7493 | #endif |
||
7494 | temppath++; |
||
7495 | i = *temppath; |
||
7496 | #ifdef ALLOW_PGMFUNCTIONS |
||
7497 | } |
||
7498 | #endif |
||
7499 | // If we just got two backslashes in a row at the |
||
7500 | // beginning of the path, the function fails |
||
7501 | if (i == '\\') |
||
7502 | { |
||
7503 | FileObjectCopy (cwdptr, tempCWD); |
||
7504 | FSerrno = CE_INVALID_ARGUMENT; |
||
7505 | return -1; |
||
7506 | } |
||
7507 | if (i == 0) |
||
7508 | { |
||
7509 | // We can't make the root dir |
||
7510 | FileObjectCopy (cwdptr, tempCWD); |
||
7511 | FSerrno = CE_INVALID_ARGUMENT; |
||
7512 | return -1; |
||
7513 | } |
||
7514 | } |
||
7515 | else |
||
7516 | { |
||
7517 | break; |
||
7518 | } |
||
7519 | } |
||
7520 | } |
||
7521 | |||
7522 | tempArray[12] = 0; |
||
7523 | while (1) |
||
7524 | { |
||
7525 | while(1) |
||
7526 | { |
||
7527 | #ifdef ALLOW_PGMFUNCTIONS |
||
7528 | if (mode == 1) |
||
7529 | { |
||
7530 | // Change directories as specified |
||
7531 | i = *temppath2; |
||
7532 | j = 0; |
||
7533 | // Parse the next token |
||
7534 | while ((i != 0) && (i != '\\') && (j < 12)) |
||
7535 | { |
||
7536 | tempArray[j++] = i; |
||
7537 | temppath2++; |
||
7538 | i = *temppath2; |
||
7539 | } |
||
7540 | } |
||
7541 | else |
||
7542 | { |
||
7543 | #endif |
||
7544 | // Change directories as specified |
||
7545 | i = *temppath; |
||
7546 | j = 0; |
||
7547 | // Parse the next token |
||
7548 | while ((i != 0) && (i != '\\') && (j < 12)) |
||
7549 | { |
||
7550 | tempArray[j++] = i; |
||
7551 | temppath++; |
||
7552 | i = *temppath; |
||
7553 | } |
||
7554 | #ifdef ALLOW_PGMFUNCTIONS |
||
7555 | } |
||
7556 | #endif |
||
7557 | tempArray[j] = 0; |
||
7558 | |||
7559 | if (tempArray[0] == '.') |
||
7560 | { |
||
7561 | if ((tempArray[1] != 0) && (tempArray[1] != '.')) |
||
7562 | { |
||
7563 | FileObjectCopy (cwdptr, tempCWD); |
||
7564 | FSerrno = CE_INVALID_ARGUMENT; |
||
7565 | return -1; |
||
7566 | } |
||
7567 | if ((tempArray[1] == '.') && (tempArray[2] != 0)) |
||
7568 | { |
||
7569 | FileObjectCopy (cwdptr, tempCWD); |
||
7570 | FSerrno = CE_INVALID_ARGUMENT; |
||
7571 | return -1; |
||
7572 | } |
||
7573 | } |
||
7574 | |||
7575 | // Try to change to it |
||
7576 | // If you can't we need to create it |
||
7577 | if (FSchdir (tempArray)) |
||
7578 | { |
||
7579 | break; |
||
7580 | } |
||
7581 | else |
||
7582 | { |
||
7583 | // We changed into the directory |
||
7584 | while (i == '\\') |
||
7585 | { |
||
7586 | // Next char is a backslash |
||
7587 | // Move past it |
||
7588 | #ifdef ALLOW_PGMFUNCTIONS |
||
7589 | if (mode == 1) |
||
7590 | { |
||
7591 | temppath2++; |
||
7592 | i = *temppath2; |
||
7593 | } |
||
7594 | else |
||
7595 | { |
||
7596 | #endif |
||
7597 | temppath++; |
||
7598 | i = *temppath; |
||
7599 | #ifdef ALLOW_PGMFUNCTIONS |
||
7600 | } |
||
7601 | #endif |
||
7602 | } |
||
7603 | // If it's the last one, return success |
||
7604 | if (i == 0) |
||
7605 | { |
||
7606 | FileObjectCopy (cwdptr, tempCWD); |
||
7607 | return 0; |
||
7608 | } |
||
7609 | } |
||
7610 | } |
||
7611 | |||
7612 | // Create a dir here |
||
7613 | if (!CreateDIR (tempArray)) |
||
7614 | { |
||
7615 | FileObjectCopy (cwdptr, tempCWD); |
||
7616 | return -1; |
||
7617 | } |
||
7618 | |||
7619 | // Try to change to that directory |
||
7620 | if (FSchdir (tempArray)) |
||
7621 | { |
||
7622 | FileObjectCopy (cwdptr, tempCWD); |
||
7623 | FSerrno = CE_BADCACHEREAD; |
||
7624 | return -1; |
||
7625 | } |
||
7626 | |||
7627 | #ifdef ALLOW_PGMFUNCTIONS |
||
7628 | if (mode == 1) |
||
7629 | { |
||
7630 | // Check for another backslash |
||
7631 | while (*temppath2 == '\\') |
||
7632 | { |
||
7633 | temppath2++; |
||
7634 | i = *temppath2; |
||
7635 | } |
||
7636 | } |
||
7637 | else |
||
7638 | { |
||
7639 | #endif |
||
7640 | while (*temppath == '\\') |
||
7641 | { |
||
7642 | temppath++; |
||
7643 | i = *temppath; |
||
7644 | } |
||
7645 | #ifdef ALLOW_PGMFUNCTIONS |
||
7646 | } |
||
7647 | #endif |
||
7648 | |||
7649 | // Check to see if we're at the end of the path string |
||
7650 | if (i == 0) |
||
7651 | { |
||
7652 | // We already have one |
||
7653 | FileObjectCopy (cwdptr, tempCWD); |
||
7654 | return 0; |
||
7655 | } |
||
7656 | } |
||
7657 | } |
||
7658 | |||
7659 | |||
7660 | /************************************************************************** |
||
7661 | Function: |
||
7662 | int CreateDIR (char * path) |
||
7663 | Summary: |
||
7664 | FSmkdir helper function to create a directory |
||
7665 | Conditions: |
||
7666 | This function should not be called by the user. |
||
7667 | Input: |
||
7668 | path - The name of the dir to create |
||
7669 | Return Values: |
||
7670 | TRUE - Directory was created successfully |
||
7671 | FALSE - Directory could not be created. |
||
7672 | Side Effects: |
||
7673 | Any unwritten data in the data buffer or the FAT buffer will be written |
||
7674 | to the device. |
||
7675 | Description: |
||
7676 | The CreateDIR function is a helper function for the mkdirhelper |
||
7677 | function. The CreateDIR function will create a new file entry for |
||
7678 | a directory and assign a cluster to it. It will erase the cluster |
||
7679 | and write a dot and dotdot entry to it. |
||
7680 | Remarks: |
||
7681 | None. |
||
7682 | **************************************************************************/ |
||
7683 | |||
7684 | int CreateDIR (char * path) |
||
7685 | { |
||
7686 | FSFILE * dirEntryPtr = &gFileTemp; |
||
7687 | DIRENTRY dir; |
||
7688 | WORD handle = 0; |
||
7689 | DWORD dot, dotdot; |
||
7690 | BYTE i; |
||
7691 | |||
7692 | for (i = 0; i < 12; i++) |
||
7693 | { |
||
7694 | defaultString[i] = *(path + i); |
||
7695 | } |
||
7696 | |||
7697 | if (FormatDirName(defaultString, 0) == FALSE) |
||
7698 | { |
||
7699 | FSerrno = CE_INVALID_FILENAME; |
||
7700 | return FALSE; |
||
7701 | } |
||
7702 | |||
7703 | // Copy name into file object |
||
7704 | for (i = 0; i < 11; i++) |
||
7705 | { |
||
7706 | dirEntryPtr->name[i] = defaultString[i]; |
||
7707 | } |
||
7708 | |||
7709 | dirEntryPtr->dirclus = cwdptr->dirclus; |
||
7710 | dirEntryPtr->dirccls = cwdptr->dirccls; |
||
7711 | dirEntryPtr->cluster = 0; |
||
7712 | dirEntryPtr->ccls = 0; |
||
7713 | dirEntryPtr->dsk = cwdptr->dsk; |
||
7714 | |||
7715 | // Create a directory entry |
||
7716 | if(CreateFileEntry(dirEntryPtr, &handle, DIRECTORY) != CE_GOOD) |
||
7717 | { |
||
7718 | return FALSE; |
||
7719 | } |
||
7720 | else |
||
7721 | { |
||
7722 | if (gNeedFATWrite) |
||
7723 | if(WriteFAT (dirEntryPtr->dsk, 0, 0, TRUE)) |
||
7724 | { |
||
7725 | FSerrno = CE_WRITE_ERROR; |
||
7726 | return FALSE; |
||
7727 | } |
||
7728 | // Zero that cluster |
||
7729 | if (dirEntryPtr->dirclus == FatRootDirClusterValue) |
||
7730 | dotdot = 0; |
||
7731 | else |
||
7732 | dotdot = dirEntryPtr->dirclus; |
||
7733 | dirEntryPtr->dirccls = dirEntryPtr->dirclus; |
||
7734 | dir = Cache_File_Entry(dirEntryPtr, &handle, TRUE); |
||
7735 | if (dir == NULL) |
||
7736 | { |
||
7737 | FSerrno = CE_BADCACHEREAD; |
||
7738 | return FALSE; |
||
7739 | } |
||
7740 | |||
7741 | // Get the cluster |
||
7742 | dot = GetFullClusterNumber(dir); // Get complete cluster number. |
||
7743 | |||
7744 | if (writeDotEntries (dirEntryPtr->dsk, dot, dotdot)) |
||
7745 | return TRUE; |
||
7746 | else |
||
7747 | return FALSE; |
||
7748 | |||
7749 | } |
||
7750 | } |
||
7751 | |||
7752 | |||
7753 | /*********************************************************************************** |
||
7754 | Function: |
||
7755 | BYTE writeDotEntries (DISK * disk, DWORD dotAddress, DWORD dotdotAddress) |
||
7756 | Summary: |
||
7757 | Create dot and dotdot entries in a non-root directory |
||
7758 | Conditions: |
||
7759 | This function should not be called by the user. |
||
7760 | Input: |
||
7761 | disk - The global disk structure |
||
7762 | dotAddress - The cluster the current dir is in |
||
7763 | dotdotAddress - The cluster the previous directory was in |
||
7764 | Return Values: |
||
7765 | TRUE - The dot and dotdot entries were created |
||
7766 | FALSE - The dot and dotdot entries could not be created in the new directory |
||
7767 | Side Effects: |
||
7768 | None |
||
7769 | Description: |
||
7770 | The writeDotEntries function will create and write dot and dotdot entries |
||
7771 | to a newly created directory. |
||
7772 | Remarks: |
||
7773 | None. |
||
7774 | ***********************************************************************************/ |
||
7775 | |||
7776 | BYTE writeDotEntries (DISK * disk, DWORD dotAddress, DWORD dotdotAddress) |
||
7777 | { |
||
7778 | WORD i; |
||
7779 | WORD size; |
||
7780 | _DIRENTRY entry; |
||
7781 | DIRENTRY entryptr = &entry; |
||
7782 | DWORD sector; |
||
7783 | |||
7784 | gBufferOwner = NULL; |
||
7785 | |||
7786 | size = sizeof (_DIRENTRY); |
||
7787 | |||
7788 | memset(disk->buffer, 0x00, MEDIA_SECTOR_SIZE); |
||
7789 | |||
7790 | entry.DIR_Name[0] = '.'; |
||
7791 | |||
7792 | for (i = 1; i < 11; i++) |
||
7793 | { |
||
7794 | entry.DIR_Name[i] = 0x20; |
||
7795 | } |
||
7796 | entry.DIR_Attr = ATTR_DIRECTORY; |
||
7797 | entry.DIR_NTRes = 0x00; |
||
7798 | |||
7799 | entry.DIR_FstClusLO = (WORD)(dotAddress & 0x0000FFFF); // Lower 16 bit address |
||
7800 | |||
7801 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
7802 | entry.DIR_FstClusHI = (WORD)((dotAddress & 0x0FFF0000)>> 16); // Higher 16 bit address. FAT32 uses only 28 bits. Mask even higher nibble also. |
||
7803 | #else // If FAT32 support not enabled |
||
7804 | entry.DIR_FstClusHI = 0; |
||
7805 | #endif |
||
7806 | |||
7807 | entry.DIR_FileSize = 0x00; |
||
7808 | |||
7809 | // Times need to be the same as the times in the directory entry |
||
7810 | |||
7811 | // Set dir date for uncontrolled clock source |
||
7812 | #ifdef INCREMENTTIMESTAMP |
||
7813 | entry.DIR_CrtTimeTenth = 0xB2; |
||
7814 | entry.DIR_CrtTime = 0x7278; |
||
7815 | entry.DIR_CrtDate = 0x32B0; |
||
7816 | entry.DIR_LstAccDate = 0x0000; |
||
7817 | entry.DIR_WrtTime = 0x0000; |
||
7818 | entry.DIR_WrtDate = 0x0000; |
||
7819 | #endif |
||
7820 | |||
7821 | #ifdef USEREALTIMECLOCK |
||
7822 | entry.DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp |
||
7823 | entry.DIR_CrtTime = gTimeCrtTime; // time created // |
||
7824 | entry.DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004) |
||
7825 | entry.DIR_LstAccDate = 0x0000; // Last Access date |
||
7826 | entry.DIR_WrtTime = 0x0000; // last update time |
||
7827 | entry.DIR_WrtDate = 0x0000; // last update date |
||
7828 | #endif |
||
7829 | |||
7830 | #ifdef USERDEFINEDCLOCK |
||
7831 | entry.DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp |
||
7832 | entry.DIR_CrtTime = gTimeCrtTime; // time created // |
||
7833 | entry.DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004) |
||
7834 | entry.DIR_LstAccDate = 0x0000; // Last Access date |
||
7835 | entry.DIR_WrtTime = 0x0000; // last update time |
||
7836 | entry.DIR_WrtDate = 0x0000; // last update date |
||
7837 | #endif |
||
7838 | |||
7839 | for (i = 0; i < size; i++) |
||
7840 | { |
||
7841 | *(disk->buffer + i) = *((char *)entryptr + i); |
||
7842 | } |
||
7843 | entry.DIR_Name[1] = '.'; |
||
7844 | |||
7845 | entry.DIR_FstClusLO = (WORD)(dotdotAddress & 0x0000FFFF); // Lower 16 bit address |
||
7846 | |||
7847 | #ifdef SUPPORT_FAT32 // If FAT32 supported. |
||
7848 | entry.DIR_FstClusHI = (WORD)((dotdotAddress & 0x0FFF0000)>> 16); // Higher 16 bit address. FAT32 uses only 28 bits. Mask even higher nibble also. |
||
7849 | #else // If FAT32 support not enabled |
||
7850 | entry.DIR_FstClusHI = 0; |
||
7851 | #endif |
||
7852 | |||
7853 | |||
7854 | for (i = 0; i < size; i++) |
||
7855 | { |
||
7856 | *(disk->buffer + i + size) = *((char *)entryptr + i); |
||
7857 | } |
||
7858 | |||
7859 | sector = Cluster2Sector (disk, dotAddress); |
||
7860 | |||
7861 | if (MDD_SectorWrite(sector, disk->buffer, FALSE) == FALSE) |
||
7862 | { |
||
7863 | FSerrno = CE_WRITE_ERROR; |
||
7864 | return FALSE; |
||
7865 | } |
||
7866 | |||
7867 | return TRUE; |
||
7868 | } |
||
7869 | |||
7870 | // This array is used to prevent a stack frame error |
||
7871 | #ifdef __18CXX |
||
7872 | char tempArray[13] = " "; |
||
7873 | #endif |
||
7874 | |||
7875 | |||
7876 | /************************************************************************** |
||
7877 | Function: |
||
7878 | int FSrmdir (char * path) |
||
7879 | Summary: |
||
7880 | Delete a directory |
||
7881 | Conditions: |
||
7882 | None |
||
7883 | Input: |
||
7884 | path - The path of the directory to remove |
||
7885 | rmsubdirs - |
||
7886 | - TRUE - All sub-dirs and files in the target dir will be removed |
||
7887 | - FALSE - FSrmdir will not remove non-empty directories |
||
7888 | Return Values: |
||
7889 | |||
7890 | EOF - The specified directory could not be deleted |
||
7891 | Side Effects: |
||
7892 | The FSerrno variable will be changed. |
||
7893 | Description: |
||
7894 | The FSrmdir function passes a RAM pointer to the path to the |
||
7895 | rmdirhelper function. |
||
7896 | Remarks: |
||
7897 | None. |
||
7898 | **************************************************************************/ |
||
7899 | |||
7900 | int FSrmdir (char * path, unsigned char rmsubdirs) |
||
7901 | { |
||
7902 | return rmdirhelper (0, path, NULL, rmsubdirs); |
||
7903 | } |
||
7904 | |||
7905 | /************************************************************************** |
||
7906 | Function: |
||
7907 | int FSrmdirpgm (const rom char * path) |
||
7908 | Summary: |
||
7909 | Delete a directory with a path in ROM on PIC18 |
||
7910 | Conditions: |
||
7911 | None. |
||
7912 | Input: |
||
7913 | path - The path of the directory to remove (ROM) |
||
7914 | rmsubdirs - |
||
7915 | - TRUE - All sub-dirs and files in the target dir will be removed |
||
7916 | - FALSE - FSrmdir will not remove non-empty directories |
||
7917 | Return Values: |
||
7918 | |||
7919 | EOF - The specified directory could not be deleted |
||
7920 | Side Effects: |
||
7921 | The FSerrno variable will be changed. |
||
7922 | Description: |
||
7923 | The FSrmdirpgm function passes a PIC18 ROM path pointer to the |
||
7924 | rmdirhelper function. |
||
7925 | Remarks: |
||
7926 | This function is for use with PIC18 when passing arguments in ROM. |
||
7927 | **************************************************************************/ |
||
7928 | |||
7929 | #ifdef ALLOW_PGMFUNCTIONS |
||
7930 | int FSrmdirpgm (const rom char * path, unsigned char rmsubdirs) |
||
7931 | { |
||
7932 | return rmdirhelper (1, NULL, path, rmsubdirs); |
||
7933 | } |
||
7934 | #endif |
||
7935 | |||
7936 | /************************************************************************************************ |
||
7937 | Function: |
||
7938 | // PIC24/30/33/32 |
||
7939 | int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs) |
||
7940 | // PIC18 |
||
7941 | int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs) |
||
7942 | Summary: |
||
7943 | Helper function for FSrmdir |
||
7944 | Conditions: |
||
7945 | This function should not be called by the user. |
||
7946 | Input: |
||
7947 | path - The path of the dir to delete |
||
7948 | rmsubdirs - |
||
7949 | - TRUE - Remove all sub-directories and files in the directory |
||
7950 | - FALSE - Non-empty directories can not be removed |
||
7951 | Return Values: |
||
7952 | |||
7953 | EOF - The specified directory could not be removed. |
||
7954 | Side Effects: |
||
7955 | The FSerrno variable will be changed. |
||
7956 | Description: |
||
7957 | This helper function is used by the FSmkdir function. If the path |
||
7958 | argument is specified in ROM for PIC18 this function will be able |
||
7959 | to parse it correctly. This function will first change to the |
||
7960 | specified directory. If the rmsubdirs argument is FALSE the function |
||
7961 | will search through the directory to ensure that it is empty and then |
||
7962 | remove it. If the rmsubdirs argument is TRUE the function will also |
||
7963 | search through the directory for subdirectories or files. When the |
||
7964 | function finds a file, the file will be erased. When the function |
||
7965 | finds a subdirectory, it will switch to the subdirectory and begin |
||
7966 | removing all of the files in that subdirectory. Once the subdirectory |
||
7967 | is empty, the function will switch back to the original directory. |
||
7968 | return to the original position in that directory, and continue removing |
||
7969 | files. Once the specified directory is empty, the function will |
||
7970 | change to the parent directory, search through it for the directory |
||
7971 | to remove, and then erase that directory. |
||
7972 | Remarks: |
||
7973 | None. |
||
7974 | ************************************************************************************************/ |
||
7975 | |||
7976 | #ifdef ALLOW_PGMFUNCTIONS |
||
7977 | int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs) |
||
7978 | #else |
||
7979 | int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs) |
||
7980 | #endif |
||
7981 | { |
||
7982 | FILEOBJ tempCWD = &tempCWDobj; |
||
7983 | FILEOBJ fo = &gFileTemp; |
||
7984 | DIRENTRY entry; |
||
7985 | WORD handle = 0; |
||
7986 | WORD handle2; |
||
7987 | WORD subDirDepth; |
||
7988 | BYTE Index, Index2; |
||
7989 | |||
7990 | #ifndef __18CXX |
||
7991 | char tempArray[13] = " "; |
||
7992 | #else |
||
7993 | char dotdotname[] = ".."; |
||
7994 | #endif |
||
7995 | |||
7996 | FSerrno = CE_GOOD; |
||
7997 | |||
7998 | // Back up the current working directory |
||
7999 | FileObjectCopy (tempCWD, cwdptr); |
||
8000 | |||
8001 | #ifdef ALLOW_PGMFUNCTIONS |
||
8002 | if (mode) |
||
8003 | { |
||
8004 | if (chdirhelper (1, NULL, romptr)) |
||
8005 | { |
||
8006 | FSerrno = CE_DIR_NOT_FOUND; |
||
8007 | return -1; |
||
8008 | } |
||
8009 | } |
||
8010 | else |
||
8011 | { |
||
8012 | #endif |
||
8013 | if (FSchdir (ramptr)) |
||
8014 | { |
||
8015 | FSerrno = CE_DIR_NOT_FOUND; |
||
8016 | return -1; |
||
8017 | } |
||
8018 | #ifdef ALLOW_PGMFUNCTIONS |
||
8019 | } |
||
8020 | #endif |
||
8021 | |||
8022 | // Make sure we aren't trying to remove the root dir or the CWD |
||
8023 | if ((cwdptr->dirclus == FatRootDirClusterValue) || (cwdptr->dirclus == tempCWD->dirclus)) |
||
8024 | { |
||
8025 | FileObjectCopy (cwdptr, tempCWD); |
||
8026 | FSerrno = CE_INVALID_ARGUMENT; |
||
8027 | return -1; |
||
8028 | } |
||
8029 | |||
8030 | handle++; |
||
8031 | entry = Cache_File_Entry (cwdptr, &handle, TRUE); |
||
8032 | |||
8033 | if (entry == NULL) |
||
8034 | { |
||
8035 | FileObjectCopy (cwdptr, tempCWD); |
||
8036 | FSerrno = CE_BADCACHEREAD; |
||
8037 | return -1; |
||
8038 | } |
||
8039 | |||
8040 | handle++; |
||
8041 | entry = Cache_File_Entry (cwdptr, &handle, FALSE); |
||
8042 | if (entry == NULL) |
||
8043 | { |
||
8044 | FileObjectCopy (cwdptr, tempCWD); |
||
8045 | FSerrno = CE_BADCACHEREAD; |
||
8046 | return -1; |
||
8047 | } |
||
8048 | // Don't remove subdirectories and sub-files |
||
8049 | if (!rmsubdirs) |
||
8050 | { |
||
8051 | while (entry->DIR_Name[0] != 0) |
||
8052 | { |
||
8053 | if ((unsigned char)entry->DIR_Name[0] != 0xE5) |
||
8054 | { |
||
8055 | FileObjectCopy (cwdptr, tempCWD); |
||
8056 | FSerrno = CE_DIR_NOT_EMPTY; |
||
8057 | return -1; |
||
8058 | } |
||
8059 | handle++; |
||
8060 | entry = Cache_File_Entry (cwdptr, &handle, FALSE); |
||
8061 | if ((entry == NULL)) |
||
8062 | { |
||
8063 | FileObjectCopy (cwdptr, tempCWD); |
||
8064 | FSerrno = CE_BADCACHEREAD; |
||
8065 | return -1; |
||
8066 | } |
||
8067 | } |
||
8068 | } |
||
8069 | else |
||
8070 | { |
||
8071 | // Do remove subdirectories and sub-files |
||
8072 | dirCleared = FALSE; |
||
8073 | subDirDepth = 0; |
||
8074 | |||
8075 | while (!dirCleared) |
||
8076 | { |
||
8077 | if (entry->DIR_Name[0] != 0) |
||
8078 | { |
||
8079 | if (((unsigned char)entry->DIR_Name[0] != 0xE5) && (entry->DIR_Attr != ATTR_VOLUME) && (entry->DIR_Attr != ATTR_LONG_NAME)) |
||
8080 | { |
||
8081 | if ((entry->DIR_Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY) |
||
8082 | { |
||
8083 | // We have a directory |
||
8084 | subDirDepth++; |
||
8085 | for (Index = 0; (Index < DIR_NAMESIZE) && (entry->DIR_Name[Index] != 0x20); Index++) |
||
8086 | { |
||
8087 | tempArray[Index] = entry->DIR_Name[Index]; |
||
8088 | } |
||
8089 | if (entry->DIR_Name[8] != 0x20) |
||
8090 | { |
||
8091 | tempArray[Index++] = '.'; |
||
8092 | for (Index2 = 0; (Index2 < DIR_EXTENSION) && (entry->DIR_Name[Index2 + DIR_NAMESIZE] != 0x20); Index2++) |
||
8093 | { |
||
8094 | tempArray[Index++] = entry->DIR_Name[Index2 + DIR_NAMESIZE]; |
||
8095 | } |
||
8096 | } |
||
8097 | tempArray[Index] = 0; |
||
8098 | // Change to the subdirectory |
||
8099 | if (FSchdir (tempArray)) |
||
8100 | { |
||
8101 | FileObjectCopy (cwdptr, tempCWD); |
||
8102 | FSerrno = CE_DIR_NOT_FOUND; |
||
8103 | return -1; |
||
8104 | } |
||
8105 | else |
||
8106 | { |
||
8107 | // Make sure we're not trying to delete the CWD |
||
8108 | if (cwdptr->dirclus == tempCWD->dirclus) |
||
8109 | { |
||
8110 | FileObjectCopy (cwdptr, tempCWD); |
||
8111 | FSerrno = CE_INVALID_ARGUMENT; |
||
8112 | return -1; |
||
8113 | } |
||
8114 | } |
||
8115 | handle = 2; |
||
8116 | recache = TRUE; |
||
8117 | } |
||
8118 | else |
||
8119 | { |
||
8120 | memset (tempArray, 0x00, 12); |
||
8121 | for (Index = 0; Index < 11; Index++) |
||
8122 | { |
||
8123 | fo->name[Index] = entry->DIR_Name[Index]; |
||
8124 | } |
||
8125 | |||
8126 | fo->dsk = &gDiskData; |
||
8127 | |||
8128 | fo->entry = handle; |
||
8129 | fo->dirclus = cwdptr->dirclus; |
||
8130 | fo->dirccls = cwdptr->dirccls; |
||
8131 | fo->cluster = 0; |
||
8132 | fo->ccls = 0; |
||
8133 | |||
8134 | if (FILEerase(fo, &handle, TRUE)) |
||
8135 | { |
||
8136 | FileObjectCopy (cwdptr, tempCWD); |
||
8137 | FSerrno = CE_ERASE_FAIL; |
||
8138 | return -1; |
||
8139 | } |
||
8140 | else |
||
8141 | { |
||
8142 | handle++; |
||
8143 | } |
||
8144 | } // Check to see if it's a DIR entry |
||
8145 | }// Check non-dir entry to see if its a valid file |
||
8146 | else |
||
8147 | { |
||
8148 | handle++; |
||
8149 | } |
||
8150 | if (recache) |
||
8151 | { |
||
8152 | recache = FALSE; |
||
8153 | cwdptr->dirccls = cwdptr->dirclus; |
||
8154 | entry = Cache_File_Entry (cwdptr, &handle, TRUE); |
||
8155 | } |
||
8156 | else |
||
8157 | { |
||
8158 | entry = Cache_File_Entry (cwdptr, &handle, FALSE); |
||
8159 | } |
||
8160 | if (entry == NULL) |
||
8161 | { |
||
8162 | FileObjectCopy (cwdptr, tempCWD); |
||
8163 | FSerrno = CE_BADCACHEREAD; |
||
8164 | return -1; |
||
8165 | } |
||
8166 | } |
||
8167 | else |
||
8168 | { |
||
8169 | // We have reached the end of the directory |
||
8170 | if (subDirDepth != 0) |
||
8171 | { |
||
8172 | handle2 = 0; |
||
8173 | |||
8174 | cwdptr->dirccls = cwdptr->dirclus; |
||
8175 | entry = Cache_File_Entry (cwdptr, &handle2, TRUE); |
||
8176 | if (entry == NULL) |
||
8177 | { |
||
8178 | FileObjectCopy (cwdptr, tempCWD); |
||
8179 | FSerrno = CE_BADCACHEREAD; |
||
8180 | return -1; |
||
8181 | } |
||
8182 | |||
8183 | // Get the cluster |
||
8184 | handle2 = GetFullClusterNumber(entry); // Get complete cluster number. |
||
8185 | |||
8186 | #ifndef __18CXX |
||
8187 | if (FSchdir ("..")) |
||
8188 | #else |
||
8189 | if (FSchdir (dotdotname)) |
||
8190 | #endif |
||
8191 | { |
||
8192 | FileObjectCopy (cwdptr, tempCWD); |
||
8193 | FSerrno = CE_DIR_NOT_FOUND; |
||
8194 | return -1; |
||
8195 | } |
||
8196 | // Return to our previous position in this directory |
||
8197 | handle = 2; |
||
8198 | cwdptr->dirccls = cwdptr->dirclus; |
||
8199 | entry = Cache_File_Entry (cwdptr, &handle, TRUE); |
||
8200 | if (entry == NULL) |
||
8201 | { |
||
8202 | FileObjectCopy (cwdptr, tempCWD); |
||
8203 | FSerrno = CE_BADCACHEREAD; |
||
8204 | return -1; |
||
8205 | } |
||
8206 | |||
8207 | // Get the cluster |
||
8208 | TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number. |
||
8209 | |||
8210 | while ((TempClusterCalc != handle2) || |
||
8211 | ((TempClusterCalc == handle2) && |
||
8212 | (((unsigned char)entry->DIR_Name[0] == 0xE5) || (entry->DIR_Attr == ATTR_VOLUME)))) |
||
8213 | { |
||
8214 | handle++; |
||
8215 | entry = Cache_File_Entry (cwdptr, &handle, FALSE); |
||
8216 | if (entry == NULL) |
||
8217 | { |
||
8218 | FileObjectCopy (cwdptr, tempCWD); |
||
8219 | FSerrno = CE_BADCACHEREAD; |
||
8220 | return -1; |
||
8221 | } |
||
8222 | // Get the cluster |
||
8223 | TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number in a loop. |
||
8224 | } |
||
8225 | // Erase the directory that we just cleared the subdirectories out of |
||
8226 | memset (tempArray, 0x00, 12); |
||
8227 | for (Index = 0; Index < 11; Index++) |
||
8228 | { |
||
8229 | tempArray[Index] = entry->DIR_Name[Index]; |
||
8230 | } |
||
8231 | if (eraseDir (tempArray)) |
||
8232 | { |
||
8233 | FileObjectCopy (cwdptr, tempCWD); |
||
8234 | FSerrno = CE_ERASE_FAIL; |
||
8235 | return -1; |
||
8236 | } |
||
8237 | else |
||
8238 | { |
||
8239 | handle++; |
||
8240 | cwdptr->dirccls = cwdptr->dirclus; |
||
8241 | entry = Cache_File_Entry (cwdptr, &handle, TRUE); |
||
8242 | if (entry == NULL) |
||
8243 | { |
||
8244 | FileObjectCopy (cwdptr, tempCWD); |
||
8245 | FSerrno = CE_BADCACHEREAD; |
||
8246 | return -1; |
||
8247 | } |
||
8248 | } |
||
8249 | |||
8250 | // Decrease the subdirectory depth |
||
8251 | subDirDepth--; |
||
8252 | } |
||
8253 | else |
||
8254 | { |
||
8255 | dirCleared = TRUE; |
||
8256 | } // Check subdirectory depth |
||
8257 | } // Check until we get an empty entry |
||
8258 | } // Loop until the whole dir is cleared |
||
8259 | } |
||
8260 | |||
8261 | // Cache the current directory name |
||
8262 | // tempArray is used so we don't disturb the |
||
8263 | // global getcwd buffer |
||
8264 | if (FSgetcwd (tempArray, 12) == NULL) |
||
8265 | { |
||
8266 | FileObjectCopy (cwdptr, tempCWD); |
||
8267 | return -1; |
||
8268 | } |
||
8269 | |||
8270 | memset(tempArray, 0x00, 12); |
||
8271 | |||
8272 | for (Index = 0; Index < 11; Index++) |
||
8273 | { |
||
8274 | tempArray[Index] = cwdptr->name[Index]; |
||
8275 | } |
||
8276 | |||
8277 | // If we're here, this directory is empty |
||
8278 | #ifndef __18CXX |
||
8279 | if (FSchdir ("..")) |
||
8280 | #else |
||
8281 | if (FSchdir (dotdotname)) |
||
8282 | #endif |
||
8283 | { |
||
8284 | FileObjectCopy (cwdptr, tempCWD); |
||
8285 | FSerrno = CE_DIR_NOT_FOUND; |
||
8286 | return -1; |
||
8287 | } |
||
8288 | |||
8289 | if (eraseDir (tempArray)) |
||
8290 | { |
||
8291 | FileObjectCopy (cwdptr, tempCWD); |
||
8292 | FSerrno = CE_ERASE_FAIL; |
||
8293 | return -1; |
||
8294 | } |
||
8295 | else |
||
8296 | { |
||
8297 | FileObjectCopy (cwdptr, tempCWD); |
||
8298 | return 0; |
||
8299 | } |
||
8300 | } |
||
8301 | |||
8302 | |||
8303 | /**************************************************************** |
||
8304 | Function: |
||
8305 | int eraseDir (char * path) |
||
8306 | Summary: |
||
8307 | FSrmdir helper function to erase dirs |
||
8308 | Conditions: |
||
8309 | This function should not be called by the user. |
||
8310 | Input: |
||
8311 | path - The name of the directory to delete |
||
8312 | Return Values: |
||
8313 | |||
8314 | -1 - Dir could not be deleted. |
||
8315 | Side Effects: |
||
8316 | None |
||
8317 | Description: |
||
8318 | The eraseDir function is a helper function for the rmdirhelper |
||
8319 | function. The eraseDir function will search for the |
||
8320 | directory that matches the specified path name and then erase |
||
8321 | it with the FILEerase function. |
||
8322 | Remarks: |
||
8323 | None. |
||
8324 | *****************************************************************/ |
||
8325 | |||
8326 | int eraseDir (char * path) |
||
8327 | { |
||
8328 | CETYPE result; |
||
8329 | BYTE Index; |
||
8330 | FSFILE tempCWDobj2; |
||
8331 | |||
8332 | if (MDD_WriteProtectState()) |
||
8333 | { |
||
8334 | return (-1); |
||
8335 | } |
||
8336 | |||
8337 | // preserve CWD |
||
8338 | FileObjectCopy(&tempCWDobj2, cwdptr); |
||
8339 | |||
8340 | for (Index = 0; Index <11; Index++) |
||
8341 | { |
||
8342 | cwdptr->name[Index] = *(path + Index); |
||
8343 | } |
||
8344 | |||
8345 | // copy file object over |
||
8346 | FileObjectCopy(&gFileTemp, cwdptr); |
||
8347 | |||
8348 | // See if the file is found |
||
8349 | result = FILEfind (cwdptr, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0); |
||
8350 | |||
8351 | if (result != CE_GOOD) |
||
8352 | { |
||
8353 | FileObjectCopy(cwdptr, &tempCWDobj2); |
||
8354 | return -1; |
||
8355 | } |
||
8356 | result = FILEerase(cwdptr, &cwdptr->entry, TRUE); |
||
8357 | if( result == CE_GOOD ) |
||
8358 | { |
||
8359 | FileObjectCopy(cwdptr, &tempCWDobj2); |
||
8360 | return 0; |
||
8361 | } |
||
8362 | else |
||
8363 | { |
||
8364 | FileObjectCopy(cwdptr, &tempCWDobj2); |
||
8365 | return -1; |
||
8366 | } |
||
8367 | } |
||
8368 | #endif |
||
8369 | |||
8370 | |||
8371 | |||
8372 | #endif |
||
8373 | |||
8374 | |||
8375 | #ifdef ALLOW_FILESEARCH |
||
8376 | |||
8377 | |||
8378 | /*********************************************************************************** |
||
8379 | Function: |
||
8380 | int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec) |
||
8381 | Summary: |
||
8382 | Initial search function |
||
8383 | Conditions: |
||
8384 | None |
||
8385 | Input: |
||
8386 | fileName - The name to search for |
||
8387 | - Parital string search characters |
||
8388 | - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*) |
||
8389 | - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T) |
||
8390 | attr - The attributes that a found file may have |
||
8391 | - ATTR_READ_ONLY - File may be read only |
||
8392 | - ATTR_HIDDEN - File may be a hidden file |
||
8393 | - ATTR_SYSTEM - File may be a system file |
||
8394 | - ATTR_VOLUME - Entry may be a volume label |
||
8395 | - ATTR_DIRECTORY - File may be a directory |
||
8396 | - ATTR_ARCHIVE - File may have archive attribute |
||
8397 | - ATTR_MASK - All attributes |
||
8398 | rec - pointer to a structure to put the file information in |
||
8399 | Return Values: |
||
8400 | |||
8401 | -1 - No file matching the specified criteria was found |
||
8402 | Side Effects: |
||
8403 | Search criteria from previous FindFirst call on passed SearchRec object |
||
8404 | will be lost. The FSerrno variable will be changed. |
||
8405 | Description: |
||
8406 | The FindFirst function will search for a file based on parameters passed in |
||
8407 | by the user. This function will use the FILEfind function to parse through |
||
8408 | the current working directory searching for entries that match the specified |
||
8409 | parameters. If a file is found, its parameters are copied into the SearchRec |
||
8410 | structure, as are the initial parameters passed in by the user and the position |
||
8411 | of the file entry in the current working directory. |
||
8412 | Remarks: |
||
8413 | Call FindFirst or FindFirstpgm before calling FindNext |
||
8414 | ***********************************************************************************/ |
||
8415 | |||
8416 | int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec) |
||
8417 | { |
||
8418 | FSFILE f; |
||
8419 | FILEOBJ fo = &f; |
||
8420 | CETYPE result; |
||
8421 | WORD fHandle; |
||
8422 | BYTE j; |
||
8423 | BYTE Index; |
||
8424 | |||
8425 | FSerrno = CE_GOOD; |
||
8426 | |||
8427 | if( !FormatFileName(fileName, fo->name, 1) ) |
||
8428 | { |
||
8429 | FSerrno = CE_INVALID_FILENAME; |
||
8430 | return -1; |
||
8431 | } |
||
8432 | |||
8433 | rec->initialized = FALSE; |
||
8434 | |||
8435 | for (Index = 0; (Index < 12) && (fileName[Index] != 0); Index++) |
||
8436 | { |
||
8437 | rec->searchname[Index] = fileName[Index]; |
||
8438 | } |
||
8439 | rec->searchname[Index] = 0; |
||
8440 | rec->searchattr = attr; |
||
8441 | #ifdef ALLOW_DIRS |
||
8442 | rec->cwdclus = cwdptr->dirclus; |
||
8443 | #else |
||
8444 | rec->cwdclus = FatRootDirClusterValue; |
||
8445 | #endif |
||
8446 | |||
8447 | fo->dsk = &gDiskData; |
||
8448 | fo->cluster = 0; |
||
8449 | fo->ccls = 0; |
||
8450 | fo->entry = 0; |
||
8451 | fo->attributes = attr; |
||
8452 | |||
8453 | #ifndef ALLOW_DIRS |
||
8454 | // start at the root directory |
||
8455 | fo->dirclus = FatRootDirClusterValue; |
||
8456 | fo->dirccls = FatRootDirClusterValue; |
||
8457 | #else |
||
8458 | fo->dirclus = cwdptr->dirclus; |
||
8459 | fo->dirccls = cwdptr->dirccls; |
||
8460 | #endif |
||
8461 | |||
8462 | // copy file object over |
||
8463 | FileObjectCopy(&gFileTemp, fo); |
||
8464 | |||
8465 | // See if the file is found |
||
8466 | result = FILEfind (fo, &gFileTemp,LOOK_FOR_MATCHING_ENTRY, 1); |
||
8467 | |||
8468 | if (result != CE_GOOD) |
||
8469 | { |
||
8470 | FSerrno = CE_FILE_NOT_FOUND; |
||
8471 | return -1; |
||
8472 | } |
||
8473 | else |
||
8474 | { |
||
8475 | fHandle = fo->entry; |
||
8476 | result = FILEopen (fo, &fHandle, 'r'); |
||
8477 | } |
||
8478 | if (result == CE_GOOD) |
||
8479 | { |
||
8480 | // Copy as much name as there is |
||
8481 | if (fo->attributes != ATTR_VOLUME) |
||
8482 | { |
||
8483 | for (Index = 0, j = 0; (j < 8) && (fo->name[j] != 0x20); Index++, j++) |
||
8484 | { |
||
8485 | rec->filename[Index] = fo->name[j]; |
||
8486 | } |
||
8487 | // Add the radix if its not a dir |
||
8488 | if ((fo->name[8] != ' ') || (fo->name[9] != ' ') || (fo->name[10] != ' ')) |
||
8489 | rec->filename[Index++] = '.'; |
||
8490 | // Move to the extension, even if there are more space chars |
||
8491 | for (j = 8; (j < 11) && (fo->name[j] != 0x20); Index++, j++) |
||
8492 | { |
||
8493 | rec->filename[Index] = fo->name[j]; |
||
8494 | } |
||
8495 | // Null terminate it |
||
8496 | rec->filename[Index] = 0; |
||
8497 | } |
||
8498 | else |
||
8499 | { |
||
8500 | for (Index = 0; Index < DIR_NAMECOMP; Index++) |
||
8501 | { |
||
8502 | rec->filename[Index] = fo->name[Index]; |
||
8503 | } |
||
8504 | rec->filename[Index] = 0; |
||
8505 | } |
||
8506 | |||
8507 | rec->attributes = fo->attributes; |
||
8508 | rec->filesize = fo->size; |
||
8509 | rec->timestamp = (DWORD)((DWORD)fo->date << 16) + fo->time; |
||
8510 | rec->entry = fo->entry; |
||
8511 | rec->initialized = TRUE; |
||
8512 | return 0; |
||
8513 | } |
||
8514 | else |
||
8515 | { |
||
8516 | FSerrno = CE_BADCACHEREAD; |
||
8517 | return -1; |
||
8518 | } |
||
8519 | } |
||
8520 | |||
8521 | |||
8522 | /********************************************************************** |
||
8523 | Function: |
||
8524 | int FindNext (SearchRec * rec) |
||
8525 | Summary: |
||
8526 | Sequential search function |
||
8527 | Conditions: |
||
8528 | None |
||
8529 | Input: |
||
8530 | rec - The structure to store the file information in |
||
8531 | Return Values: |
||
8532 | |||
8533 | -1 - No additional files matching the specified criteria were found |
||
8534 | Side Effects: |
||
8535 | The FSerrno variable will be changed. |
||
8536 | Description: |
||
8537 | The FindNext function performs the same function as the FindFirst |
||
8538 | funciton, except it does not copy any search parameters into the |
||
8539 | SearchRec structure (only info about found files) and it begins |
||
8540 | searching at the last directory entry offset at which a file was |
||
8541 | found, rather than at the beginning of the current working |
||
8542 | directory. |
||
8543 | Remarks: |
||
8544 | Call FindFirst or FindFirstpgm before calling this function |
||
8545 | **********************************************************************/ |
||
8546 | |||
8547 | int FindNext (SearchRec * rec) |
||
8548 | { |
||
8549 | FSFILE f; |
||
8550 | FILEOBJ fo = &f; |
||
8551 | CETYPE result; |
||
8552 | BYTE i, j; |
||
8553 | |||
8554 | FSerrno = CE_GOOD; |
||
8555 | |||
8556 | // Make sure we called FindFirst on this object |
||
8557 | if (rec->initialized == FALSE) |
||
8558 | { |
||
8559 | FSerrno = CE_NOT_INIT; |
||
8560 | return -1; |
||
8561 | } |
||
8562 | |||
8563 | // Make sure we called FindFirst in the cwd |
||
8564 | #ifdef ALLOW_DIRS |
||
8565 | if (rec->cwdclus != cwdptr->dirclus) |
||
8566 | { |
||
8567 | FSerrno = CE_INVALID_ARGUMENT; |
||
8568 | return -1; |
||
8569 | } |
||
8570 | #endif |
||
8571 | |||
8572 | if( !FormatFileName(rec->searchname, fo->name, 1) ) |
||
8573 | { |
||
8574 | FSerrno = CE_INVALID_FILENAME; |
||
8575 | return -1; |
||
8576 | } |
||
8577 | |||
8578 | /* Brn: Copy the formatted name to "fo" which is necesary before calling "FILEfind" function */ |
||
8579 | //strcpy(fo->name,rec->searchname); |
||
8580 | |||
8581 | fo->dsk = &gDiskData; |
||
8582 | fo->cluster = 0; |
||
8583 | fo->ccls = 0; |
||
8584 | fo->entry = rec->entry + 1; |
||
8585 | fo->attributes = rec->searchattr; |
||
8586 | |||
8587 | #ifndef ALLOW_DIRS |
||
8588 | // start at the root directory |
||
8589 | fo->dirclus = FatRootDirClusterValue; |
||
8590 | fo->dirccls = FatRootDirClusterValue; |
||
8591 | #else |
||
8592 | fo->dirclus = cwdptr->dirclus; |
||
8593 | fo->dirccls = cwdptr->dirccls; |
||
8594 | #endif |
||
8595 | |||
8596 | // copy file object over |
||
8597 | FileObjectCopy(&gFileTemp, fo); |
||
8598 | |||
8599 | // See if the file is found |
||
8600 | result = FILEfind (fo, &gFileTemp,LOOK_FOR_MATCHING_ENTRY, 1); |
||
8601 | |||
8602 | if (result != CE_GOOD) |
||
8603 | { |
||
8604 | FSerrno = CE_FILE_NOT_FOUND; |
||
8605 | return -1; |
||
8606 | } |
||
8607 | else |
||
8608 | { |
||
8609 | if (fo->attributes != ATTR_VOLUME) |
||
8610 | { |
||
8611 | for (i = 0, j = 0; (j < 8) && (fo->name[j] != 0x20); i++, j++) |
||
8612 | { |
||
8613 | rec->filename[i] = fo->name[j]; |
||
8614 | } |
||
8615 | // Add the radix if its not a dir |
||
8616 | if ((fo->name[8] != ' ') || (fo->name[9] != ' ') || (fo->name[10] != ' ')) |
||
8617 | rec->filename[i++] = '.'; |
||
8618 | // Move to the extension, even if there are more space chars |
||
8619 | for (j = 8; (j < 11) && (fo->name[j] != 0x20); i++, j++) |
||
8620 | { |
||
8621 | rec->filename[i] = fo->name[j]; |
||
8622 | } |
||
8623 | // Null terminate it |
||
8624 | rec->filename[i] = 0; |
||
8625 | } |
||
8626 | else |
||
8627 | { |
||
8628 | for (i = 0; i < DIR_NAMECOMP; i++) |
||
8629 | { |
||
8630 | rec->filename[i] = fo->name[i]; |
||
8631 | } |
||
8632 | rec->filename[i] = 0; |
||
8633 | } |
||
8634 | |||
8635 | rec->attributes = fo->attributes; |
||
8636 | rec->filesize = fo->size; |
||
8637 | rec->timestamp = (DWORD)((DWORD)fo->date << 16) + fo->time; |
||
8638 | rec->entry = fo->entry; |
||
8639 | return 0; |
||
8640 | } |
||
8641 | } |
||
8642 | |||
8643 | |||
8644 | #endif |
||
8645 | |||
8646 | |||
8647 | |||
8648 | #ifdef ALLOW_FSFPRINTF |
||
8649 | |||
8650 | |||
8651 | |||
8652 | /********************************************************************** |
||
8653 | Function: |
||
8654 | int FSputc (char c, FSFILE * file) |
||
8655 | Summary: |
||
8656 | FSfprintf helper function to write a char |
||
8657 | Conditions: |
||
8658 | This function should not be called by the user. |
||
8659 | Input: |
||
8660 | c - The character to write to the file. |
||
8661 | file - The file to write to. |
||
8662 | Return Values: |
||
8663 | |||
8664 | EOF - The character was not written to the file. |
||
8665 | Side Effects: |
||
8666 | None |
||
8667 | Description: |
||
8668 | This is a helper function for FSfprintf. It will write one |
||
8669 | character to a file. |
||
8670 | Remarks: |
||
8671 | None |
||
8672 | **********************************************************************/ |
||
8673 | |||
8674 | int FSputc (char c, FSFILE * file) |
||
8675 | { |
||
8676 | if (FSfwrite ((void *)&c, 1, 1, file) != 1) |
||
8677 | return EOF; |
||
8678 | else |
||
8679 | return 0; |
||
8680 | } |
||
8681 | |||
8682 | |||
8683 | /********************************************************************** |
||
8684 | Function: |
||
8685 | int str_put_n_chars (FSFILE * handle, unsigned char n, char c) |
||
8686 | Summary: |
||
8687 | FSfprintf helper function to write a char multiple times |
||
8688 | Conditions: |
||
8689 | This function should not be called by the user. |
||
8690 | Input: |
||
8691 | handle - The file to write to. |
||
8692 | n - The number of times to write that character to a file. |
||
8693 | c - The character to write to the file. |
||
8694 | Return Values: |
||
8695 | |||
8696 | EOF - The characters were not written to the file. |
||
8697 | Side Effects: |
||
8698 | None |
||
8699 | Description: |
||
8700 | This funciton is used by the FSfprintf function to write multiple |
||
8701 | instances of a single character to a file (for example, when |
||
8702 | padding a format specifier with leading spacez or zeros). |
||
8703 | Remarks: |
||
8704 | None. |
||
8705 | **********************************************************************/ |
||
8706 | |||
8707 | |||
8708 | unsigned char str_put_n_chars (FSFILE * handle, unsigned char n, char c) |
||
8709 | { |
||
8710 | while (n--) |
||
8711 | if (FSputc (c, handle) == EOF) |
||
8712 | return 1; |
||
8713 | return 0; |
||
8714 | } |
||
8715 | |||
8716 | |||
8717 | /********************************************************************** |
||
8718 | Function: |
||
8719 | // PIC24/30/33/32 |
||
8720 | int FSfprintf (FSFILE * fptr, const char * fmt, ...) |
||
8721 | // PIC18 |
||
8722 | int FSfpritnf (FSFILE * fptr, const rom char * fmt, ...) |
||
8723 | Summary: |
||
8724 | Function to write formatted strings to a file |
||
8725 | Conditions: |
||
8726 | For PIC18, integer promotion must be enabled in the project build |
||
8727 | options menu. File opened in a write mode. |
||
8728 | Input: |
||
8729 | fptr - A pointer to the file to write to. |
||
8730 | fmt - A string of characters and format specifiers to write to |
||
8731 | the file |
||
8732 | ... - Additional arguments inserted in the string by format |
||
8733 | specifiers |
||
8734 | Returns: |
||
8735 | The number of characters written to the file |
||
8736 | Side Effects: |
||
8737 | The FSerrno variable will be changed. |
||
8738 | Description: |
||
8739 | Writes a specially formatted string to a file. |
||
8740 | Remarks: |
||
8741 | Consult AN1045 for a full description of how to use format |
||
8742 | specifiers. |
||
8743 | **********************************************************************/ |
||
8744 | |||
8745 | #ifdef __18CXX |
||
8746 | int FSfprintf (FSFILE *fptr, const rom char *fmt, ...) |
||
8747 | #else |
||
8748 | int FSfprintf (FSFILE *fptr, const char * fmt, ...) |
||
8749 | #endif |
||
8750 | { |
||
8751 | va_list ap; |
||
8752 | int n; |
||
8753 | |||
8754 | va_start (ap, fmt); |
||
8755 | n = FSvfprintf (fptr, fmt, ap); |
||
8756 | va_end (ap); |
||
8757 | return n; |
||
8758 | } |
||
8759 | |||
8760 | |||
8761 | /********************************************************************** |
||
8762 | Function: |
||
8763 | // PIC24/30/33/32 |
||
8764 | int FSvfprintf (FSFILE * handle, const char * formatString, va_list ap) |
||
8765 | // PIC18 |
||
8766 | int FSvfpritnf (auto FSFILE * handle, auto const rom char * formatString, auto va_list ap) |
||
8767 | Summary: |
||
8768 | Helper function for FSfprintf |
||
8769 | Conditions: |
||
8770 | This function should not be called by the user. |
||
8771 | Input: |
||
8772 | handle - A pointer to the file to write to. |
||
8773 | formatString - A string of characters and format specifiers to write to |
||
8774 | the file |
||
8775 | ap - A structure pointing to the arguments on the stack |
||
8776 | Returns: |
||
8777 | The number of characters written to the file |
||
8778 | Side Effects: |
||
8779 | The FSerrno variable will be changed. |
||
8780 | Description: |
||
8781 | This helper function will access the elements passed to FSfprintf |
||
8782 | Remarks: |
||
8783 | Consult AN1045 for a full description of how to use format |
||
8784 | specifiers. |
||
8785 | **********************************************************************/ |
||
8786 | |||
8787 | #ifdef __18CXX |
||
8788 | int FSvfprintf (auto FSFILE *handle, auto const rom char * formatString, auto va_list ap) |
||
8789 | #else |
||
8790 | int FSvfprintf (FSFILE *handle, const char * formatString, va_list ap) |
||
8791 | #endif |
||
8792 | { |
||
8793 | unsigned char c; |
||
8794 | int count = 0; |
||
8795 | |||
8796 | for (c = *formatString; c; c = *++formatString) |
||
8797 | { |
||
8798 | if (c == '%') |
||
8799 | { |
||
8800 | unsigned char flags = 0; |
||
8801 | unsigned char width = 0; |
||
8802 | unsigned char precision = 0; |
||
8803 | unsigned char have_precision = 0; |
||
8804 | unsigned char size = 0; |
||
8805 | #ifndef __18CXX |
||
8806 | unsigned char size2 = 0; |
||
8807 | #endif |
||
8808 | unsigned char space_cnt; |
||
8809 | unsigned char cval; |
||
8810 | #ifdef __18CXX |
||
8811 | unsigned long larg; |
||
8812 | far rom char * romstring; |
||
8813 | #else |
||
8814 | unsigned long long larg; |
||
8815 | #endif |
||
8816 | char * ramstring; |
||
8817 | int n; |
||
8818 | |||
8819 | FSerrno = CE_GOOD; |
||
8820 | |||
8821 | c = *++formatString; |
||
8822 | |||
8823 | while (c == '-' || c == '+' || c == ' ' || c == '#' |
||
8824 | || c == '0') |
||
8825 | { |
||
8826 | switch (c) |
||
8827 | { |
||
8828 | case '-': |
||
8829 | flags |= _FLAG_MINUS; |
||
8830 | break; |
||
8831 | case '+': |
||
8832 | flags |= _FLAG_PLUS; |
||
8833 | break; |
||
8834 | case ' ': |
||
8835 | flags |= _FLAG_SPACE; |
||
8836 | break; |
||
8837 | case '#': |
||
8838 | flags |= _FLAG_OCTO; |
||
8839 | break; |
||
8840 | case '0': |
||
8841 | flags |= _FLAG_ZERO; |
||
8842 | break; |
||
8843 | } |
||
8844 | c = *++formatString; |
||
8845 | } |
||
8846 | /* the optional width field is next */ |
||
8847 | if (c == '*') |
||
8848 | { |
||
8849 | n = va_arg (ap, int); |
||
8850 | if (n < 0) |
||
8851 | { |
||
8852 | flags |= _FLAG_MINUS; |
||
8853 | width = -n; |
||
8854 | } |
||
8855 | else |
||
8856 | width = n; |
||
8857 | c = *++formatString; |
||
8858 | } |
||
8859 | else |
||
8860 | { |
||
8861 | cval = 0; |
||
8862 | while ((unsigned char) isdigit (c)) |
||
8863 | { |
||
8864 | cval = cval * 10 + c - '0'; |
||
8865 | c = *++formatString; |
||
8866 | } |
||
8867 | width = cval; |
||
8868 | } |
||
8869 | |||
8870 | /* if '-' is specified, '0' is ignored */ |
||
8871 | if (flags & _FLAG_MINUS) |
||
8872 | flags &= ~_FLAG_ZERO; |
||
8873 | |||
8874 | /* the optional precision field is next */ |
||
8875 | if (c == '.') |
||
8876 | { |
||
8877 | c = *++formatString; |
||
8878 | if (c == '*') |
||
8879 | { |
||
8880 | n = va_arg (ap, int); |
||
8881 | if (n >= 0) |
||
8882 | { |
||
8883 | precision = n; |
||
8884 | have_precision = 1; |
||
8885 | } |
||
8886 | c = *++formatString; |
||
8887 | } |
||
8888 | else |
||
8889 | { |
||
8890 | cval = 0; |
||
8891 | while ((unsigned char) isdigit (c)) |
||
8892 | { |
||
8893 | cval = cval * 10 + c - '0'; |
||
8894 | c = *++formatString; |
||
8895 | } |
||
8896 | precision = cval; |
||
8897 | have_precision = 1; |
||
8898 | } |
||
8899 | } |
||
8900 | |||
8901 | /* the optional 'h' specifier. since int and short int are |
||
8902 | the same size for MPLAB C18, this is a NOP for us. */ |
||
8903 | if (c == 'h') |
||
8904 | { |
||
8905 | c = *++formatString; |
||
8906 | /* if 'c' is another 'h' character, this is an 'hh' |
||
8907 | specifier and the size is 8 bits */ |
||
8908 | if (c == 'h') |
||
8909 | { |
||
8910 | size = _FMT_BYTE; |
||
8911 | c = *++formatString; |
||
8912 | } |
||
8913 | } |
||
8914 | else if (c == 't' || c == 'z') |
||
8915 | c = *++formatString; |
||
8916 | #ifdef __18CXX |
||
8917 | else if (c == 'H' || c == 'T' || c == 'Z') |
||
8918 | { |
||
8919 | size = _FMT_SHRTLONG; |
||
8920 | c = *++formatString; |
||
8921 | } |
||
8922 | else if (c == 'l' || c == 'j') |
||
8923 | #else |
||
8924 | else if (c == 'q' || c == 'j') |
||
8925 | { |
||
8926 | size = _FMT_LONGLONG; |
||
8927 | c = *++formatString; |
||
8928 | } |
||
8929 | else if (c == 'l') |
||
8930 | #endif |
||
8931 | { |
||
8932 | size = _FMT_LONG; |
||
8933 | c = *++formatString; |
||
8934 | } |
||
8935 | |||
8936 | switch (c) |
||
8937 | { |
||
8938 | case '\0': |
||
8939 | /* this is undefined behaviour. we have a trailing '%' character |
||
8940 | in the string, perhaps with some flags, width, precision |
||
8941 | stuff as well, but no format specifier. We'll, arbitrarily, |
||
8942 | back up a character so that the loop will terminate |
||
8943 | properly when it loops back and we'll output a '%' |
||
8944 | character. */ |
||
8945 | --formatString; |
||
8946 | /* fallthrough */ |
||
8947 | case '%': |
||
8948 | if (FSputc ('%', handle) == EOF) |
||
8949 | { |
||
8950 | FSerrno = CE_WRITE_ERROR; |
||
8951 | return EOF; |
||
8952 | } |
||
8953 | ++count; |
||
8954 | break; |
||
8955 | case 'c': |
||
8956 | space_cnt = 0; |
||
8957 | if (width > 1) |
||
8958 | { |
||
8959 | space_cnt = width - 1; |
||
8960 | count += space_cnt; |
||
8961 | } |
||
8962 | if (space_cnt && !(flags & _FLAG_MINUS)) |
||
8963 | { |
||
8964 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
8965 | { |
||
8966 | FSerrno = CE_WRITE_ERROR; |
||
8967 | return EOF; |
||
8968 | } |
||
8969 | space_cnt = 0; |
||
8970 | } |
||
8971 | c = va_arg (ap, int); |
||
8972 | if (FSputc (c, handle) == EOF) |
||
8973 | { |
||
8974 | FSerrno = CE_WRITE_ERROR; |
||
8975 | return EOF; |
||
8976 | } |
||
8977 | ++count; |
||
8978 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
8979 | { |
||
8980 | FSerrno = CE_WRITE_ERROR; |
||
8981 | return EOF; |
||
8982 | } |
||
8983 | break; |
||
8984 | case 'S': |
||
8985 | #ifdef __18CXX |
||
8986 | if (size == _FMT_SHRTLONG) |
||
8987 | romstring = va_arg (ap, rom far char *); |
||
8988 | else |
||
8989 | romstring = (far rom char*)va_arg (ap, rom near char *); |
||
8990 | n = strlenpgm (romstring); |
||
8991 | /* Normalize the width based on the length of the actual |
||
8992 | string and the precision. */ |
||
8993 | if (have_precision && precision < (unsigned char) n) |
||
8994 | n = precision; |
||
8995 | if (width < (unsigned char) n) |
||
8996 | width = n; |
||
8997 | space_cnt = width - (unsigned char) n; |
||
8998 | count += space_cnt; |
||
8999 | /* we've already calculated the space count that the width |
||
9000 | will require. now we want the width field to have the |
||
9001 | number of character to display from the string itself, |
||
9002 | limited by the length of the actual string and the |
||
9003 | specified precision. */ |
||
9004 | if (have_precision && precision < width) |
||
9005 | width = precision; |
||
9006 | /* if right justified, we print the spaces before the |
||
9007 | string */ |
||
9008 | if (!(flags & _FLAG_MINUS)) |
||
9009 | { |
||
9010 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9011 | { |
||
9012 | FSerrno = CE_WRITE_ERROR; |
||
9013 | return EOF; |
||
9014 | } |
||
9015 | space_cnt = 0; |
||
9016 | } |
||
9017 | cval = 0; |
||
9018 | for (c = *romstring; c && cval < width; c = *++romstring) |
||
9019 | { |
||
9020 | if (FSputc (c, handle) == EOF) |
||
9021 | { |
||
9022 | FSerrno = CE_WRITE_ERROR; |
||
9023 | return EOF; |
||
9024 | } |
||
9025 | ++count; |
||
9026 | ++cval; |
||
9027 | } |
||
9028 | /* If there are spaces left, it's left justified. |
||
9029 | Either way, calling the function unconditionally |
||
9030 | is smaller code. */ |
||
9031 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9032 | { |
||
9033 | FSerrno = CE_WRITE_ERROR; |
||
9034 | return EOF; |
||
9035 | } |
||
9036 | break; |
||
9037 | #endif |
||
9038 | case 's': |
||
9039 | ramstring = va_arg (ap, char *); |
||
9040 | n = strlen (ramstring); |
||
9041 | /* Normalize the width based on the length of the actual |
||
9042 | string and the precision. */ |
||
9043 | if (have_precision && precision < (unsigned char) n) |
||
9044 | n = precision; |
||
9045 | if (width < (unsigned char) n) |
||
9046 | width = n; |
||
9047 | space_cnt = width - (unsigned char) n; |
||
9048 | count += space_cnt; |
||
9049 | /* we've already calculated the space count that the width |
||
9050 | will require. now we want the width field to have the |
||
9051 | number of character to display from the string itself, |
||
9052 | limited by the length of the actual string and the |
||
9053 | specified precision. */ |
||
9054 | if (have_precision && precision < width) |
||
9055 | width = precision; |
||
9056 | /* if right justified, we print the spaces before the string */ |
||
9057 | if (!(flags & _FLAG_MINUS)) |
||
9058 | { |
||
9059 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9060 | { |
||
9061 | FSerrno = CE_WRITE_ERROR; |
||
9062 | return EOF; |
||
9063 | } |
||
9064 | space_cnt = 0; |
||
9065 | } |
||
9066 | cval = 0; |
||
9067 | for (c = *ramstring; c && cval < width; c = *++ramstring) |
||
9068 | { |
||
9069 | if (FSputc (c, handle) == EOF) |
||
9070 | { |
||
9071 | FSerrno = CE_WRITE_ERROR; |
||
9072 | return EOF; |
||
9073 | } |
||
9074 | ++count; |
||
9075 | ++cval; |
||
9076 | } |
||
9077 | /* If there are spaces left, it's left justified. |
||
9078 | Either way, calling the function unconditionally |
||
9079 | is smaller code. */ |
||
9080 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9081 | { |
||
9082 | FSerrno = CE_WRITE_ERROR; |
||
9083 | return EOF; |
||
9084 | } |
||
9085 | break; |
||
9086 | case 'd': |
||
9087 | case 'i': |
||
9088 | flags |= _FLAG_SIGNED; |
||
9089 | /* fall through */ |
||
9090 | case 'o': |
||
9091 | case 'u': |
||
9092 | case 'x': |
||
9093 | case 'X': |
||
9094 | case 'b': |
||
9095 | case 'B': |
||
9096 | /* This is a bit of a trick. The 'l' and 'hh' size |
||
9097 | specifiers are valid only for the integer conversions, |
||
9098 | not the 'p' or 'P' conversions, and are ignored for the |
||
9099 | latter. By jumping over the additional size specifier |
||
9100 | checks here we get the best code size since we can |
||
9101 | limit the size checks in the remaining code. */ |
||
9102 | if (size == _FMT_LONG) |
||
9103 | { |
||
9104 | if (flags & _FLAG_SIGNED) |
||
9105 | larg = va_arg (ap, long int); |
||
9106 | else |
||
9107 | larg = va_arg (ap, unsigned long int); |
||
9108 | goto _do_integer_conversion; |
||
9109 | } |
||
9110 | else if (size == _FMT_BYTE) |
||
9111 | { |
||
9112 | if (flags & _FLAG_SIGNED) |
||
9113 | larg = (signed char) va_arg (ap, int); |
||
9114 | else |
||
9115 | larg = (unsigned char) va_arg (ap, unsigned int); |
||
9116 | goto _do_integer_conversion; |
||
9117 | } |
||
9118 | #ifndef __18CXX |
||
9119 | else if (size == _FMT_LONGLONG) |
||
9120 | { |
||
9121 | if (flags & _FLAG_SIGNED) |
||
9122 | larg = (signed long long)va_arg (ap, long long); |
||
9123 | else |
||
9124 | larg = (unsigned long long) va_arg (ap, unsigned long long); |
||
9125 | goto _do_integer_conversion; |
||
9126 | } |
||
9127 | #endif |
||
9128 | /* fall trough */ |
||
9129 | case 'p': |
||
9130 | case 'P': |
||
9131 | #ifdef __18CXX |
||
9132 | if (size == _FMT_SHRTLONG) |
||
9133 | { |
||
9134 | if (flags & _FLAG_SIGNED) |
||
9135 | larg = va_arg (ap, short long int); |
||
9136 | else |
||
9137 | larg = va_arg (ap, unsigned short long int); |
||
9138 | } |
||
9139 | else |
||
9140 | #endif |
||
9141 | if (flags & _FLAG_SIGNED) |
||
9142 | larg = va_arg (ap, int); |
||
9143 | else |
||
9144 | larg = va_arg (ap, unsigned int); |
||
9145 | _do_integer_conversion: |
||
9146 | /* default precision is 1 */ |
||
9147 | if (!have_precision) |
||
9148 | precision = 1; |
||
9149 | { |
||
9150 | unsigned char digit_cnt = 0; |
||
9151 | unsigned char prefix_cnt = 0; |
||
9152 | unsigned char sign_char; |
||
9153 | /* A 32 bit number will require at most 32 digits in the |
||
9154 | string representation (binary format). */ |
||
9155 | #ifdef __18CXX |
||
9156 | char buf[33]; |
||
9157 | /* Start storing digits least-significant first */ |
||
9158 | char *q = &buf[31]; |
||
9159 | /* null terminate the string */ |
||
9160 | buf[32] = '\0'; |
||
9161 | #else |
||
9162 | char buf[65]; |
||
9163 | char *q = &buf[63]; |
||
9164 | buf[64] = '\0'; |
||
9165 | #endif |
||
9166 | space_cnt = 0; |
||
9167 | size = 10; |
||
9168 | |||
9169 | switch (c) |
||
9170 | { |
||
9171 | case 'b': |
||
9172 | case 'B': |
||
9173 | size = 2; |
||
9174 | #ifndef __18CXX |
||
9175 | size2 = 1; |
||
9176 | #endif |
||
9177 | break; |
||
9178 | case 'o': |
||
9179 | size = 8; |
||
9180 | #ifndef __18CXX |
||
9181 | size2 = 3; |
||
9182 | #endif |
||
9183 | break; |
||
9184 | case 'p': |
||
9185 | case 'P': |
||
9186 | /* from here on out, treat 'p' conversions just |
||
9187 | like 'x' conversions. */ |
||
9188 | c += 'x' - 'p'; |
||
9189 | /* fall through */ |
||
9190 | case 'x': |
||
9191 | case 'X': |
||
9192 | size = 16; |
||
9193 | #ifndef __18CXX |
||
9194 | size2 = 4; |
||
9195 | #endif |
||
9196 | break; |
||
9197 | }// switch (c) |
||
9198 | |||
9199 | /* if it's an unsigned conversion, we should ignore the |
||
9200 | ' ' and '+' flags */ |
||
9201 | if (!(flags & _FLAG_SIGNED)) |
||
9202 | flags &= ~(_FLAG_PLUS | _FLAG_SPACE); |
||
9203 | |||
9204 | /* if it's a negative value, we need to negate the |
||
9205 | unsigned version before we convert to text. Using |
||
9206 | unsigned for this allows us to (ab)use the 2's |
||
9207 | complement system to avoid overflow and be able to |
||
9208 | adequately handle LONG_MIN. |
||
9209 | |||
9210 | We'll figure out what sign character to print, if |
||
9211 | any, here as well. */ |
||
9212 | #ifdef __18CXX |
||
9213 | if (flags & _FLAG_SIGNED && ((long) larg < 0)) |
||
9214 | { |
||
9215 | larg = -(long) larg; |
||
9216 | #else |
||
9217 | if (flags & _FLAG_SIGNED && ((long long) larg < 0)) |
||
9218 | { |
||
9219 | larg = -(long long) larg; |
||
9220 | #endif |
||
9221 | sign_char = '-'; |
||
9222 | ++digit_cnt; |
||
9223 | } |
||
9224 | else if (flags & _FLAG_PLUS) |
||
9225 | { |
||
9226 | sign_char = '+'; |
||
9227 | ++digit_cnt; |
||
9228 | } |
||
9229 | else if (flags & _FLAG_SPACE) |
||
9230 | { |
||
9231 | sign_char = ' '; |
||
9232 | ++digit_cnt; |
||
9233 | } |
||
9234 | else |
||
9235 | sign_char = '\0'; |
||
9236 | /* get the digits for the actual number. If the |
||
9237 | precision is zero and the value is zero, the result |
||
9238 | is no characters. */ |
||
9239 | if (precision || larg) |
||
9240 | { |
||
9241 | do |
||
9242 | { |
||
9243 | #ifdef __18CXX |
||
9244 | cval = s_digits[larg % size]; |
||
9245 | if (c == 'X' && cval >= 'a') |
||
9246 | cval -= 'a' - 'A'; |
||
9247 | larg /= size; |
||
9248 | #else |
||
9249 | // larg is congruent mod size2 to its lower 16 bits |
||
9250 | // for size2 = 2^n, 0 <= n <= 4 |
||
9251 | if (size2 != 0) |
||
9252 | cval = s_digits[(unsigned int) larg % size]; |
||
9253 | else |
||
9254 | cval = s_digits[larg % size]; |
||
9255 | if (c == 'X' && cval >= 'a') |
||
9256 | cval -= 'a' - 'A'; |
||
9257 | if (size2 != 0) |
||
9258 | larg = larg >> size2; |
||
9259 | else |
||
9260 | larg /= size; |
||
9261 | #endif |
||
9262 | *q-- = cval; |
||
9263 | ++digit_cnt; |
||
9264 | } while (larg); |
||
9265 | /* if the '#' flag was specified and we're dealing |
||
9266 | with an 'o', 'b', 'B', 'x', or 'X' conversion, |
||
9267 | we need a bit more. */ |
||
9268 | if (flags & _FLAG_OCTO) |
||
9269 | { |
||
9270 | if (c == 'o') |
||
9271 | { |
||
9272 | /* per the standard, for octal, the '#' flag |
||
9273 | makes the precision be at least one more |
||
9274 | than the number of digits in the number */ |
||
9275 | if (precision <= digit_cnt) |
||
9276 | precision = digit_cnt + 1; |
||
9277 | } |
||
9278 | else if (c == 'x' || c == 'X' || c == 'b' || c == 'B') |
||
9279 | prefix_cnt = 2; |
||
9280 | } |
||
9281 | } |
||
9282 | else |
||
9283 | digit_cnt = 0; |
||
9284 | |||
9285 | /* The leading zero count depends on whether the '0' |
||
9286 | flag was specified or not. If it was not, then the |
||
9287 | count is the difference between the specified |
||
9288 | precision and the number of digits (including the |
||
9289 | sign character, if any) to be printed; otherwise, |
||
9290 | it's as if the precision were equal to the max of |
||
9291 | the specified precision and the field width. If a |
||
9292 | precision was specified, the '0' flag is ignored, |
||
9293 | however. */ |
||
9294 | if ((flags & _FLAG_ZERO) && (width > precision) |
||
9295 | && !have_precision) |
||
9296 | precision = width; |
||
9297 | /* for the rest of the processing, precision contains |
||
9298 | the leading zero count for the conversion. */ |
||
9299 | if (precision > digit_cnt) |
||
9300 | precision -= digit_cnt; |
||
9301 | else |
||
9302 | precision = 0; |
||
9303 | /* the space count is the difference between the field |
||
9304 | width and the digit count plus the leading zero |
||
9305 | count. If the width is less than the digit count |
||
9306 | plus the leading zero count, the space count is |
||
9307 | zero. */ |
||
9308 | if (width > precision + digit_cnt + prefix_cnt) |
||
9309 | space_cnt = width - precision - digit_cnt - prefix_cnt; |
||
9310 | |||
9311 | /* for output, we check the justification, if it's |
||
9312 | right justified and the space count is positive, we |
||
9313 | emit the space characters first. */ |
||
9314 | if (!(flags & _FLAG_MINUS) && space_cnt) |
||
9315 | { |
||
9316 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9317 | { |
||
9318 | FSerrno = CE_WRITE_ERROR; |
||
9319 | return EOF; |
||
9320 | } |
||
9321 | count += space_cnt; |
||
9322 | space_cnt = 0; |
||
9323 | } |
||
9324 | /* if we have a sign character to print, that comes |
||
9325 | next */ |
||
9326 | if (sign_char) |
||
9327 | if (FSputc (sign_char, handle) == EOF) |
||
9328 | { |
||
9329 | FSerrno = CE_WRITE_ERROR; |
||
9330 | return EOF; |
||
9331 | } |
||
9332 | /* if we have a prefix (0b, 0B, 0x or 0X), that's next */ |
||
9333 | if (prefix_cnt) |
||
9334 | { |
||
9335 | if (FSputc ('0', handle) == EOF) |
||
9336 | { |
||
9337 | FSerrno = CE_WRITE_ERROR; |
||
9338 | return EOF; |
||
9339 | } |
||
9340 | if (FSputc (c, handle) == EOF) |
||
9341 | { |
||
9342 | FSerrno = CE_WRITE_ERROR; |
||
9343 | return EOF; |
||
9344 | } |
||
9345 | } |
||
9346 | /* if we have leading zeros, they follow. the prefix, if any |
||
9347 | is included in the number of digits when determining how |
||
9348 | many leading zeroes are needed. */ |
||
9349 | // if (precision > prefix_cnt) |
||
9350 | // precision -= prefix_cnt; |
||
9351 | if (str_put_n_chars (handle, precision, '0')) |
||
9352 | { |
||
9353 | FSerrno = CE_WRITE_ERROR; |
||
9354 | return EOF; |
||
9355 | } |
||
9356 | /* print the actual number */ |
||
9357 | for (cval = *++q; cval; cval = *++q) |
||
9358 | if (FSputc (cval, handle) == EOF) |
||
9359 | { |
||
9360 | FSerrno = CE_WRITE_ERROR; |
||
9361 | return EOF; |
||
9362 | } |
||
9363 | /* if there are any spaces left, they go to right-pad |
||
9364 | the field */ |
||
9365 | if (str_put_n_chars (handle, space_cnt, ' ')) |
||
9366 | { |
||
9367 | FSerrno = CE_WRITE_ERROR; |
||
9368 | return EOF; |
||
9369 | } |
||
9370 | |||
9371 | count += precision + digit_cnt + space_cnt + prefix_cnt; |
||
9372 | } |
||
9373 | break; |
||
9374 | case 'n': |
||
9375 | switch (size) |
||
9376 | { |
||
9377 | case _FMT_LONG: |
||
9378 | *(long *) va_arg (ap, long *) = count; |
||
9379 | break; |
||
9380 | #ifdef __18CXX |
||
9381 | case _FMT_SHRTLONG: |
||
9382 | *(short long *) va_arg (ap, short long *) = count; |
||
9383 | break; |
||
9384 | #else |
||
9385 | case _FMT_LONGLONG: |
||
9386 | *(long long *) va_arg (ap, long long *) = count; |
||
9387 | break; |
||
9388 | #endif |
||
9389 | case _FMT_BYTE: |
||
9390 | *(signed char *) va_arg (ap, signed char *) = count; |
||
9391 | break; |
||
9392 | default: |
||
9393 | *(int *) va_arg (ap, int *) = count; |
||
9394 | break; |
||
9395 | } |
||
9396 | break; |
||
9397 | default: |
||
9398 | /* undefined behaviour. we do nothing */ |
||
9399 | break; |
||
9400 | } |
||
9401 | } |
||
9402 | else |
||
9403 | { |
||
9404 | if (FSputc (c, handle) == EOF) |
||
9405 | { |
||
9406 | FSerrno = CE_WRITE_ERROR; |
||
9407 | return EOF; |
||
9408 | } |
||
9409 | ++count; |
||
9410 | } |
||
9411 | } |
||
9412 | return count; |
||
9413 | } |
||
9414 | |||
9415 | |||
9416 | |||
9417 | #endif |
||
9418 | |||
9419 | |||
9420 | |||
9421 |
Powered by WebSVN v2.8.3