1 /******************************************************************************
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 Company’s 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 Fixed bug that prevented FAT being updated when media is re-inserted
47
48 1.2.6 Fixed bug that resulted in a bus error when attempts to read a invalid memory region
49 Fixed bug that prevented the Windows Explorer to show the Date Creation field for directories
50
51 x.x.x Fixed issue on some USB drives where the information written
52 to the drive is cached in a RAM for 500ms before it is
53 written to the flash unless the sector is accessed again.
54 Add some error recovery for FAT32 systems when there is
55 corruption in the boot sector.
56
57 1.3.0 Modified to support Long File Name(LFN) format
58 1.3.4 1) Initialized some of the local variables to default values
59 to remove non-critical compiler warnings for code sanitation.
60 2) The sector size of the media device is obtained from the MBR of media.So,
61 instead of using the hard coded macro "DIRENTRIES_PER_SECTOR", the variables
62 "dirEntriesPerSector" & "disk->sectorSize" are used in the code. Refer
63 "Cache_File_Entry","EraseCluster" & "writeDotEntries" fucntions to see
64 the change.
65 ********************************************************************/
66
67 #include "Compiler.h"
68 #include "MDD File System/FSIO.h"
69 #include "GenericTypeDefs.h"
70 #include "string.h"
71 #include "stdlib.h"
72 #include "ctype.h"
73 #include "MDD File System/FSDefs.h"
74
75 #ifdef ALLOW_FSFPRINTF
76 #include "stdarg.h"
77 #endif
78
79 #ifdef FS_DYNAMIC_MEM
80 #ifdef __18CXX
81 #include "salloc.h"
82 #endif
83 #endif
84
85 #ifndef ALLOW_WRITES
86 #ifdef ALLOW_FORMATS
87 #error Write functions must be enabled to use the format function
88 #endif
89 #ifdef ALLOW_FSFPRINTF
90 #error Write functions must be enabled to use the FSfprintf function
91 #endif
92 #endif
93
94 #ifdef USEREALTIMECLOCK
95 #ifdef USERDEFINEDCLOCK
96 #error Please select only one timestamp clocking mode in FSconfig.h
97 #endif
98 #ifdef INCREMENTTIMESTAMP
99 #error Please select only one timestamp clocking mode in FSconfig.h
100 #endif
101 #elif defined USERDEFINEDCLOCK
102 #ifdef INCREMENTTIMESTAMP
103 #error Please select only one timestamp clocking mode in FSconfig.h
104 #endif
105 #endif
106 /*****************************************************************************/
107 /* Global Variables */
108 /*****************************************************************************/
109
110 #ifndef FS_DYNAMIC_MEM
111 FSFILE gFileArray[FS_MAX_FILES_OPEN]; // Array that contains file information (static allocation)
112 BYTE gFileSlotOpen[FS_MAX_FILES_OPEN]; // Array that indicates which elements of gFileArray are available for use
113 #ifdef SUPPORT_LFN
114 // Array that stores long file name (static allocation)
115 unsigned short int lfnData[FS_MAX_FILES_OPEN][257];
116 #endif
117 #endif
118
119 #ifdef SUPPORT_LFN
120 #ifdef ALLOW_FILESEARCH
121 // Array that stores long file name for File Search operation (static allocation)
122 unsigned short int recordSearchName[257];
123 unsigned short int recordFoundName[257];
124 unsigned short int recordSearchLength;
125 #endif
126 unsigned short int fileFoundString[261];
127 #endif
128
129 #if defined(USEREALTIMECLOCK) || defined(USERDEFINEDCLOCK)
130 // Timing variables
131 BYTE gTimeCrtMS; // Global time variable (for timestamps) used to indicate create time (milliseconds)
132 WORD gTimeCrtTime; // Global time variable (for timestamps) used to indicate create time
133 WORD gTimeCrtDate; // Global time variable (for timestamps) used to indicate create date
134 WORD gTimeAccDate; // Global time variable (for timestamps) used to indicate last access date
135 WORD gTimeWrtTime; // Global time variable (for timestamps) used to indicate last update time
136 WORD gTimeWrtDate; // Global time variable (for timestamps) used to indicate last update date
137 #endif
138
139 DWORD gLastFATSectorRead = 0xFFFFFFFF; // Global variable indicating which FAT sector was read last
140 BYTE gNeedFATWrite = FALSE; // Global variable indicating that there is information that needs to be written to the FAT
141 FSFILE * gBufferOwner = NULL; // Global variable indicating which file is using the data buffer
142 DWORD gLastDataSectorRead = 0xFFFFFFFF; // Global variable indicating which data sector was read last
143 BYTE gNeedDataWrite = FALSE; // Global variable indicating that there is information that needs to be written to the data section
144 BYTE nextClusterIsLast = FALSE; // Global variable indicating that the entries in a directory align with a cluster boundary
145
146 BYTE gBufferZeroed = FALSE; // Global variable indicating that the data buffer contains all zeros
147
148 DWORD FatRootDirClusterValue; // Global variable containing the cluster number of the root dir (0 for FAT12/16)
149
150 BYTE FSerrno; // Global error variable. Set to one of many error codes after each function call.
151
152 DWORD TempClusterCalc; // Global variable used to store the calculated value of the cluster of a specified sector.
153 BYTE dirCleared; // Global variable used by the "recursive" FSrmdir function to indicate that all subdirectories and files have been deleted from the target directory.
154 BYTE recache = FALSE; // Global variable used by the "recursive" FSrmdir function to indicate that additional cache reads are needed.
155 FSFILE tempCWDobj; // Global variable used to preserve the current working directory information.
156 FSFILE gFileTemp; // Global variable used for file operations.
157
158 FSFILE cwd; // Global current working directory
159 FSFILE * cwdptr = &cwd; // Pointer to the current working directory
160
161
162 #ifdef __18CXX
163 #pragma udata dataBuffer = DATA_BUFFER_ADDRESS
164 BYTE gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer
165 #pragma udata FATBuffer = FAT_BUFFER_ADDRESS
166 BYTE gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer
167 #endif
168
169 #if defined (__C30__) || defined (__PIC32MX__)
170 BYTE __attribute__ ((aligned(4))) gDataBuffer[MEDIA_SECTOR_SIZE]; // The global data sector buffer
171 BYTE __attribute__ ((aligned(4))) gFATBuffer[MEDIA_SECTOR_SIZE]; // The global FAT sector buffer
172 #endif
173
174
175 #pragma udata
176
177 DISK gDiskData; // Global structure containing device information.
178
179 /* Global Variables to handle ASCII & UTF16 file operations */
180 char *asciiFilename;
181 unsigned short int fileNameLength;
182 #ifdef SUPPORT_LFN
183 unsigned short int *utf16Filename;
184 BOOL utfModeFileName = FALSE;
185 BOOL twoByteMode = FALSE;
186 #endif
187 /************************************************************************/
188 /* Structures and defines */
189 /************************************************************************/
190
191 // Directory entry structure
192 typedef struct
193 {
194 char DIR_Name[DIR_NAMESIZE]; // File name
195 char DIR_Extension[DIR_EXTENSION]; // File extension
196 BYTE DIR_Attr; // File attributes
197 BYTE DIR_NTRes; // Reserved byte
198 BYTE DIR_CrtTimeTenth; // Create time (millisecond field)
199 WORD DIR_CrtTime; // Create time (second, minute, hour field)
200 WORD DIR_CrtDate; // Create date
201 WORD DIR_LstAccDate; // Last access date
202 WORD DIR_FstClusHI; // High word of the entry's first cluster number
203 WORD DIR_WrtTime; // Last update time
204 WORD DIR_WrtDate; // Last update date
205 WORD DIR_FstClusLO; // Low word of the entry's first cluster number
206 DWORD DIR_FileSize; // The 32-bit file size
207 }_DIRENTRY;
208
209 typedef _DIRENTRY * DIRENTRY; // A pointer to a directory entry structure
210
211 #define DIRECTORY 0x12 // Value indicating that the CreateFileEntry function will be creating a directory
212
213 #define DIRENTRIES_PER_SECTOR (MEDIA_SECTOR_SIZE / 32) // The number of directory entries in a sector
214
215 // Maximum number of UTF16 words in single Root directory entry
216 #define MAX_UTF16_CHARS_IN_LFN_ENTRY (BYTE)13
217
218 // Long File Name Entry
219 typedef struct
220 {
221 BYTE LFN_SequenceNo; // Sequence number,
222 BYTE LFN_Part1[10]; // File name part 1
223 BYTE LFN_Attribute; // File attribute
224 BYTE LFN_Type; // LFN Type
225 BYTE LFN_Checksum; // Checksum
226 unsigned short int LFN_Part2[6]; // File name part 2
227 unsigned short int LFN_Reserved2; // Reserved for future use
228 unsigned short int LFN_Part3[2]; // File name part 3
229 }LFN_ENTRY;
230
231 /* Summary: Possible type of file or directory name.
232 ** Description: See the FormatFileName() & FormatDirName() function for more information.
233 */
234 typedef enum
235 {
236 NAME_8P3_ASCII_CAPS_TYPE,
237 NAME_8P3_ASCII_MIXED_TYPE,
238 NAME_8P3_UTF16_TYPE, // SUBTYPES OF 8P3 UTF16 TYPE
239 NAME_8P3_UTF16_ASCII_CAPS_TYPE,
240 NAME_8P3_UTF16_ASCII_MIXED_TYPE,
241 NAME_8P3_UTF16_NONASCII_TYPE,
242 NAME_LFN_TYPE,
243 NAME_ERROR
244 } FILE_DIR_NAME_TYPE;
245
246 // internal errors
247 #define CE_FAT_EOF 60 // Error that indicates an attempt to read FAT entries beyond the end of the file
248 #define CE_EOF 61 // Error that indicates that the end of the file has been reached
249
250 typedef FSFILE * FILEOBJ; // Pointer to an FSFILE object
251
252 #ifdef ALLOW_FSFPRINTF
253
254 #define _FLAG_MINUS 0x1 // FSfprintf minus flag indicator
255 #define _FLAG_PLUS 0x2 // FSfprintf plus flag indicator
256 #define _FLAG_SPACE 0x4 // FSfprintf space flag indicator
257 #define _FLAG_OCTO 0x8 // FSfprintf octothorpe (hash mark) flag indicator
258 #define _FLAG_ZERO 0x10 // FSfprintf zero flag indicator
259 #define _FLAG_SIGNED 0x80 // FSfprintf signed flag indicator
260
261 #ifdef __18CXX
262 #define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag
263 #define _FMT_LONG 1 // FSfprintf 32-bit argument size flag
264 #define _FMT_SHRTLONG 2 // FSfprintf 24-bit argument size flag
265 #define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag
266 #else
267 #define _FMT_UNSPECIFIED 0 // FSfprintf unspecified argument size flag
268 #define _FMT_LONGLONG 1 // FSfprintf 64-bit argument size flag
269 #define _FMT_LONG 2 // FSfprintf 32-bit argument size flag
270 #define _FMT_BYTE 3 // FSfprintf 8-bit argument size flag
271 #endif
272
273 #ifdef __18CXX
274 static const rom char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits
275 #else
276 static const char s_digits[] = "0123456789abcdef"; // FSfprintf table of conversion digits
277 #endif
278
279 #endif
280
281 /************************************************************************************/
282 /* Prototypes */
283 /************************************************************************************/
284
285 DWORD ReadFAT (DISK *dsk, DWORD ccls);
286 DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead);
287 BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle);
288 DWORD Cluster2Sector(DISK * disk, DWORD cluster);
289 DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle);
290 #ifdef INCREMENTTIMESTAMP
291 void IncrementTimeStamp(DIRENTRY dir);
292 #elif defined USEREALTIMECLOCK
293 void CacheTime (void);
294 #endif
295
296 #if defined (__C30__) || defined (__PIC32MX__)
297 BYTE ReadByte( BYTE* pBuffer, WORD index );
298 WORD ReadWord( BYTE* pBuffer, WORD index );
299 DWORD ReadDWord( BYTE* pBuffer, WORD index );
300 #endif
301
302 void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource);
303 FILE_DIR_NAME_TYPE ValidateChars(BYTE mode);
304 BYTE FormatFileName( const char* fileName, FILEOBJ fptr, BYTE mode);
305 CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode);
306 BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n);
307 CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type);
308 #if defined(SUPPORT_LFN)
309 BOOL Alias_LFN_Object(FILEOBJ fo);
310 BYTE Fill_LFN_Object(FILEOBJ fo, LFN_ENTRY *lfno, WORD *fHandle);
311 #endif
312
313 // Write functions
314 #ifdef ALLOW_WRITES
315 BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry);
316 BYTE flushData (void);
317 CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters);
318 BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode);
319 BYTE FAT_erase_cluster_chain (DWORD cluster, DISK * dsk);
320 DWORD FATfindEmptyCluster(FILEOBJ fo);
321 BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle);
322 BYTE PopulateEntries(FILEOBJ fo, WORD *fHandle, BYTE mode);
323 CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster);
324 BYTE EraseCluster(DISK *disk, DWORD cluster);
325 CETYPE CreateFirstCluster(FILEOBJ fo);
326 DWORD WriteFAT (DISK *dsk, DWORD ccls, DWORD value, BYTE forceWrite);
327 CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode, BOOL createFirstCluster);
328 #endif
329
330 // Directory functions
331 #ifdef ALLOW_DIRS
332 BYTE GetPreviousEntry (FSFILE * fo);
333 BYTE FormatDirName (char * string,FILEOBJ fptr, BYTE mode);
334 int CreateDIR (char * path);
335 BYTE writeDotEntries (DISK * dsk, DWORD dotAddress, DWORD dotdotAddress);
336 int eraseDir (char * path);
337 #ifdef ALLOW_PGMFUNCTIONS
338 #ifdef ALLOW_WRITES
339 int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr);
340 int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs);
341 #endif
342 int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr);
343 #else
344 #ifdef ALLOW_WRITES
345 int mkdirhelper (BYTE mode, char * ramptr, char * romptr);
346 int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs);
347 #endif
348 int chdirhelper (BYTE mode, char * ramptr, char * romptr);
349 #endif
350 #endif
351
352 #ifdef ALLOW_FSFPRINTF
353 #ifdef __18CXX
354 int FSvfprintf (auto FSFILE *handle, auto const rom char *formatString, auto va_list ap);
355 #else
356 int FSvfprintf (FSFILE *handle, const char *formatString, va_list ap);
357 #endif
358 int FSputc (char c, FSFILE * file);
359 unsigned char str_put_n_chars (FSFILE * handle, unsigned char n, char c);
360 #endif
361
362 BYTE DISKmount( DISK *dsk);
363 BYTE LoadMBR(DISK *dsk);
364 BYTE LoadBootSector(DISK *dsk);
365 DWORD GetFullClusterNumber(DIRENTRY entry);
366
367
368 /*************************************************************************
369 Function:
370 int FSInit(void)
371 Summary:
372 Function to initialize the device.
373 Conditions:
374 The physical device should be connected to the microcontroller.
375 Input:
376 None
377 Return Values:
378 TRUE - Initialization successful
379 FALSE - Initialization unsuccessful
380 Side Effects:
381 The FSerrno variable will be changed.
382 Description:
383 Initializes the static or dynamic memory slots for holding file
384 structures. Initializes the device with the DISKmount function. Loads
385 MBR and boot sector information. Initializes the current working
386 directory to the root directory for the device if directory support
387 is enabled.
388 Remarks:
389 None
390 *************************************************************************/
391
392 int FSInit(void)
393 {
394 int fIndex;
395 #ifndef FS_DYNAMIC_MEM
396 for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ )
397 gFileSlotOpen[fIndex] = TRUE;
398 #else
399 #ifdef __18CXX
400 SRAMInitHeap();
401 #endif
402 #endif
403
404 gBufferZeroed = FALSE;
405 gNeedFATWrite = FALSE;
406 gLastFATSectorRead = 0xFFFFFFFF;
407 gLastDataSectorRead = 0xFFFFFFFF;
408
409 MDD_InitIO();
410
411 if(DISKmount(&gDiskData) == CE_GOOD)
412 {
413 // Initialize the current working directory to the root
414 #ifdef ALLOW_DIRS
415 cwdptr->dsk = &gDiskData;
416 cwdptr->sec = 0;
417 cwdptr->pos = 0;
418 cwdptr->seek = 0;
419 cwdptr->size = 0;
420 cwdptr->name[0] = '\\';
421 for (fIndex = 1; fIndex < 11; fIndex++)
422 {
423 cwdptr->name[fIndex] = 0x20;
424 }
425 cwdptr->entry = 0;
426 cwdptr->attributes = ATTR_DIRECTORY;
427 // "FatRootDirClusterValue" indicates the root
428 cwdptr->dirclus = FatRootDirClusterValue;
429 cwdptr->dirccls = FatRootDirClusterValue;
430 #if defined(SUPPORT_LFN)
431 // Initialize default values for LFN support
432 cwdptr->AsciiEncodingType = TRUE;
433 cwdptr->utf16LFNlength = 0x0000;
434 #endif
435 #endif
436
437 FSerrno = 0;
438 return TRUE;
439 }
440
441 return FALSE;
442 }
443
444
445 /********************************************************************************
446 Function:
447 CETYPE FILEfind (FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode)
448 Summary
449 Finds a file on the device
450 Conditions:
451 This function should not be called by the user.
452 Input:
453 foDest - FSFILE object containing information of the file found
454 foCompareTo - FSFILE object containing the name/attr of the file to be
455 found
456 cmd -
457 - LOOK_FOR_EMPTY_ENTRY: Search for empty entry.
458 - LOOK_FOR_MATCHING_ENTRY: Search for matching entry.
459 mode -
460 - 0: Match file exactly with default attributes.
461 - 1: Match file to user-specified attributes.
462 Return Values:
463 CE_GOOD - File found.
464 CE_FILE_NOT_FOUND - File not found.
465 Side Effects:
466 None.
467 Description:
468 The FILEfind function will sequentially cache directory entries within
469 the current working directory into the foDest FSFILE object. If the cmd
470 parameter is specified as LOOK_FOR_EMPTY_ENTRY the search will continue
471 until an empty directory entry is found. If the cmd parameter is specified
472 as LOOK_FOR_MATCHING_ENTRY these entries will be compared to the foCompareTo
473 object until a match is found or there are no more entries in the current
474 working directory. If the mode is specified a '0' the attributes of the FSFILE
475 entries are irrelevant. If the mode is specified as '1' the attributes of the
476 foDest entry must match the attributes specified in the foCompareTo file and
477 partial string search characters may bypass portions of the comparison.
478 Remarks:
479 None
480 ********************************************************************************/
481
482 CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd, BYTE mode)
483 {
484 WORD attrib, compareAttrib;
485 WORD fHandle = foDest->entry; // current entry counter
486 CETYPE statusB = CE_FILE_NOT_FOUND;
487 BYTE character,test,state,index;
488
489 #if defined(SUPPORT_LFN)
490
491 LFN_ENTRY lfnObject; // Long File Name Object
492 unsigned char *dst = (unsigned char *)&fileFoundString[0];
493 unsigned short int *templfnPtr = (unsigned short int *)foCompareTo -> utf16LFNptr;
494 UINT16_VAL tempShift;
495 short int fileCompareLfnIndex,fileFoundLfnIndex = 0,fileFoundMaxLfnIndex = 0,lfnCountIndex;
496 BOOL lfnFirstCheck = FALSE,foundSFN,foundLFN,fileFoundDotPosition = FALSE,fileCompareDotPosition;
497 BYTE lfnMaxSequenceNum = 0,reminder = 0;
498
499 fileNameLength = foCompareTo->utf16LFNlength;
500
501 // If 'fileNameLength' is non zero then it means that file name is of LFN format.
502 // If 'fileNameLength' is zero then it means that file name is of 8.3 format
503 if(fileNameLength)
504 {
505 // Find out the number of root entries for the given LFN
506 reminder = fileNameLength % MAX_UTF16_CHARS_IN_LFN_ENTRY;
507
508 index = fileNameLength/MAX_UTF16_CHARS_IN_LFN_ENTRY;
509
510 if(reminder || (fileNameLength < MAX_UTF16_CHARS_IN_LFN_ENTRY))
511 {
512 index++;
513 }
514
515 // The maximum sequence number of the LFN
516 lfnMaxSequenceNum = (BYTE)0x40 | (BYTE)index;
517 }
518 #endif
519
520 // reset the cluster
521 foDest->dirccls = foDest->dirclus;
522 // Attribute to be compared as per application layer request
523 compareAttrib = 0xFFFF ^ foCompareTo->attributes;
524
525 if (fHandle == 0)
526 {
527 if (Cache_File_Entry(foDest, &fHandle, TRUE) == NULL)
528 {
529 statusB = CE_BADCACHEREAD;
530 }
531 }
532 else
533 {
534 // Maximum 16 entries possible
535 if ((fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) != 0)
536 {
537 if (Cache_File_Entry (foDest, &fHandle, TRUE) == NULL)
538 {
539 statusB = CE_BADCACHEREAD;
540 }
541 }
542 }
543
544 if (statusB != CE_BADCACHEREAD)
545 {
546 // Loop until you reach the end or find the file
547 while(1)
548 {
549 if(statusB != CE_GOOD) //First time entry always here
550 {
551 #if defined(SUPPORT_LFN)
552 state = Fill_LFN_Object(foDest,&lfnObject,&fHandle);
553 #else
554 state = Fill_File_Object(foDest, &fHandle);
555 #endif
556
557 if(state == NO_MORE) // Reached the end of available files. Comparision over and file not found so quit.
558 {
559 break;
560 }
561 }
562 else // statusB == CE_GOOD then exit
563 {
564 break; // Code below intializes"statusB = CE_GOOD;" so, if no problem in the filled file, Exit the while loop.
565 }
566
567 if(state == FOUND) // Validate the correct matching of filled file data with the required(to be found) one.
568 {
569 #if defined(SUPPORT_LFN)
570 foundSFN = FALSE;
571 foundLFN = FALSE;
572
573 if(lfnObject.LFN_Attribute != ATTR_LONG_NAME)
574 {
575 lfnFirstCheck = FALSE;
576 if((mode == 0x00) && fileNameLength)
577 {
578 fHandle++;
579 continue;
580 }
581
582 *dst = lfnObject.LFN_SequenceNo;
583 for(index = 0;index < 10;index++)
584 dst[index + 1] = lfnObject.LFN_Part1[index];
585 foundSFN = TRUE;
586 }
587 else
588 {
589 if(lfnObject.LFN_SequenceNo & 0x40)
590 {
591 if((mode == 0x00) && ((fileNameLength && (lfnObject.LFN_SequenceNo != lfnMaxSequenceNum)) || !fileNameLength))
592 {
593 // fHandle = fHandle + (lfnObject.LFN_SequenceNo & 0xBF) + 1;
594 fHandle++;
595 continue;
596 }
597
598 fileFoundLfnIndex = (lfnObject.LFN_SequenceNo & 0xBF) * MAX_UTF16_CHARS_IN_LFN_ENTRY - 1;
599 fileCompareLfnIndex = fileFoundLfnIndex;
600
601 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[1];
602 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[0];
603
604 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[5];
605 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[4];
606 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[3];
607 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[2];
608 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[1];
609 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[0];
610
611 tempShift.byte.LB = lfnObject.LFN_Part1[8];
612 tempShift.byte.HB = lfnObject.LFN_Part1[9];
613 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
614 tempShift.byte.LB = lfnObject.LFN_Part1[6];
615 tempShift.byte.HB = lfnObject.LFN_Part1[7];
616 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
617 tempShift.byte.LB = lfnObject.LFN_Part1[4];
618 tempShift.byte.HB = lfnObject.LFN_Part1[5];
619 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
620 tempShift.byte.LB = lfnObject.LFN_Part1[2];
621 tempShift.byte.HB = lfnObject.LFN_Part1[3];
622 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
623 tempShift.byte.LB = lfnObject.LFN_Part1[0];
624 tempShift.byte.HB = lfnObject.LFN_Part1[1];
625 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
626
627 if(reminder)
628 index = reminder;
629 else
630 index = MAX_UTF16_CHARS_IN_LFN_ENTRY;
631
632 if(mode == 0x00)
633 {
634 if((fileFoundString[fileFoundLfnIndex + index] != 0x00) && fileNameLength)
635 {
636 // fHandle = fHandle + (lfnObject.LFN_SequenceNo & 0xBF) + 1;
637 fHandle++;
638 continue;
639 }
640 }
641 else
642 {
643 while(fileFoundString[fileCompareLfnIndex])
644 fileCompareLfnIndex--;
645 fileFoundMaxLfnIndex = fileCompareLfnIndex - 1;
646 }
647 lfnFirstCheck = TRUE;
648 }
649 else if(lfnFirstCheck == TRUE)
650 {
651 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[1];
652 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part3[0];
653
654 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[5];
655 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[4];
656 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[3];
657 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[2];
658 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[1];
659 fileFoundString[fileFoundLfnIndex--] = lfnObject.LFN_Part2[0];
660
661 tempShift.byte.LB = lfnObject.LFN_Part1[8];
662 tempShift.byte.HB = lfnObject.LFN_Part1[9];
663 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
664 tempShift.byte.LB = lfnObject.LFN_Part1[6];
665 tempShift.byte.HB = lfnObject.LFN_Part1[7];
666 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
667 tempShift.byte.LB = lfnObject.LFN_Part1[4];
668 tempShift.byte.HB = lfnObject.LFN_Part1[5];
669 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
670 tempShift.byte.LB = lfnObject.LFN_Part1[2];
671 tempShift.byte.HB = lfnObject.LFN_Part1[3];
672 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
673 tempShift.byte.LB = lfnObject.LFN_Part1[0];
674 tempShift.byte.HB = lfnObject.LFN_Part1[1];
675 fileFoundString[fileFoundLfnIndex--] = tempShift.Val;
676 }
677 else
678 {
679 fHandle++;
680 continue;
681 }
682
683 if(fileFoundLfnIndex > 0)
684 {
685 fHandle++;
686 continue;
687 }
688
689 foundLFN = TRUE;
690 }
691
692 lfnFirstCheck = FALSE;
693 statusB = CE_GOOD;
694 switch (mode)
695 {
696 case 0:
697 if(fileNameLength)
698 {
699 // see if we are a volume id or hidden, ignore
700 // search for one. if status = TRUE we found one
701 for(fileCompareLfnIndex = 0;fileCompareLfnIndex < fileNameLength;fileCompareLfnIndex++)
702 {
703 if(foCompareTo -> AsciiEncodingType)
704 {
705 // get the source character
706 character = (BYTE)templfnPtr[fileCompareLfnIndex];
707 // get the destination character
708 test = (BYTE)fileFoundString[fileCompareLfnIndex];
709 if((fileFoundString[fileCompareLfnIndex] > 0xFF) || (tolower(character) != tolower(test)))
710 {
711 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
712 break;
713 }
714 }
715 else
716 {
717 if(templfnPtr[fileCompareLfnIndex] != fileFoundString[fileCompareLfnIndex])
718 {
719 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
720 break;
721 }
722 }
723 }// for loop
724 }
725 else
726 {
727 /* We got something */
728 character = (BYTE)'m'; // random value
729
730 // search for one. if status = TRUE we found one
731 for(index = 0; index < DIR_NAMECOMP; index++)
732 {
733 // get the source character
734 character = dst[index];
735 // get the destination character
736 test = foCompareTo->name[index];
737 if(tolower(character) != tolower(test))
738 {
739 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
740 break;
741 }
742 }// for loop
743 }
744 break;
745
746 case 1:
747 if(fileNameLength)
748 {
749 fileFoundDotPosition = FALSE;
750 if(foundLFN)
751 {
752 lfnCountIndex = fileFoundMaxLfnIndex;
753 while(lfnCountIndex > 0)
754 {
755 if(fileFoundString[lfnCountIndex] == '.')
756 {
757 fileFoundDotPosition = TRUE;
758 lfnCountIndex--;
759 break;
760 }
761 lfnCountIndex--;
762 }
763
764 if(fileFoundDotPosition == FALSE)
765 lfnCountIndex = fileFoundMaxLfnIndex;
766 }
767 else
768 {
769 if(dst[DIR_NAMESIZE] != ' ')
770 fileFoundDotPosition = TRUE;
771 lfnCountIndex = DIR_NAMESIZE - 1;
772 }
773
774 fileFoundLfnIndex = fileNameLength - 1;
775 fileCompareDotPosition = FALSE;
776 while(fileFoundLfnIndex > 0)
777 {
778 if(templfnPtr[fileFoundLfnIndex] == '.')
779 {
780 fileCompareDotPosition = TRUE;
781 fileFoundLfnIndex--;
782 break;
783 }
784 fileFoundLfnIndex--;
785 }
786 if(fileCompareDotPosition == FALSE)
787 fileFoundLfnIndex = fileNameLength - 1;
788
789 // Check for attribute match
790 for(fileCompareLfnIndex = 0;;)
791 {
792 if (templfnPtr[fileCompareLfnIndex] == '*')
793 break;
794
795 if(fileCompareLfnIndex > lfnCountIndex)
796 {
797 // if(foundLFN)
798 // fHandle++;
799 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
800 break;
801 }
802
803 if (templfnPtr[fileCompareLfnIndex] != '?')
804 {
805 if(foCompareTo -> AsciiEncodingType)
806 {
807 // get the source character
808 character = (BYTE)templfnPtr[fileCompareLfnIndex];
809 // get the destination character
810 if(foundLFN)
811 test = (BYTE)fileFoundString[fileCompareLfnIndex];
812 else
813 test = dst[fileCompareLfnIndex];
814
815 if((foundLFN && (fileFoundString[fileCompareLfnIndex] > 0xFF)) ||
816 (tolower(character) != tolower(test)))
817 {
818 // if(foundLFN)
819 // fHandle++;
820 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
821 break;
822 }
823 }
824 else
825 {
826 if((templfnPtr[fileCompareLfnIndex] != fileFoundString[fileCompareLfnIndex]) || foundSFN)
827 {
828 // if(foundLFN)
829 // fHandle++;
830 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
831 break;
832 }
833 }
834 }
835
836 fileCompareLfnIndex++;
837 if(fileCompareLfnIndex > fileFoundLfnIndex)
838 {
839 if(fileCompareLfnIndex <= lfnCountIndex)
840 {
841 // if(foundLFN)
842 // fHandle++;
843 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
844 }
845 break;
846 }
847 }// for loop
848
849 if(fileCompareDotPosition == FALSE)
850 {
851 if(fileFoundDotPosition == TRUE)
852 {
853 // if(foundLFN)
854 // fHandle++;
855 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
856 }
857 break;
858 }
859 else
860 {
861 if(fileFoundDotPosition == FALSE)
862 {
863 // if(foundLFN)
864 // fHandle++;
865 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
866 break;
867 }
868
869 if(foundLFN)
870 lfnCountIndex = lfnCountIndex + 2;
871 else
872 lfnCountIndex = DIR_NAMESIZE;
873 }
874
875 // Check for attribute match
876 for(fileCompareLfnIndex = fileFoundLfnIndex + 2;;)
877 {
878 if (templfnPtr[fileCompareLfnIndex] == '*')
879 break;
880
881 if((foundLFN && (lfnCountIndex > fileFoundMaxLfnIndex)) || (foundSFN && (lfnCountIndex == 11)))
882 {
883 // if(foundLFN)
884 // fHandle++;
885 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
886 break;
887 }
888
889 if (templfnPtr[fileCompareLfnIndex] != '?')
890 {
891 if(foCompareTo -> AsciiEncodingType)
892 {
893 // get the source character
894 character = (BYTE)templfnPtr[fileCompareLfnIndex];
895 // get the destination character
896 if(foundLFN)
897 test = (BYTE)fileFoundString[lfnCountIndex];
898 else
899 test = dst[lfnCountIndex];
900 if((foundLFN && (fileFoundString[lfnCountIndex] > 0xFF)) ||
901 (tolower(character) != tolower(test)))
902 {
903 // if(foundLFN)
904 // fHandle++;
905 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
906 break;
907 }
908 }
909 else
910 {
911 if((templfnPtr[fileCompareLfnIndex] != fileFoundString[lfnCountIndex]) || foundSFN)
912 {
913 // if(foundLFN)
914 // fHandle++;
915 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
916 break;
917 }
918 }
919 }
920 lfnCountIndex++;
921 fileCompareLfnIndex++;
922 if(fileCompareLfnIndex == (fileNameLength - 1))
923 {
924 if((foundLFN && (lfnCountIndex <= fileFoundMaxLfnIndex)) || (foundSFN && (lfnCountIndex < 11) && (dst[lfnCountIndex] != ' ')))
925 {
926 // if(foundLFN)
927 // fHandle++;
928 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
929 }
930 break;
931 }
932 }// for loop
933 }
934 else
935 {
936 /* We got something */
937 if(foundLFN)
938 {
939 fileCompareLfnIndex = fileFoundMaxLfnIndex;
940 fileFoundDotPosition = FALSE;
941 while(fileCompareLfnIndex > 0)
942 {
943 if(fileFoundString[fileCompareLfnIndex] == '.')
944 {
945 fileFoundDotPosition = TRUE;
946 fileCompareLfnIndex--;
947 break;
948 }
949 fileCompareLfnIndex--;
950 }
951
952 if(fileFoundDotPosition == FALSE)
953 fileCompareLfnIndex = fileFoundMaxLfnIndex;
954 }
955 else
956 fileCompareLfnIndex = DIR_NAMESIZE - 1; // Short File name last char position
957
958 character = (BYTE)'m'; // random value
959 if (foCompareTo->name[0] != '*') //If "*" is passed for comparion as 1st char then don't proceed. Go back, file alreay found.
960 {
961 for (index = 0;;)
962 {
963 if(foundLFN)
964 {
965 if((fileFoundString[index] > 0xFF) || (index > fileCompareLfnIndex))
966 {
967 // fHandle++;
968 statusB = CE_FILE_NOT_FOUND; // it's not a match
969 break;
970 }
971 }
972
973 // Get the source character
974 if(foundLFN)
975 character = (BYTE)fileFoundString[index];
976 else
977 character = dst[index];
978
979 // Get the destination character
980 test = foCompareTo->name[index];
981 if (test == '*')
982 break;
983 if (test != '?')
984 {
985 if(tolower(character) != tolower(test))
986 {
987 statusB = CE_FILE_NOT_FOUND; // it's not a match
988 break;
989 }
990 }
991
992 index++;
993 if(index == DIR_NAMESIZE)
994 {
995 if(foundLFN && (index <= fileCompareLfnIndex))
996 {
997 // fHandle++;
998 statusB = CE_FILE_NOT_FOUND; // it's not a match
999 }
1000 break;
1001 }
1002 }
1003 }
1004
1005 // Before calling this "FILEfind" fn, "formatfilename" must be called. Hence, extn always starts from position "8".
1006 if ((foCompareTo->name[8] != '*') && (statusB == CE_GOOD))
1007 {
1008 if(foundLFN)
1009 {
1010 if(foCompareTo->name[8] == ' ')
1011 {
1012 if(fileFoundDotPosition == TRUE)
1013 {
1014 // fHandle++;
1015 statusB = CE_FILE_NOT_FOUND; // it's not a match
1016 }
1017 break;
1018 }
1019 else
1020 {
1021 if(fileFoundDotPosition == FALSE)
1022 {
1023 // fHandle++;
1024 statusB = CE_FILE_NOT_FOUND; // it's not a match
1025 break;
1026 }
1027 }
1028 fileCompareLfnIndex = fileCompareLfnIndex + 2;
1029 }
1030 else
1031 fileCompareLfnIndex = DIR_NAMESIZE;
1032
1033 for (index = 8;;)
1034 {
1035 if(foundLFN)
1036 {
1037 if((fileFoundString[fileCompareLfnIndex] > 0xFF) || (fileCompareLfnIndex > fileFoundMaxLfnIndex))
1038 {
1039 // fHandle++;
1040 statusB = CE_FILE_NOT_FOUND; // it's not a match
1041 break;
1042 }
1043 }
1044 // Get the destination character
1045 test = foCompareTo->name[index];
1046 // Get the source character
1047 if(foundLFN)
1048 character = (BYTE)fileFoundString[fileCompareLfnIndex++];
1049 else
1050 character = dst[fileCompareLfnIndex++];
1051
1052 if (test == '*')
1053 break;
1054 if (test != '?')
1055 {
1056 if(tolower(character) != tolower(test))
1057 {
1058 statusB = CE_FILE_NOT_FOUND; // it's not a match
1059 break;
1060 }
1061 }
1062
1063 index++;
1064 if(index == DIR_NAMECOMP)
1065 {
1066 if(foundLFN && (fileCompareLfnIndex <= fileFoundMaxLfnIndex))
1067 statusB = CE_FILE_NOT_FOUND; // it's not a match
1068 break;
1069 }
1070 }
1071 }
1072 }
1073 break;
1074 }
1075
1076 // If the comparision of each character in LFN is completed
1077 if(statusB == CE_GOOD)
1078 {
1079 if(foundLFN)
1080 fHandle++;
1081
1082 state = Fill_File_Object(foDest, &fHandle);
1083
1084 /* We got something get the attributes */
1085 attrib = foDest->attributes;
1086
1087 attrib &= ATTR_MASK;
1088
1089 switch (mode)
1090 {
1091 case 0:
1092 // see if we are a volume id or hidden, ignore
1093 if(attrib == ATTR_VOLUME)
1094 statusB = CE_FILE_NOT_FOUND;
1095 break;
1096
1097 case 1:
1098 // Check for attribute match
1099 if ((attrib & compareAttrib) != 0)
1100 statusB = CE_FILE_NOT_FOUND; // Indicate the already filled file data is correct and go back
1101 if(foundLFN)
1102 foDest->utf16LFNlength = fileFoundMaxLfnIndex + 1;
1103 else
1104 foDest->utf16LFNlength = 0;
1105 break;
1106 }
1107 }
1108 #else
1109 {
1110 /* We got something */
1111 // get the attributes
1112 attrib = foDest->attributes;
1113
1114 attrib &= ATTR_MASK;
1115 switch (mode)
1116 {
1117 case 0:
1118 // see if we are a volume id or hidden, ignore
1119 if(attrib != ATTR_VOLUME)
1120 {
1121 statusB = CE_GOOD;
1122 character = (BYTE)'m'; // random value
1123
1124 // search for one. if status = TRUE we found one
1125 for(index = 0; index < DIR_NAMECOMP; index++)
1126 {
1127 // get the source character
1128 character = foDest->name[index];
1129 // get the destination character
1130 test = foCompareTo->name[index];
1131 if(tolower(character) != tolower(test))
1132 {
1133 statusB = CE_FILE_NOT_FOUND; // Nope its not a match
1134 break;
1135 }
1136 }// for loop
1137 } // not dir nor vol
1138 break;
1139
1140 case 1:
1141 // Check for attribute match
1142 if (((attrib & compareAttrib) == 0) && (attrib != ATTR_LONG_NAME))
1143 {
1144 statusB = CE_GOOD; // Indicate the already filled file data is correct and go back
1145 character = (BYTE)'m'; // random value
1146 if (foCompareTo->name[0] != '*') //If "*" is passed for comparion as 1st char then don't proceed. Go back, file alreay found.
1147 {
1148 for (index = 0; index < DIR_NAMESIZE; index++)
1149 {
1150 // Get the source character
1151 character = foDest->name[index];
1152 // Get the destination character
1153 test = foCompareTo->name[index];
1154 if (test == '*')
1155 break;
1156 if (test != '?')
1157 {
1158 if(tolower(character) != tolower(test))
1159 {
1160 statusB = CE_FILE_NOT_FOUND; // it's not a match
1161 break;
1162 }
1163 }
1164 }
1165 }
1166
1167 // Before calling this "FILEfind" fn, "formatfilename" must be called. Hence, extn always starts from position "8".
1168 if ((foCompareTo->name[8] != '*') && (statusB == CE_GOOD))
1169 {
1170 for (index = 8; index < DIR_NAMECOMP; index++)
1171 {
1172 // Get the source character
1173 character = foDest->name[index];
1174 // Get the destination character
1175 test = foCompareTo->name[index];
1176 if (test == '*')
1177 break;
1178 if (test != '?')
1179 {
1180 if(tolower(character) != tolower(test))
1181 {
1182 statusB = CE_FILE_NOT_FOUND; // it's not a match
1183 break;
1184 }
1185 }
1186 }
1187 }
1188
1189 } // Attribute match
1190
1191 break;
1192 }
1193 }
1194 #endif
1195 } // not found
1196 else
1197 {
1198 #if defined(SUPPORT_LFN)
1199 lfnFirstCheck = FALSE;
1200 #endif
1201 /*** looking for an empty/re-usable entry ***/
1202 if ( cmd == LOOK_FOR_EMPTY_ENTRY)
1203 statusB = CE_GOOD;
1204 } // found or not
1205
1206 // increment it no matter what happened
1207 fHandle++;
1208
1209 }// while
1210 }
1211
1212 return(statusB);
1213 } // FILEFind
1214
1215
1216 /**************************************************************************
1217 Function:
1218 CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
1219 Summary:
1220 Loads file information from the device
1221 Conditions:
1222 This function should not be called by the user.
1223 Input:
1224 fo - File to be opened
1225 fHandle - Location of file
1226 type -
1227 - WRITE - Create a new file or replace an existing file
1228 - READ - Read data from an existing file
1229 - APPEND - Append data to an existing file
1230 Return Values:
1231 CE_GOOD - FILEopen successful
1232 CE_NOT_INIT - Device is not yet initialized
1233 CE_FILE_NOT_FOUND - Could not find the file on the device
1234 CE_BAD_SECTOR_READ - A bad read of a sector occured
1235 Side Effects:
1236 None
1237 Description:
1238 This function will cache a directory entry in the directory specified
1239 by the dirclus parameter of hte FSFILE object 'fo.' The offset of the
1240 entry in the directory is specified by fHandle. Once the directory entry
1241 has been loaded, the first sector of the file can be loaded using the
1242 cluster value specified in the directory entry. The type argument will
1243 specify the mode the files will be opened in. This will allow this
1244 function to set the correct read/write flags for the file.
1245 Remarks:
1246 If the mode the file is being opened in is a plus mode (e.g. READ+) the
1247 flags will be modified further in the FSfopen function.
1248 **************************************************************************/
1249
1250 CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
1251 {
1252 DISK *dsk; //Disk structure
1253 BYTE r; //Result of search for file
1254 DWORD l; //lba of first sector of first cluster
1255 CETYPE error = CE_GOOD;
1256
1257 dsk = (DISK *)(fo->dsk);
1258 if (dsk->mount == FALSE)
1259 {
1260 error = CE_NOT_INIT;
1261 }
1262 else
1263 {
1264 // load the sector
1265 fo->dirccls = fo->dirclus;
1266 // Cache no matter what if it's the first entry
1267 if (*fHandle == 0)
1268 {
1269 if (Cache_File_Entry(fo, fHandle, TRUE) == NULL)
1270 {
1271 error = CE_BADCACHEREAD;
1272 }
1273 }
1274 else
1275 {
1276 // If it's not the first, only cache it if it's
1277 // not divisible by the number of entries per sector
1278 // If it is, Fill_File_Object will cache it
1279 if ((*fHandle & 0xf) != 0)
1280 {
1281 if (Cache_File_Entry (fo, fHandle, TRUE) == NULL)
1282 {
1283 error = CE_BADCACHEREAD;
1284 }
1285 }
1286 }
1287
1288 // Fill up the File Object with the information pointed to by fHandle
1289 r = Fill_File_Object(fo, fHandle);
1290 if (r != FOUND)
1291 error = CE_FILE_NOT_FOUND;
1292 else
1293 {
1294 fo->seek = 0; // first byte in file
1295 fo->ccls = fo->cluster; // first cluster
1296 fo->sec = 0; // first sector in the cluster
1297 fo->pos = 0; // first byte in sector/cluster
1298
1299 if ( r == NOT_FOUND)
1300 {
1301 error = CE_FILE_NOT_FOUND;
1302 }
1303 else
1304 {
1305 // Determine the lba of the selected sector and load
1306 l = Cluster2Sector(dsk,fo->ccls);
1307 #ifdef ALLOW_WRITES
1308 if (gNeedDataWrite)
1309 if (flushData())
1310 return CE_WRITE_ERROR;
1311 #endif
1312 gBufferOwner = fo;
1313 if (gLastDataSectorRead != l)
1314 {
1315 gBufferZeroed = FALSE;
1316 if ( !MDD_SectorRead( l, dsk->buffer))
1317 error = CE_BAD_SECTOR_READ;
1318 gLastDataSectorRead = l;
1319 }
1320 } // -- found
1321
1322 fo->flags.FileWriteEOF = FALSE;
1323 // Set flag for operation type
1324 #ifdef ALLOW_WRITES
1325 if ((type == 'w') || (type == 'a'))
1326 {
1327 fo->flags.write = 1; //write or append
1328 fo->flags.read = 0;
1329 }
1330 else
1331 {
1332 #endif
1333 fo->flags.write = 0; //read
1334 fo->flags.read = 1;
1335 #ifdef ALLOW_WRITES
1336 } // -- flags
1337 #endif
1338 } // -- r = Found
1339 } // -- Mounted
1340 return (error);
1341 } // -- FILEopen
1342
1343
1344 /*************************************************************************
1345 Function:
1346 BYTE FILEget_next_cluster(FILEOBJ fo, WORD n)
1347 Summary:
1348 Step through a chain of clusters
1349 Conditions:
1350 This function should not be called by the user.
1351 Input:
1352 fo - The file to get the next cluster of
1353 n - Number of links in the FAT cluster chain to jump through
1354 Return Values:
1355 CE_GOOD - Operation successful
1356 CE_BAD_SECTOR_READ - A bad read occured of a sector
1357 CE_INVALID_CLUSTER - Invalid cluster value \> maxcls
1358 CE_FAT_EOF - Fat attempt to read beyond EOF
1359 Side Effects:
1360 None
1361 Description:
1362 This function will load 'n' proximate clusters for a file from
1363 the FAT on the device. It will stop checking for clusters if the
1364 ReadFAT function returns an error, if it reaches the last cluster in
1365 a file, or if the device tries to read beyond the last cluster used
1366 by the device.
1367 Remarks:
1368 None
1369 *************************************************************************/
1370
1371 BYTE FILEget_next_cluster(FILEOBJ fo, DWORD n)
1372 {
1373 DWORD c, c2, ClusterFailValue, LastClustervalue;
1374 BYTE error = CE_GOOD;
1375 DISK * disk;
1376
1377 disk = fo->dsk;
1378
1379 /* Settings based on FAT type */
1380 switch (disk->type)
1381 {
1382 #ifdef SUPPORT_FAT32 // If FAT32 supported.
1383 case FAT32:
1384 LastClustervalue = LAST_CLUSTER_FAT32;
1385 ClusterFailValue = CLUSTER_FAIL_FAT32;
1386 break;
1387 #endif
1388 case FAT12:
1389 LastClustervalue = LAST_CLUSTER_FAT12;
1390 ClusterFailValue = CLUSTER_FAIL_FAT16;
1391 break;
1392 case FAT16:
1393 default:
1394 LastClustervalue = LAST_CLUSTER_FAT16;
1395 ClusterFailValue = CLUSTER_FAIL_FAT16;
1396 break;
1397 }
1398
1399 // loop n times
1400 do
1401 {
1402 // get the next cluster link from FAT
1403 c2 = fo->ccls;
1404 if ( (c = ReadFAT( disk, c2)) == ClusterFailValue)
1405 error = CE_BAD_SECTOR_READ;
1406 else
1407 {
1408 // check if cluster value is valid
1409 if ( c >= disk->maxcls)
1410 {
1411 error = CE_INVALID_CLUSTER;
1412 }
1413
1414 // compare against max value of a cluster in FAT
1415 // return if eof
1416 if ( c >= LastClustervalue) // check against eof
1417 {
1418 error = CE_FAT_EOF;
1419 }
1420 }
1421
1422 // update the FSFILE structure
1423 fo->ccls = c;
1424
1425 } while ((--n > 0) && (error == CE_GOOD));// loop end
1426
1427 return(error);
1428 } // get next cluster
1429
1430
1431 /**************************************************************************
1432 Function:
1433 BYTE DISKmount ( DISK *dsk)
1434 Summary:
1435 Initialies the device and loads MBR and boot sector information
1436 Conditions:
1437 This function should not be called by the user.
1438 Input:
1439 dsk - The disk structure to be initialized.
1440 Return Values:
1441 CE_GOOD - Disk mounted
1442 CE_INIT_ERROR - Initialization error has occured
1443 CE_UNSUPPORTED_SECTOR_SIZE - Media sector size bigger than
1444 MEDIA_SECTOR_SIZE as defined in FSconfig.h.
1445 Side Effects:
1446 None
1447 Description:
1448 This function will use the function pointed to by the MDD_MediaInitialize
1449 function pointer to initialize the device (if any initialization is
1450 required). It then attempts to load the master boot record with the
1451 LoadMBR function and the boot sector with the LoadBootSector function.
1452 These two functions will be used to initialize a global DISK structure
1453 that will be used when accessing file information in the future.
1454 Remarks:
1455 None
1456 **************************************************************************/
1457
1458 BYTE DISKmount( DISK *dsk)
1459 {
1460 BYTE error = CE_GOOD;
1461 MEDIA_INFORMATION *mediaInformation;
1462
1463 dsk->mount = FALSE; // default invalid
1464 dsk->buffer = gDataBuffer; // assign buffer
1465
1466 // Initialize the device
1467 mediaInformation = MDD_MediaInitialize();
1468 if (mediaInformation->errorCode != MEDIA_NO_ERROR)
1469 {
1470 error = CE_INIT_ERROR;
1471 FSerrno = CE_INIT_ERROR;
1472 }
1473 else
1474 {
1475 // If the media initialization routine determined the sector size,
1476 // check it and make sure we can support it.
1477 if (mediaInformation->validityFlags.bits.sectorSize)
1478 {
1479 dsk->sectorSize = mediaInformation->sectorSize;
1480 if (mediaInformation->sectorSize > MEDIA_SECTOR_SIZE)
1481 {
1482 error = CE_UNSUPPORTED_SECTOR_SIZE;
1483 FSerrno = CE_UNSUPPORTED_SECTOR_SIZE;
1484 return error;
1485 }
1486 }
1487
1488 // Load the Master Boot Record (partition)
1489 if((error = LoadMBR(dsk)) == CE_GOOD)
1490 {
1491 // Now the boot sector
1492 if((error = LoadBootSector(dsk)) == CE_GOOD)
1493 dsk->mount = TRUE; // Mark that the DISK mounted successfully
1494 }
1495 } // -- Load file parameters
1496
1497 return(error);
1498 } // -- mount
1499
1500
1501
1502 /********************************************************************
1503 Function:
1504 CETYPE LoadMBR ( DISK *dsk)
1505 Summary:
1506 Loads the MBR and extracts necessary information
1507 Conditions:
1508 This function should not be called by the user.
1509 Input:
1510 dsk - The disk containing the master boot record to be loaded
1511 Return Values:
1512 CE_GOOD - MBR loaded successfully
1513 CE_BAD_SECTOR_READ - A bad read occured of a sector
1514 CE_BAD_PARTITION - The boot record is bad
1515 Side Effects:
1516 None
1517 Description:
1518 The LoadMBR function will use the function pointed to by the
1519 MDD_SectorRead function pointer to read the 0 sector from the
1520 device. If a valid boot signature is obtained, this function
1521 will compare fields in that cached sector to the values that
1522 would be present if that sector was a boot sector. If all of
1523 those values match, it will be assumed that the device does not
1524 have a master boot record and the 0 sector is actually the boot
1525 sector. Otherwise, data about the partition and the actual
1526 location of the boot sector will be loaded from the MBR into
1527 the DISK structure pointed to by 'dsk.'
1528 Remarks:
1529 None
1530 ********************************************************************/
1531
1532 BYTE LoadMBR(DISK *dsk)
1533 {
1534 PT_MBR Partition;
1535 BYTE error = CE_GOOD;
1536 BYTE type;
1537 BootSec BSec;
1538
1539 // Get the partition table from the MBR
1540 if ( MDD_SectorRead( FO_MBR, dsk->buffer) != TRUE)
1541 {
1542 error = CE_BAD_SECTOR_READ;
1543 FSerrno = CE_BAD_SECTOR_READ;
1544 }
1545 else
1546 {
1547 // Check if the card has no MBR
1548 BSec = (BootSec) dsk->buffer;
1549
1550 if((BSec->Signature0 == FAT_GOOD_SIGN_0) && (BSec->Signature1 == FAT_GOOD_SIGN_1))
1551 {
1552 // Technically, the OEM name is not for indication
1553 // The alternative is to read the CIS from attribute
1554 // memory. See the PCMCIA metaformat for more details
1555 #if defined (__C30__) || defined (__PIC32MX__)
1556 if ((ReadByte( dsk->buffer, BSI_FSTYPE ) == 'F') && \
1557 (ReadByte( dsk->buffer, BSI_FSTYPE + 1 ) == 'A') && \
1558 (ReadByte( dsk->buffer, BSI_FSTYPE + 2 ) == 'T') && \
1559 (ReadByte( dsk->buffer, BSI_FSTYPE + 3 ) == '1') && \
1560 (ReadByte( dsk->buffer, BSI_BOOTSIG) == 0x29))
1561 #else
1562 if ((BSec->FAT.FAT_16.BootSec_FSType[0] == 'F') && \
1563 (BSec->FAT.FAT_16.BootSec_FSType[1] == 'A') && \
1564 (BSec->FAT.FAT_16.BootSec_FSType[2] == 'T') && \
1565 (BSec->FAT.FAT_16.BootSec_FSType[3] == '1') && \
1566 (BSec->FAT.FAT_16.BootSec_BootSig == 0x29))
1567 #endif
1568 {
1569 dsk->firsts = 0;
1570 dsk->type = FAT16;
1571 return CE_GOOD;
1572 }
1573 else
1574 {
1575 #if defined (__C30__) || defined (__PIC32MX__)
1576 if ((ReadByte( dsk->buffer, BSI_FAT32_FSTYPE ) == 'F') && \
1577 (ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 1 ) == 'A') && \
1578 (ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 2 ) == 'T') && \
1579 (ReadByte( dsk->buffer, BSI_FAT32_FSTYPE + 3 ) == '3') && \
1580 (ReadByte( dsk->buffer, BSI_FAT32_BOOTSIG) == 0x29))
1581 #else
1582 if ((BSec->FAT.FAT_32.BootSec_FilSysType[0] == 'F') && \
1583 (BSec->FAT.FAT_32.BootSec_FilSysType[1] == 'A') && \
1584 (BSec->FAT.FAT_32.BootSec_FilSysType[2] == 'T') && \
1585 (BSec->FAT.FAT_32.BootSec_FilSysType[3] == '3') && \
1586 (BSec->FAT.FAT_32.BootSec_BootSig == 0x29))
1587 #endif
1588 {
1589 dsk->firsts = 0;
1590 dsk->type = FAT32;
1591 return CE_GOOD;
1592 }
1593 }
1594 }
1595 // assign it the partition table strucutre
1596 Partition = (PT_MBR)dsk->buffer;
1597
1598 // Ensure its good
1599 if((Partition->Signature0 != FAT_GOOD_SIGN_0) || (Partition->Signature1 != FAT_GOOD_SIGN_1))
1600 {
1601 FSerrno = CE_BAD_PARTITION;
1602 error = CE_BAD_PARTITION;
1603 }
1604 else
1605 {
1606 /* Valid Master Boot Record Loaded */
1607
1608 // Get the 32 bit offset to the first partition
1609 dsk->firsts = Partition->Partition0.PTE_FrstSect;
1610
1611 // check if the partition type is acceptable
1612 type = Partition->Partition0.PTE_FSDesc;
1613
1614 switch (type)
1615 {
1616 case 0x01:
1617 dsk->type = FAT12;
1618 break;
1619
1620 case 0x04:
1621 case 0x06:
1622 case 0x0E:
1623 dsk->type = FAT16;
1624 break;
1625
1626 case 0x0B:
1627 case 0x0C:
1628
1629 #ifdef SUPPORT_FAT32 // If FAT32 supported.
1630 dsk->type = FAT32; // FAT32 is supported too
1631 #else
1632 FSerrno = CE_CARDFAT32;
1633 error = CE_CARDFAT32;
1634 #endif
1635 break;
1636
1637 default:
1638 FSerrno = CE_UNSUPPORTED_FS;
1639 error = CE_UNSUPPORTED_FS;
1640 } // switch
1641 }
1642 }
1643
1644 return(error);
1645 }// -- LoadMBR
1646
1647
1648 /**************************************************************************
1649 Function:
1650 BYTE LoadBootSector (DISK *dsk)
1651 Summary:
1652 Load the boot sector and extract the necessary information
1653 Conditions:
1654 This function should not be called by the user.
1655 Input:
1656 dsk - The disk containing the boot sector
1657 Return Values:
1658 CE_GOOD - Boot sector loaded
1659 CE_BAD_SECTOR_READ - A bad read occured of a sector
1660 CE_NOT_FORMATTED - The disk is of an unsupported format
1661 CE_CARDFAT32 - FAT 32 device not supported
1662 CE_UNSUPPORTED_SECTOR_SIZE - The sector size is not supported
1663 Side Effects:
1664 None
1665 Description:
1666 LoadBootSector will use the function pointed to by the MDD_SectorWrite
1667 function pointer to load the boot sector, whose location was obtained
1668 by a previous call of LoadMBR. If the boot sector is loaded successfully,
1669 partition information will be calcualted from it and copied into the DISK
1670 structure pointed to by 'dsk.'
1671 Remarks:
1672 None
1673 **************************************************************************/
1674
1675
1676 BYTE LoadBootSector(DISK *dsk)
1677 {
1678 DWORD RootDirSectors;
1679 DWORD TotSec,DataSec;
1680 BYTE error = CE_GOOD;
1681 BootSec BSec;
1682 WORD BytesPerSec;
1683 WORD ReservedSectorCount;
1684
1685 #if defined(SUPPORT_FAT32)
1686 BOOL TriedSpecifiedBackupBootSec = FALSE;
1687 BOOL TriedBackupBootSecAtAddress6 = FALSE;
1688 #endif
1689 // Get the Boot sector
1690 if ( MDD_SectorRead( dsk->firsts, dsk->buffer) != TRUE)
1691 {
1692 error = CE_BAD_SECTOR_READ;
1693 }
1694 else
1695 {
1696 BSec = (BootSec)dsk->buffer;
1697
1698 do //test each possible boot sector (FAT32 can have backup boot sectors)
1699 {
1700
1701 //Verify the Boot Sector has a valid signature
1702 if( (BSec->Signature0 != FAT_GOOD_SIGN_0)
1703 || (BSec->Signature1 != FAT_GOOD_SIGN_1)
1704 )
1705 {
1706 error = CE_NOT_FORMATTED;
1707 }
1708 else
1709 {
1710
1711 do //loop just to allow a break to jump out of this section of code
1712 {
1713 #ifdef __18CXX
1714 // Load count of sectors per cluster
1715 dsk->SecPerClus = BSec->FAT.FAT_16.BootSec_SPC;
1716 // Load the sector number of the first FAT sector
1717 dsk->fat = dsk->firsts + BSec->FAT.FAT_16.BootSec_ResrvSec;
1718 // Load the count of FAT tables
1719 dsk->fatcopy = BSec->FAT.FAT_16.BootSec_FATCount;
1720 // Load the size of the FATs
1721 dsk->fatsize = BSec->FAT.FAT_16.BootSec_SPF;
1722 if(dsk->fatsize == 0)
1723 dsk->fatsize = BSec->FAT.FAT_32.BootSec_FATSz32;
1724 // Calculate the location of the root sector (for FAT12/16)
1725 dsk->root = dsk->fat + (DWORD)(dsk->fatcopy * (DWORD)dsk->fatsize);
1726 // Determine the max size of the root (will be 0 for FAT32)
1727 dsk->maxroot = BSec->FAT.FAT_16.BootSec_RootDirEnts;
1728
1729 // Determine the total number of sectors in the partition
1730 if(BSec->FAT.FAT_16.BootSec_TotSec16 != 0)
1731 {
1732 TotSec = BSec->FAT.FAT_16.BootSec_TotSec16;
1733 }
1734 else
1735 {
1736 TotSec = BSec->FAT.FAT_16.BootSec_TotSec32;
1737 }
1738
1739 // Calculate the number of bytes in each sector
1740 BytesPerSec = BSec->FAT.FAT_16.BootSec_BPS;
1741 if( (BytesPerSec == 0) || ((BytesPerSec & 1) == 1) )
1742 {
1743 error = CE_UNSUPPORTED_SECTOR_SIZE;
1744 break; //break out of the do while loop
1745 }
1746
1747 // Calculate the number of sectors in the root (will be 0 for FAT32)
1748 RootDirSectors = ((BSec->FAT.FAT_16.BootSec_RootDirEnts * 32) + (BSec->FAT.FAT_16.BootSec_BPS - 1)) / BSec->FAT.FAT_16.BootSec_BPS;
1749 // Calculate the number of data sectors on the card
1750 DataSec = TotSec - (dsk->root + RootDirSectors);
1751 // Calculate the maximum number of clusters on the card
1752 dsk->maxcls = DataSec / dsk->SecPerClus;
1753
1754 #else // PIC24/30/33
1755
1756 // Read the count of reserved sectors
1757 ReservedSectorCount = ReadWord( dsk->buffer, BSI_RESRVSEC );
1758 // Load the count of sectors per cluster
1759 dsk->SecPerClus = ReadByte( dsk->buffer, BSI_SPC );
1760 // Load the sector number of the first FAT sector
1761 dsk->fat = dsk->firsts + ReservedSectorCount;
1762 // Load the count of FAT tables
1763 dsk->fatcopy = ReadByte( dsk->buffer, BSI_FATCOUNT );
1764 // Load the size of the FATs
1765 dsk->fatsize = ReadWord( dsk->buffer, BSI_SPF );
1766 if(dsk->fatsize == 0)
1767 dsk->fatsize = ReadDWord( dsk->buffer, BSI_FATSZ32 );
1768 // Calculate the location of the root sector (for FAT12/16)
1769 dsk->root = dsk->fat + (DWORD)(dsk->fatcopy * (DWORD)dsk->fatsize);
1770 // Determine the max size of the root (will be 0 for FAT32)
1771 dsk->maxroot = ReadWord( dsk->buffer, BSI_ROOTDIRENTS );
1772
1773 // Determine the total number of sectors in the partition
1774 TotSec = ReadWord( dsk->buffer, BSI_TOTSEC16 );
1775 if( TotSec == 0 )
1776 TotSec = ReadDWord( dsk->buffer, BSI_TOTSEC32 );
1777
1778 // Calculate the number of bytes in each sector
1779 BytesPerSec = ReadWord( dsk->buffer, BSI_BPS );
1780 if( (BytesPerSec == 0) || ((BytesPerSec & 1) == 1) )
1781 {
1782 error = CE_UNSUPPORTED_SECTOR_SIZE;
1783 break;
1784 }
1785
1786 // Calculate the number of sectors in the root (will be 0 for FAT32)
1787 RootDirSectors = ((dsk->maxroot * NUMBER_OF_BYTES_IN_DIR_ENTRY) + (BytesPerSec - 1)) / BytesPerSec;
1788 // Calculate the number of data sectors on the card
1789 DataSec = TotSec - (ReservedSectorCount + (dsk->fatcopy * dsk->fatsize ) + RootDirSectors);
1790 // Calculate the maximum number of clusters on the card
1791 dsk->maxcls = DataSec / dsk->SecPerClus;
1792
1793 #endif
1794
1795 // Determine the file system type based on the number of clusters used
1796 if(dsk->maxcls < 4085)
1797 {
1798 dsk->type = FAT12;
1799 }
1800 else
1801 {
1802 if(dsk->maxcls < 65525)
1803 {
1804 dsk->type = FAT16;
1805 }
1806 else
1807 {
1808 #ifdef SUPPORT_FAT32
1809 dsk->type = FAT32;
1810 #else
1811 error = CE_CARDFAT32;
1812 #endif
1813 }
1814 }
1815
1816 #ifdef SUPPORT_FAT32
1817 if (dsk->type == FAT32)
1818 {
1819 #ifdef __18CXX
1820 FatRootDirClusterValue = BSec->FAT.FAT_32.BootSec_RootClus;
1821 #else
1822 FatRootDirClusterValue = ReadDWord( dsk->buffer, BSI_ROOTCLUS );
1823 #endif
1824 dsk->data = dsk->root + RootDirSectors;
1825 }
1826 else
1827 #endif
1828 {
1829 FatRootDirClusterValue = 0;
1830 dsk->data = dsk->root + ( dsk->maxroot >> 4);
1831 }
1832
1833 #ifdef __18CXX
1834 if(BSec->FAT.FAT_16.BootSec_BPS > MEDIA_SECTOR_SIZE)
1835 #else
1836 if(BytesPerSec > MEDIA_SECTOR_SIZE)
1837 #endif
1838 {
1839 error = CE_UNSUPPORTED_SECTOR_SIZE;
1840 }
1841
1842 }while(0); // do/while loop designed to allow to break out if
1843 // there is an error detected without returning
1844 // from the function.
1845
1846 }
1847
1848 #if defined(SUPPORT_FAT32)
1849 if ((dsk->type == FAT32) || ((error != CE_GOOD) && ((BSec->FAT.FAT_32.BootSec_BootSig == 0x29) || (BSec->FAT.FAT_32.BootSec_BootSig == 0x28))))
1850 {
1851 //Check for possible errors in the formatting
1852 if( (BSec->FAT.FAT_32.BootSec_TotSec16 != 0)
1853 || (BSec->FAT.FAT_32.BootSec_Reserved[0] != 0)
1854 || (BSec->FAT.FAT_32.BootSec_Reserved[1] != 0)
1855 || (BSec->FAT.FAT_32.BootSec_Reserved[2] != 0)
1856 || (BSec->FAT.FAT_32.BootSec_Reserved[3] != 0)
1857 || (BSec->FAT.FAT_32.BootSec_Reserved[4] != 0)
1858 || (BSec->FAT.FAT_32.BootSec_Reserved[5] != 0)
1859 || (BSec->FAT.FAT_32.BootSec_Reserved[6] != 0)
1860 || (BSec->FAT.FAT_32.BootSec_Reserved[7] != 0)
1861 || (BSec->FAT.FAT_32.BootSec_Reserved[8] != 0)
1862 || (BSec->FAT.FAT_32.BootSec_Reserved[9] != 0)
1863 || (BSec->FAT.FAT_32.BootSec_Reserved[10] != 0)
1864 || (BSec->FAT.FAT_32.BootSec_Reserved[11] != 0)
1865 || ((BSec->FAT.FAT_32.BootSec_BootSig != 0x29) && (BSec->FAT.FAT_32.BootSec_BootSig != 0x28))
1866 )
1867 {
1868 error = CE_NOT_FORMATTED;
1869 }
1870
1871 //If there were formatting errors then in FAT32 we can try to use
1872 // the backup boot sector
1873 if((error != CE_GOOD) && (TriedSpecifiedBackupBootSec == FALSE))
1874 {
1875 TriedSpecifiedBackupBootSec = TRUE;
1876
1877 if ( MDD_SectorRead( dsk->firsts + BSec->FAT.FAT_32.BootSec_BkBootSec, dsk->buffer) != TRUE)
1878 {
1879 FSerrno = CE_BAD_SECTOR_READ;
1880 return CE_BAD_SECTOR_READ;
1881 }
1882 else
1883 {
1884 error = CE_GOOD;
1885 continue;
1886 }
1887 }
1888
1889 if((error != CE_GOOD) && (TriedBackupBootSecAtAddress6 == FALSE))
1890 {
1891 TriedBackupBootSecAtAddress6 = TRUE;
1892
1893 //Here we are using the magic number 6 because the FAT32 specification
1894 // recommends that "No value other than 6 is recommended." We've
1895 // already tried using the value specified in the BPB_BkBootSec
1896 // field and it must have failed
1897 if ( MDD_SectorRead( dsk->firsts + 6, dsk->buffer) != TRUE)
1898 {
1899 FSerrno = CE_BAD_SECTOR_READ;
1900 return CE_BAD_SECTOR_READ;
1901 }
1902 else
1903 {
1904 error = CE_GOOD;
1905 continue;
1906 }
1907 }
1908
1909 } //type == FAT32
1910 #endif //SUPPORT_FAT32
1911 break;
1912 }
1913 while(1);
1914 }
1915
1916 if(error != CE_GOOD)
1917 {
1918 FSerrno = error;
1919 }
1920
1921 return(error);
1922 }
1923
1924
1925
1926 /*************************************************************************
1927 Function:
1928 DWORD GetFullClusterNumber (DIRENTRY entry)
1929 Summary:
1930 Gets the cluster number from a directory entry
1931 Conditions:
1932 This function should not be called by the user.
1933 Input:
1934 entry - The cached directory entry to get the cluster number from
1935 Returns:
1936 The cluster value from the passed directory entry
1937 Side Effects:
1938 None.
1939 Description:
1940 This function will load both the high and low 16-bit first cluster
1941 values of a file from a directory entry and copy them into a 32-bit
1942 cluster number variable, which will be returned.
1943 Remarks:
1944 None
1945 *************************************************************************/
1946
1947 DWORD GetFullClusterNumber(DIRENTRY entry)
1948 {
1949
1950 DWORD TempFullClusterCalc = 0;
1951
1952 #ifndef SUPPORT_FAT32 // If FAT32 Not supported.
1953 entry->DIR_FstClusHI = 0; // If FAT32 is not supported then Higher Word of the address is "0"
1954 #endif
1955
1956 // Get the cluster
1957 TempFullClusterCalc = (entry->DIR_FstClusHI);
1958 TempFullClusterCalc = TempFullClusterCalc << 16;
1959 TempFullClusterCalc |= entry->DIR_FstClusLO;
1960
1961 return TempFullClusterCalc;
1962 }
1963
1964
1965 #ifdef ALLOW_FORMATS
1966 #ifdef ALLOW_WRITES
1967
1968
1969 /*********************************************************************************
1970 Function:
1971 int FSCreateMBR (unsigned long firstSector, unsigned long numSectors)
1972 Summary:
1973 Creates a master boot record
1974 Conditions:
1975 The I/O pins for the device have been initialized by the InitIO function.
1976 Input:
1977 firstSector - The first sector of the partition on the device (cannot
1978 be 0; that's the MBR)
1979 numSectors - The number of sectors available in memory (including the
1980 MBR)
1981 Return Values:
1982 0 - MBR was created successfully
1983 EOF - MBR could not be created
1984 Side Effects:
1985 None
1986 Description:
1987 This function can be used to create a master boot record for a device. Note
1988 that this function should not be used on a device that is already formatted
1989 with a master boot record (i.e. most SD cards, CF cards, USB keys). This
1990 function will fill the global data buffer with appropriate partition information
1991 for a FAT partition with a type determined by the number of sectors available
1992 to the partition. It will then write the MBR information to the first sector
1993 on the device. This function should be followed by a call to FSformat, which
1994 will create a boot sector, root dir, and FAT appropriate the the information
1995 contained in the new master boot record. Note that FSformat only supports
1996 FAT12 and FAT16 formatting at this time, and so cannot be used to format a
1997 device with more than 0x3FFD5F sectors.
1998 Remarks:
1999 This function can damage the device being used, and should not be called
2000 unless the user is sure about the size of the device and the first sector value.
2001 *********************************************************************************/
2002
2003 int FSCreateMBR (unsigned long firstSector, unsigned long numSectors)
2004 {
2005 PT_MBR Partition;
2006 DWORD CyHdSc = 0x00000000;
2007 DWORD tempSector;
2008
2009 if ((firstSector == 0) || (numSectors <= 1))
2010 return EOF;
2011
2012 if (firstSector > (numSectors - 1))
2013 return EOF;
2014
2015 if (gNeedDataWrite)
2016 if (flushData())
2017 return EOF;
2018
2019 memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE);
2020
2021 Partition = (PT_MBR) gDataBuffer;
2022
2023 // Set Cylinder-head-sector address of the first sector
2024 tempSector = firstSector;
2025 CyHdSc = (tempSector / (unsigned int)16065 ) << 14;
2026 tempSector %= 16065;
2027 CyHdSc |= (tempSector / 63) << 6;
2028 tempSector %= 63;
2029 CyHdSc |= tempSector + 1;
2030 gDataBuffer[447] = (BYTE)((CyHdSc >> 16) & 0xFF);
2031 gDataBuffer[448] = (BYTE)((CyHdSc >> 8) & 0xFF);
2032 gDataBuffer[449] = (BYTE)((CyHdSc) & 0xFF);
2033
2034 // Set the count of sectors
2035 Partition->Partition0.PTE_NumSect = numSectors - firstSector;
2036
2037 // Set the partition type
2038 // We only support creating FAT12 and FAT16 MBRs at this time
2039 if (Partition->Partition0.PTE_NumSect < 0x1039)
2040 {
2041 // FAT12
2042 Partition->Partition0.PTE_FSDesc = 0x01;
2043 }
2044 else if (Partition->Partition0.PTE_NumSect <= 0x3FFD5F)
2045 {
2046 // FAT16
2047 Partition->Partition0.PTE_FSDesc = 0x06;
2048 }
2049 else
2050 return EOF;
2051
2052 // Set the LBA of the first sector
2053 Partition->Partition0.PTE_FrstSect = firstSector;
2054
2055 // Set the Cylinder-head-sector address of the last sector
2056 tempSector = firstSector + numSectors - 1;
2057 CyHdSc = (tempSector / (unsigned int)16065 ) << 14;
2058 tempSector %= 16065;
2059 CyHdSc |= (tempSector / 63) << 6;
2060 tempSector %= 63;
2061 CyHdSc |= tempSector + 1;
2062 gDataBuffer[451] = (BYTE)((CyHdSc >> 16) & 0xFF);
2063 gDataBuffer[452] = (BYTE)((CyHdSc >> 8) & 0xFF);
2064 gDataBuffer[453] = (BYTE)((CyHdSc) & 0xFF);
2065
2066 // Set the boot descriptor. This will be 0, since we won't
2067 // be booting anything from our device probably
2068 Partition->Partition0.PTE_BootDes = 0x00;
2069
2070 // Set the signature codes
2071 Partition->Signature0 = 0x55;
2072 Partition->Signature1 = 0xAA;
2073
2074 if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) != TRUE)
2075 return EOF;
2076 else
2077 return 0;
2078
2079 }
2080
2081
2082 /*******************************************************************
2083 Function:
2084 int FSformat (char mode, long int serialNumber, char * volumeID)
2085 Summary:
2086 Formats a device
2087 Conditions:
2088 The device must possess a valid master boot record.
2089 Input:
2090 mode - - 0 - Just erase the FAT and root
2091 - 1 - Create a new boot sector
2092 serialNumber - Serial number to write to the card
2093 volumeID - Name of the card
2094 Return Values:
2095 0 - Format was successful
2096 EOF - Format was unsuccessful
2097 Side Effects:
2098 The FSerrno variable will be changed.
2099 Description:
2100 The FSformat function can be used to create a new boot sector
2101 on a device, based on the information in the master boot record.
2102 This function will first initialize the I/O pins and the device,
2103 and then attempts to read the master boot record. If the MBR
2104 cannot be loaded successfully, the function will fail. Next, if
2105 the 'mode' argument is specified as '0' the existing boot sector
2106 information will be loaded. If the 'mode' argument is '1' an
2107 entirely new boot sector will be constructed using the disk
2108 values from the master boot record. Once the boot sector has
2109 been successfully loaded/created, the locations of the FAT and
2110 root will be loaded from it, and they will be completely
2111 erased. If the user has specified a volumeID parameter, a
2112 VOLUME attribute entry will be created in the root directory
2113 to name the device.
2114
2115 FAT12, FAT16 and FAT32 formatting are supported.
2116
2117 Based on the number of sectors, the format function automatically
2118 compute the smallest possible value for the cluster size in order to
2119 accommodate the physical size of the media. In this case, if a media
2120 with a big capacity is formatted, the format function may take a very
2121 long time to write all the FAT tables.
2122
2123 Therefore, the FORMAT_SECTORS_PER_CLUSTER macro may be used to
2124 specify the exact cluster size (in multiples of sector size). This
2125 macro can be defined in FSconfig.h
2126
2127 Remarks:
2128 Only devices with a sector size of 512 bytes are supported by the
2129 format function
2130 *******************************************************************/
2131
2132 int FSformat (char mode, long int serialNumber, char * volumeID)
2133 {
2134 PT_MBR masterBootRecord;
2135 DWORD secCount, DataClusters, RootDirSectors;
2136 BootSec BSec;
2137 DISK d;
2138 DISK * disk = &d;
2139 WORD j;
2140 DWORD fatsize, test;
2141 DWORD Index;
2142 MEDIA_INFORMATION * mediaInfo;
2143 #ifdef __18CXX
2144 // This is here because of a C18 compiler feature
2145 BYTE * dataBufferPointer = gDataBuffer;
2146 #endif
2147
2148 FSerrno = CE_GOOD;
2149
2150 gBufferZeroed = FALSE;
2151 gNeedFATWrite = FALSE;
2152 gLastFATSectorRead = 0xFFFFFFFF;
2153 gLastDataSectorRead = 0xFFFFFFFF;
2154
2155 disk->buffer = gDataBuffer;
2156
2157 MDD_InitIO();
2158
2159 mediaInfo = MDD_MediaInitialize();
2160 if (mediaInfo->errorCode != MEDIA_NO_ERROR)
2161 {
2162 FSerrno = CE_INIT_ERROR;
2163 return EOF;
2164 }
2165
2166 if (MDD_SectorRead (0x00, gDataBuffer) == FALSE)
2167 {
2168 FSerrno = CE_BADCACHEREAD;
2169 return EOF;
2170 }
2171
2172 // Check if the card has no MBR
2173 BSec = (BootSec) disk->buffer;
2174 if((BSec->Signature0 == FAT_GOOD_SIGN_0) && (BSec->Signature1 == FAT_GOOD_SIGN_1))
2175 {
2176 // Technically, the OEM name is not for indication
2177 // The alternative is to read the CIS from attribute
2178 // memory. See the PCMCIA metaformat for more details
2179 #if defined (__C30__) || defined (__PIC32MX__)
2180 if ((ReadByte( disk->buffer, BSI_FSTYPE ) == 'F') && \
2181 (ReadByte( disk->buffer, BSI_FSTYPE + 1 ) == 'A') && \
2182 (ReadByte( disk->buffer, BSI_FSTYPE + 2 ) == 'T') && \
2183 (ReadByte( disk->buffer, BSI_FSTYPE + 3 ) == '1') && \
2184 (ReadByte( disk->buffer, BSI_BOOTSIG) == 0x29))
2185 #else
2186 if ((BSec->FAT.FAT_16.BootSec_FSType[0] == 'F') && \
2187 (BSec->FAT.FAT_16.BootSec_FSType[1] == 'A') && \
2188 (BSec->FAT.FAT_16.BootSec_FSType[2] == 'T') && \
2189 (BSec->FAT.FAT_16.BootSec_FSType[3] == '1') && \
2190 (BSec->FAT.FAT_16.BootSec_BootSig == 0x29))
2191 #endif
2192 {
2193 /* Mark that we do not have a MBR;
2194 this is not actualy used - is here only to remove a compilation warning */
2195 masterBootRecord = (PT_MBR) NULL;
2196 switch (mode)
2197 {
2198 case 1:
2199 // not enough info to construct our own boot sector
2200 FSerrno = CE_INVALID_ARGUMENT;
2201 return EOF;
2202 case 0:
2203 // We have to determine the operating system, and the
2204 // locations and sizes of the root dir and FAT, and the
2205 // count of FATs
2206 disk->firsts = 0;
2207 if (LoadBootSector (disk) != CE_GOOD)
2208 {
2209 FSerrno = CE_BADCACHEREAD;
2210 return EOF;
2211 }
2212 default:
2213 break;
2214 }
2215 }
2216 else
2217 {
2218 masterBootRecord = (PT_MBR) &gDataBuffer;
2219 disk->firsts = masterBootRecord->Partition0.PTE_FrstSect;
2220 }
2221 }
2222 else
2223 {
2224 /* If the signature is not correct, this is neither a MBR, nor a VBR */
2225 FSerrno = CE_BAD_PARTITION;
2226 return EOF;
2227 }
2228
2229 switch (mode)
2230 {
2231 // True: Rewrite the whole boot sector
2232 case 1:
2233 secCount = masterBootRecord->Partition0.PTE_NumSect;
2234
2235 if (secCount < 0x1039)
2236 {
2237 disk->type = FAT12;
2238 // Format to FAT12 only if there are too few sectors to format
2239 // as FAT16
2240 masterBootRecord->Partition0.PTE_FSDesc = 0x01;
2241 if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE)
2242 {
2243 FSerrno = CE_WRITE_ERROR;
2244 return EOF;
2245 }
2246
2247 if (secCount >= 0x1028)
2248 {
2249 // More than 0x18 sectors for FATs, 0x20 for root dir,
2250 // 0x8 reserved, and 0xFED for data
2251 // So double the number of sectors in a cluster to reduce
2252 // the number of data clusters used
2253 disk->SecPerClus = 2;
2254 }
2255 else
2256 {
2257 // One sector per cluster
2258 disk->SecPerClus = 1;
2259 }
2260
2261 // Prepare a boot sector
2262 memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE);
2263
2264 // Last digit of file system name (FAT12 )
2265 gDataBuffer[58] = '2';
2266
2267 // Calculate the size of the FAT
2268 fatsize = (secCount - 0x21 + (2*disk->SecPerClus));
2269 test = (341 * disk->SecPerClus) + 2;
2270 fatsize = (fatsize + (test-1)) / test;
2271
2272 disk->fatcopy = 0x02;
2273 disk->maxroot = 0x200;
2274
2275 disk->fatsize = fatsize;
2276
2277 }
2278 else if (secCount <= 0x3FFD5F)
2279 {
2280 disk->type = FAT16;
2281 // Format to FAT16
2282 masterBootRecord->Partition0.PTE_FSDesc = 0x06;
2283 if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE)
2284 {
2285 FSerrno = CE_WRITE_ERROR;
2286 return EOF;
2287 }
2288
2289 DataClusters = secCount - 0x218;
2290 // Figure out how many sectors per cluster we need
2291 disk->SecPerClus = 1;
2292 while (DataClusters > 0xFFED)
2293 {
2294 disk->SecPerClus *= 2;
2295 DataClusters /= 2;
2296 }
2297 // This shouldnt happen
2298 if (disk->SecPerClus > 128)
2299 {
2300 FSerrno = CE_BAD_PARTITION;
2301 return EOF;
2302 }
2303
2304 // Prepare a boot sector
2305 memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE);
2306
2307 // Last digit of file system name (FAT16 )
2308 gDataBuffer[58] = '6';
2309
2310 // Calculate the size of the FAT
2311 fatsize = (secCount - 0x21 + (2*disk->SecPerClus));
2312 test = (256 * disk->SecPerClus) + 2;
2313 fatsize = (fatsize + (test-1)) / test;
2314
2315 disk->fatcopy = 0x02;
2316 disk->maxroot = 0x200;
2317
2318 disk->fatsize = fatsize;
2319 }
2320 else
2321 {
2322 disk->type = FAT32;
2323 // Format to FAT32
2324 masterBootRecord->Partition0.PTE_FSDesc = 0x0B;
2325 if (MDD_SectorWrite (0x00, gDataBuffer, TRUE) == FALSE)
2326 {
2327 FSerrno = CE_WRITE_ERROR;
2328 return EOF;
2329 }
2330
2331 #ifdef FORMAT_SECTORS_PER_CLUSTER
2332 disk->SecPerClus = FORMAT_SECTORS_PER_CLUSTER;
2333 DataClusters = secCount / disk->SecPerClus;
2334
2335 /* FAT32: 65526 < Number of clusters < 4177918 */
2336 if ((DataClusters <= 65526) || (DataClusters >= 4177918))
2337 {
2338 FSerrno = CE_BAD_PARTITION;
2339 return EOF;
2340 }
2341 #else
2342 /* FAT32: 65526 < Number of clusters < 4177918 */
2343 DataClusters = secCount;
2344 // Figure out how many sectors per cluster we need
2345 disk->SecPerClus = 1;
2346 while (DataClusters > 0x3FBFFE)
2347 {
2348 disk->SecPerClus *= 2;
2349 DataClusters /= 2;
2350 }
2351 #endif
2352 // Check the cluster size: FAT32 supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K
2353 if (disk->SecPerClus > 128)
2354 {
2355 FSerrno = CE_BAD_PARTITION;
2356 return EOF;
2357 }
2358
2359 // Prepare a boot sector
2360 memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE);
2361
2362 // Calculate the size of the FAT
2363 fatsize = (secCount - 0x20);
2364 test = (128 * disk->SecPerClus) + 1;
2365 fatsize = (fatsize + (test-1)) / test;
2366
2367 disk->fatcopy = 0x02;
2368 disk->maxroot = 0x200;
2369
2370 disk->fatsize = fatsize;
2371 }
2372
2373 // Non-file system specific values
2374 gDataBuffer[0] = 0xEB; //Jump instruction
2375 gDataBuffer[1] = 0x3C;
2376 gDataBuffer[2] = 0x90;
2377 gDataBuffer[3] = 'M'; //OEM Name "MCHP FAT"
2378 gDataBuffer[4] = 'C';
2379 gDataBuffer[5] = 'H';
2380 gDataBuffer[6] = 'P';
2381 gDataBuffer[7] = ' ';
2382 gDataBuffer[8] = 'F';
2383 gDataBuffer[9] = 'A';
2384 gDataBuffer[10] = 'T';
2385
2386 gDataBuffer[11] = 0x00; //Sector size
2387 gDataBuffer[12] = 0x02;
2388
2389 gDataBuffer[13] = disk->SecPerClus; //Sectors per cluster
2390
2391 if ((disk->type == FAT12) || (disk->type == FAT16))
2392 {
2393 gDataBuffer[14] = 0x08; //Reserved sector count
2394 gDataBuffer[15] = 0x00;
2395 disk->fat = 0x08 + disk->firsts;
2396
2397 gDataBuffer[16] = 0x02; //number of FATs
2398
2399 gDataBuffer[17] = 0x00; //Max number of root directory entries - 512 files allowed
2400 gDataBuffer[18] = 0x02;
2401
2402 gDataBuffer[19] = 0x00; //total sectors
2403 gDataBuffer[20] = 0x00;
2404
2405 gDataBuffer[21] = 0xF8; //Media Descriptor
2406
2407 gDataBuffer[22] = fatsize & 0xFF; //Sectors per FAT
2408 gDataBuffer[23] = (fatsize >> 8) & 0xFF;
2409
2410 gDataBuffer[24] = 0x3F; //Sectors per track
2411 gDataBuffer[25] = 0x00;
2412
2413 gDataBuffer[26] = 0xFF; //Number of heads
2414 gDataBuffer[27] = 0x00;
2415
2416 // Hidden sectors = sectors between the MBR and the boot sector
2417 gDataBuffer[28] = (BYTE)(disk->firsts & 0xFF);
2418 gDataBuffer[29] = (BYTE)((disk->firsts / 0x100) & 0xFF);
2419 gDataBuffer[30] = (BYTE)((disk->firsts / 0x10000) & 0xFF);
2420 gDataBuffer[31] = (BYTE)((disk->firsts / 0x1000000) & 0xFF);
2421
2422 // Total Sectors = same as sectors in the partition from MBR
2423 gDataBuffer[32] = (BYTE)(secCount & 0xFF);
2424 gDataBuffer[33] = (BYTE)((secCount / 0x100) & 0xFF);
2425 gDataBuffer[34] = (BYTE)((secCount / 0x10000) & 0xFF);
2426 gDataBuffer[35] = (BYTE)((secCount / 0x1000000) & 0xFF);
2427
2428 gDataBuffer[36] = 0x00; // Physical drive number
2429
2430 gDataBuffer[37] = 0x00; // Reserved (current head)
2431
2432 gDataBuffer[38] = 0x29; // Signature code
2433
2434 gDataBuffer[39] = (BYTE)(serialNumber & 0xFF);
2435 gDataBuffer[40] = (BYTE)((serialNumber / 0x100) & 0xFF);
2436 gDataBuffer[41] = (BYTE)((serialNumber / 0x10000) & 0xFF);
2437 gDataBuffer[42] = (BYTE)((serialNumber / 0x1000000) & 0xFF);
2438
2439 // Volume ID
2440 if (volumeID != NULL)
2441 {
2442 for (Index = 0; (*(volumeID + Index) != 0) && (Index < 11); Index++)
2443 {
2444 gDataBuffer[Index + 43] = *(volumeID + Index);
2445 }
2446 while (Index < 11)
2447 {
2448 gDataBuffer[43 + Index++] = 0x20;
2449 }
2450 }
2451 else
2452 {
2453 for (Index = 0; Index < 11; Index++)
2454 {
2455 gDataBuffer[Index+43] = 0;
2456 }
2457 }
2458
2459 gDataBuffer[54] = 'F';
2460 gDataBuffer[55] = 'A';
2461 gDataBuffer[56] = 'T';
2462 gDataBuffer[57] = '1';
2463 gDataBuffer[59] = ' ';
2464 gDataBuffer[60] = ' ';
2465 gDataBuffer[61] = ' ';
2466
2467 }
2468 else //FAT32
2469 {
2470 gDataBuffer[14] = 0x20; //Reserved sector count
2471 gDataBuffer[15] = 0x00;
2472 disk->fat = 0x20 + disk->firsts;
2473
2474 gDataBuffer[16] = 0x02; //number of FATs
2475
2476 gDataBuffer[17] = 0x00; //Max number of root directory entries - 512 files allowed
2477 gDataBuffer[18] = 0x00;
2478
2479 gDataBuffer[19] = 0x00; //total sectors
2480 gDataBuffer[20] = 0x00;
2481
2482 gDataBuffer[21] = 0xF8; //Media Descriptor
2483
2484 gDataBuffer[22] = 0x00; //Sectors per FAT
2485 gDataBuffer[23] = 0x00;
2486
2487 gDataBuffer[24] = 0x3F; //Sectors per track
2488 gDataBuffer[25] = 0x00;
2489
2490 gDataBuffer[26] = 0xFF; //Number of heads
2491 gDataBuffer[27] = 0x00;
2492
2493 // Hidden sectors = sectors between the MBR and the boot sector
2494 gDataBuffer[28] = (BYTE)(disk->firsts & 0xFF);
2495 gDataBuffer[29] = (BYTE)((disk->firsts / 0x100) & 0xFF);
2496 gDataBuffer[30] = (BYTE)((disk->firsts / 0x10000) & 0xFF);
2497 gDataBuffer[31] = (BYTE)((disk->firsts / 0x1000000) & 0xFF);
2498
2499 // Total Sectors = same as sectors in the partition from MBR
2500 gDataBuffer[32] = (BYTE)(secCount & 0xFF);
2501 gDataBuffer[33] = (BYTE)((secCount / 0x100) & 0xFF);
2502 gDataBuffer[34] = (BYTE)((secCount / 0x10000) & 0xFF);
2503 gDataBuffer[35] = (BYTE)((secCount / 0x1000000) & 0xFF);
2504
2505 gDataBuffer[36] = fatsize & 0xFF; //Sectors per FAT
2506 gDataBuffer[37] = (fatsize >> 8) & 0xFF;
2507 gDataBuffer[38] = (fatsize >> 16) & 0xFF;
2508 gDataBuffer[39] = (fatsize >> 24) & 0xFF;
2509
2510 gDataBuffer[40] = 0x00; //Active FAT
2511 gDataBuffer[41] = 0x00;
2512
2513 gDataBuffer[42] = 0x00; //File System version
2514 gDataBuffer[43] = 0x00;
2515
2516 gDataBuffer[44] = 0x02; //First cluster of the root directory
2517 gDataBuffer[45] = 0x00;
2518 gDataBuffer[46] = 0x00;
2519 gDataBuffer[47] = 0x00;
2520
2521 gDataBuffer[48] = 0x01; //FSInfo
2522 gDataBuffer[49] = 0x00;
2523
2524 gDataBuffer[50] = 0x00; //Backup Boot Sector
2525 gDataBuffer[51] = 0x00;
2526
2527 gDataBuffer[52] = 0x00; //Reserved for future expansion
2528 gDataBuffer[53] = 0x00;
2529 gDataBuffer[54] = 0x00;
2530 gDataBuffer[55] = 0x00;
2531 gDataBuffer[56] = 0x00;
2532 gDataBuffer[57] = 0x00;
2533 gDataBuffer[58] = 0x00;
2534 gDataBuffer[59] = 0x00;
2535 gDataBuffer[60] = 0x00;
2536 gDataBuffer[61] = 0x00;
2537 gDataBuffer[62] = 0x00;
2538 gDataBuffer[63] = 0x00;
2539
2540 gDataBuffer[64] = 0x00; // Physical drive number
2541
2542 gDataBuffer[65] = 0x00; // Reserved (current head)
2543
2544 gDataBuffer[66] = 0x29; // Signature code
2545
2546 gDataBuffer[67] = (BYTE)(serialNumber & 0xFF);
2547 gDataBuffer[68] = (BYTE)((serialNumber / 0x100) & 0xFF);
2548 gDataBuffer[69] = (BYTE)((serialNumber / 0x10000) & 0xFF);
2549 gDataBuffer[70] = (BYTE)((serialNumber / 0x1000000) & 0xFF);
2550
2551 // Volume ID
2552 if (volumeID != NULL)
2553 {
2554 for (Index = 0; (*(volumeID + Index) != 0) && (Index < 11); Index++)
2555 {
2556 gDataBuffer[Index + 71] = *(volumeID + Index);
2557 }
2558 while (Index < 11)
2559 {
2560 gDataBuffer[71 + Index++] = 0x20;
2561 }
2562 }
2563 else
2564 {
2565 for (Index = 0; Index < 11; Index++)
2566 {
2567 gDataBuffer[Index+71] = 0;
2568 }
2569 }
2570
2571 gDataBuffer[82] = 'F';
2572 gDataBuffer[83] = 'A';
2573 gDataBuffer[84] = 'T';
2574 gDataBuffer[85] = '3';
2575 gDataBuffer[86] = '2';
2576 gDataBuffer[87] = ' ';
2577 gDataBuffer[88] = ' ';
2578 gDataBuffer[89] = ' ';
2579
2580
2581 }
2582
2583 #ifdef __18CXX
2584 // C18 can't reference a value greater than 256
2585 // using an array name pointer
2586 *(dataBufferPointer + 510) = 0x55;
2587 *(dataBufferPointer + 511) = 0xAA;
2588 #else
2589 gDataBuffer[510] = 0x55;
2590 gDataBuffer[511] = 0xAA;
2591 #endif
2592
2593 disk->root = disk->fat + (disk->fatcopy * disk->fatsize);
2594
2595 if (MDD_SectorWrite (disk->firsts, gDataBuffer, FALSE) == FALSE)
2596 {
2597 FSerrno = CE_WRITE_ERROR;
2598 return EOF;
2599 }
2600
2601 break;
2602 case 0:
2603 if (LoadBootSector (disk) != CE_GOOD)
2604 {
2605 FSerrno = CE_BADCACHEREAD;
2606 return EOF;
2607 }
2608 break;
2609 default:
2610 FSerrno = CE_INVALID_ARGUMENT;
2611 return EOF;
2612 }
2613
2614 // Erase the FAT
2615 memset (gDataBuffer, 0x00, MEDIA_SECTOR_SIZE);
2616
2617 if (disk->type == FAT32)
2618 {
2619 gDataBuffer[0] = 0xF8; //BPB_Media byte value in its low 8 bits, and all other bits are set to 1
2620 gDataBuffer[1] = 0xFF;
2621 gDataBuffer[2] = 0xFF;
2622 gDataBuffer[3] = 0xFF;
2623
2624 gDataBuffer[4] = 0x00; //Disk is clean and no read/write errors were encountered
2625 gDataBuffer[5] = 0x00;
2626 gDataBuffer[6] = 0x00;
2627 gDataBuffer[7] = 0x0C;
2628
2629 gDataBuffer[8] = 0xFF; //Root Directory EOF
2630 gDataBuffer[9] = 0xFF;
2631 gDataBuffer[10] = 0xFF;
2632 gDataBuffer[11] = 0xFF;
2633
2634 for (j = disk->fatcopy - 1; j != 0xFFFF; j--)
2635 {
2636 if (MDD_SectorWrite (disk->fat + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE)
2637 return EOF;
2638 }
2639
2640 memset (gDataBuffer, 0x00, 12);
2641
2642 for (Index = disk->fat + 1; Index < (disk->fat + disk->fatsize); Index++)
2643 {
2644 for (j = disk->fatcopy - 1; j != 0xFFFF; j--)
2645 {
2646 if (MDD_SectorWrite (Index + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE)
2647 return EOF;
2648 }
2649 }
2650
2651 // Erase the root directory
2652 for (Index = 1; Index < disk->SecPerClus; Index++)
2653 {
2654 if (MDD_SectorWrite (disk->root + Index, gDataBuffer, FALSE) == FALSE)
2655 return EOF;
2656 }
2657
2658 if (volumeID != NULL)
2659 {
2660 // Create a drive name entry in the root dir
2661 Index = 0;
2662 while ((*(volumeID + Index) != 0) && (Index < 11))
2663 {
2664 gDataBuffer[Index] = *(volumeID + Index);
2665 Index++;
2666 }
2667 while (Index < 11)
2668 {
2669 gDataBuffer[Index++] = ' ';
2670 }
2671 gDataBuffer[11] = 0x08;
2672 gDataBuffer[17] = 0x11;
2673 gDataBuffer[19] = 0x11;
2674 gDataBuffer[23] = 0x11;
2675
2676 if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE)
2677 return EOF;
2678 }
2679 else
2680 {
2681 if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE)
2682 return EOF;
2683 }
2684
2685 return 0;
2686 }
2687 else
2688 {
2689 gDataBuffer[0] = 0xF8;
2690 gDataBuffer[1] = 0xFF;
2691 gDataBuffer[2] = 0xFF;
2692 if (disk->type == FAT16)
2693 gDataBuffer[3] = 0xFF;
2694
2695 for (j = disk->fatcopy - 1; j != 0xFFFF; j--)
2696 {
2697 if (MDD_SectorWrite (disk->fat + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE)
2698 return EOF;
2699 }
2700
2701 memset (gDataBuffer, 0x00, 4);
2702
2703 for (Index = disk->fat + 1; Index < (disk->fat + disk->fatsize); Index++)
2704 {
2705 for (j = disk->fatcopy - 1; j != 0xFFFF; j--)
2706 {
2707 if (MDD_SectorWrite (Index + (j * disk->fatsize), gDataBuffer, FALSE) == FALSE)
2708 return EOF;
2709 }
2710 }
2711
2712 // Erase the root directory
2713 RootDirSectors = ((disk->maxroot * 32) + (disk->sectorSize - 1)) / disk->sectorSize;
2714
2715 for (Index = 1; Index < RootDirSectors; Index++)
2716 {
2717 if (MDD_SectorWrite (disk->root + Index, gDataBuffer, FALSE) == FALSE)
2718 return EOF;
2719 }
2720
2721 if (volumeID != NULL)
2722 {
2723 // Create a drive name entry in the root dir
2724 Index = 0;
2725 while ((*(volumeID + Index) != 0) && (Index < 11))
2726 {
2727 gDataBuffer[Index] = *(volumeID + Index);
2728 Index++;
2729 }
2730 while (Index < 11)
2731 {
2732 gDataBuffer[Index++] = ' ';
2733 }
2734 gDataBuffer[11] = 0x08;
2735 gDataBuffer[17] = 0x11;
2736 gDataBuffer[19] = 0x11;
2737 gDataBuffer[23] = 0x11;
2738
2739 if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE)
2740 return EOF;
2741 }
2742 else
2743 {
2744 if (MDD_SectorWrite (disk->root, gDataBuffer, FALSE) == FALSE)
2745 return EOF;
2746 }
2747
2748 return 0;
2749 }
2750 }
2751 #endif
2752 #endif
2753
2754
2755 /*******************************************************
2756 Function:
2757 BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry)
2758 Summary:
2759 Write dir entry info into a specified entry
2760 Conditions:
2761 This function should not be called by the user.
2762 Input:
2763 fo - \File structure
2764 curEntry - Write destination
2765 Return Values:
2766 TRUE - Operation successful
2767 FALSE - Operation failed
2768 Side Effects:
2769 None
2770 Description:
2771 This function will calculate the sector of the
2772 directory (whose base sector is pointed to by the
2773 dirccls value in the FSFILE object 'fo') that contains
2774 a directory entry whose offset is indicated by the
2775 curEntry parameter. It will then write the data
2776 in the global data buffer (which should already
2777 contain the entries for that sector) to the device.
2778 Remarks:
2779 None
2780 *******************************************************/
2781
2782 #ifdef ALLOW_WRITES
2783 BYTE Write_File_Entry( FILEOBJ fo, WORD * curEntry)
2784 {
2785 DISK *dsk;
2786 BYTE status;
2787 BYTE offset2;
2788 DWORD sector;
2789 DWORD ccls;
2790
2791 dsk = fo->dsk;
2792
2793 // get the cluster of this entry
2794 ccls = fo->dirccls;
2795
2796 // figure out the offset from the base sector
2797 offset2 = (*curEntry / (dsk->sectorSize/32));
2798
2799 /* Settings based on FAT type */
2800 switch (dsk->type)
2801 {
2802 #ifdef SUPPORT_FAT32 // If FAT32 supported.
2803 case FAT32:
2804 // Root is always cluster-based in FAT32
2805 offset2 = offset2 % (dsk->SecPerClus);
2806 break;
2807 #endif
2808 case FAT12:
2809 case FAT16:
2810 if(ccls != FatRootDirClusterValue)
2811 offset2 = offset2 % (dsk->SecPerClus);
2812 break;
2813 }
2814
2815 sector = Cluster2Sector(dsk,ccls);
2816
2817 // Now write it
2818 // "Offset" ensures writing of data belonging to a file entry only. Hence it doesn't change other file entries.
2819 if ( !MDD_SectorWrite( sector + offset2, dsk->buffer, FALSE))
2820 status = FALSE;
2821 else
2822 status = TRUE;
2823
2824 return(status);
2825 } // Write_File_Entry
2826 #endif
2827
2828
2829 /**********************************************************
2830 Function:
2831 BYTE FAT_erase_cluster_chain (WORD cluster, DISK * dsk)
2832 Summary:
2833 Erase a chain of clusters
2834 Conditions:
2835 This function should not be called by the user.
2836 Input:
2837 cluster - The cluster number
2838 dsk - The disk structure
2839 Return Values:
2840 TRUE - Operation successful
2841 FALSE - Operation failed
2842 Side Effects:
2843 None
2844 Description:
2845 This function will parse through a cluster chain
2846 starting with the cluster pointed to by 'cluster' and
2847 mark all of the FAT entries as empty until the end of
2848 the chain has been reached or an error occurs.
2849 Remarks:
2850 None
2851 **********************************************************/
2852
2853 #ifdef ALLOW_WRITES
2854 BYTE FAT_erase_cluster_chain (DWORD cluster, DISK * dsk)
2855 {
2856 DWORD c,c2,ClusterFailValue;
2857 enum _status {Good, Fail, Exit}status;
2858
2859 status = Good;
2860
2861 /* Settings based on FAT type */
2862 switch (dsk->type)
2863 {
2864
2865 #ifdef SUPPORT_FAT32 // If FAT32 supported.
2866 case FAT32:
2867 ClusterFailValue = CLUSTER_FAIL_FAT32;
2868 c2 = LAST_CLUSTER_FAT32;
2869 break;
2870 #endif
2871 case FAT12:
2872 ClusterFailValue = CLUSTER_FAIL_FAT16; // FAT16 value itself
2873 c2 = LAST_CLUSTER_FAT12;
2874 break;
2875 case FAT16:
2876 default:
2877 ClusterFailValue = CLUSTER_FAIL_FAT16;
2878 c2 = LAST_CLUSTER_FAT16;
2879 break;
2880 }
2881
2882 // Make sure there is actually a cluster assigned
2883 if((cluster == 0) || (cluster == 1)) // Cluster assigned can't be "0" and "1"
2884 {
2885 status = Exit;
2886 }
2887 else
2888 {
2889 while(status == Good)
2890 {
2891 // Get the FAT entry
2892 if((c = ReadFAT( dsk, cluster)) == ClusterFailValue)
2893 status = Fail;
2894 else
2895 {
2896 if((c == 0) || (c == 1)) // Cluster assigned can't be "0" and "1"
2897 {
2898 status = Exit;
2899 }
2900 else
2901 {
2902 // compare against max value of a cluster in FATxx
2903 // look for the last cluster in the chain
2904 if ( c >= c2)
2905 status = Exit;
2906
2907 // Now erase this FAT entry
2908 if(WriteFAT(dsk, cluster, CLUSTER_EMPTY, FALSE) == ClusterFailValue)
2909 status = Fail;
2910
2911 // now update what the current cluster is
2912 cluster = c;
2913 }
2914 }
2915 }// while status
2916 }// cluster == 0
2917
2918 WriteFAT (dsk, 0, 0, TRUE);
2919
2920 if(status == Exit)
2921 return(TRUE);
2922 else
2923 return(FALSE);
2924 } // Erase cluster
2925 #endif
2926
2927 /**************************************************************************
2928 Function:
2929 DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead)
2930 Summary:
2931 Load a file entry
2932 Conditions:
2933 This function should not be called by the user.
2934 Input:
2935 fo - File information
2936 curEntry - Offset of the directory entry to load.
2937 ForceRead - Forces loading of a new sector of the directory.
2938 Return:
2939 DIRENTRY - Pointer to the directory entry that was loaded.
2940 Side Effects:
2941 Any unwritten data in the data buffer will be written to the device.
2942 Description:
2943 Load the sector containing the file entry pointed to by 'curEntry'
2944 from the directory pointed to by the variables in 'fo.'
2945 Remarks:
2946 Any modification of this function is extremely likely to
2947 break something.
2948 **************************************************************************/
2949
2950 DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead)
2951 {
2952 DIRENTRY dir;
2953 DISK *dsk;
2954 DWORD sector;
2955 DWORD cluster, LastClusterLimit;
2956 DWORD ccls;
2957 BYTE offset2;
2958 BYTE numofclus;
2959 BYTE dirEntriesPerSector;
2960
2961 dsk = fo->dsk;
2962
2963 // get the base sector of this directory
2964 cluster = fo->dirclus;
2965 ccls = fo->dirccls;
2966
2967 dirEntriesPerSector = dsk->sectorSize/32;
2968
2969 // figure out the offset from the base sector
2970 offset2 = (*curEntry / dirEntriesPerSector);
2971
2972 offset2 = offset2; // emulator issue
2973
2974 /* Settings based on FAT type */
2975 switch (dsk->type)
2976 {
2977 #ifdef SUPPORT_FAT32 // If FAT32 supported.
2978 case FAT32:
2979 // the ROOT is always cluster based in FAT32
2980 /* In FAT32: There is no ROOT region. Root etries are made in DATA region only.
2981 Every cluster of DATA which is accupied by ROOT is tracked by FAT table/entry so the ROOT can grow
2982 to an amount which is restricted only by available free DATA region. */
2983 offset2 = offset2 % (dsk->SecPerClus); // figure out the offset
2984 LastClusterLimit = LAST_CLUSTER_FAT32;
2985 break;
2986 #endif
2987 case FAT12:
2988 case FAT16:
2989 default:
2990 // if its the root its not cluster based
2991 if(cluster != 0)
2992 offset2 = offset2 % (dsk->SecPerClus); // figure out the offset
2993 LastClusterLimit = LAST_CLUSTER_FAT16;
2994 break;
2995 }
2996
2997 // check if a new sector of the root must be loaded
2998 if (ForceRead || ((*curEntry & MASK_MAX_FILE_ENTRY_LIMIT_BITS) == 0)) // only 16 entries per sector
2999 {
3000 // see if we have to load a new cluster
3001 if(((offset2 == 0) && (*curEntry >= dirEntriesPerSector)) || ForceRead)
3002 {
3003 if(cluster == 0)
3004 {
3005 ccls = 0;
3006 }
3007 else
3008 {
3009 // If ForceRead, read the number of sectors from 0
3010 if(ForceRead)
3011 numofclus = ((WORD)(*curEntry) / (WORD)(((WORD)dirEntriesPerSector) * (WORD)dsk->SecPerClus));
3012 // Otherwise just read the next sector
3013 else
3014 numofclus = 1;
3015
3016 // move to the correct cluster
3017 while(numofclus)
3018 {
3019 ccls = ReadFAT(dsk, ccls);
3020
3021 if(ccls >= LastClusterLimit)
3022 break;
3023 else
3024 numofclus--;
3025 }
3026 }
3027 }
3028
3029 // see if that we have a valid cluster number
3030 if(ccls < LastClusterLimit)
3031 {
3032 fo->dirccls = ccls; // write it back
3033
3034 sector = Cluster2Sector(dsk,ccls);
3035
3036 /* see if we are root and about to go pass our boundaries
3037 FAT32 stores the root directory in the Data Region along with files and other directories,
3038 allowing it to grow without such a restraint */
3039 if((ccls == FatRootDirClusterValue) && ((sector + offset2) >= dsk->data) && (FAT32 != dsk->type))
3040 {
3041 dir = ((DIRENTRY)NULL); // reached the end of the root
3042 }
3043 else
3044 {
3045 #ifdef ALLOW_WRITES
3046 if (gNeedDataWrite)
3047 if (flushData())
3048 return NULL;
3049 #endif
3050 gBufferOwner = NULL;
3051 gBufferZeroed = FALSE;
3052
3053 if ( MDD_SectorRead( sector + offset2, dsk->buffer) != TRUE) // if FALSE: sector could not be read.
3054 {
3055 dir = ((DIRENTRY)NULL);
3056 }
3057 else // Sector has been read properly, Copy the root entry info of the file searched.
3058 {
3059 if(ForceRead) // Buffer holds all 16 root entry info. Point to the one required.
3060 dir = (DIRENTRY)((DIRENTRY)dsk->buffer) + ((*curEntry)%dirEntriesPerSector);
3061 else
3062 dir = (DIRENTRY)dsk->buffer;
3063 }
3064 gLastDataSectorRead = 0xFFFFFFFF;
3065 }
3066 }
3067 else
3068 {
3069 nextClusterIsLast = TRUE;
3070 dir = ((DIRENTRY)NULL);
3071 }
3072 }
3073 else
3074 dir = (DIRENTRY)((DIRENTRY)dsk->buffer) + ((*curEntry)%dirEntriesPerSector);
3075
3076 return(dir);
3077 } // Cache_File_Entry
3078
3079
3080 /*************************************************************************
3081 Function:
3082 CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode, BOOL createFirstCluster)
3083 Summary:
3084 Create a new file entry
3085 Conditions:
3086 Should not be called by the user.
3087 Input:
3088 fo - Pointer to file structure
3089 fHandle - Location to create file
3090 mode - DIRECTORY mode or ARCHIVE mode
3091 createFirstCluster - If set to TRUE, first cluster is created
3092 Return Values:
3093 CE_GOOD - File Creation successful
3094 CE_DIR_FULL - All root directory entries are taken
3095 CE_WRITE_ERROR - The head cluster of the file could not be created.
3096 Side Effects:
3097 Modifies the FSerrno variable.
3098 Description:
3099 With the data passed within fo, create a new file entry in the current
3100 directory. This function will first search for empty file entries.
3101 Once an empty entry is found, the entry will be populated with data
3102 for a file or directory entry. Finally, the first cluster of the
3103 new file will be located and allocated, and its value will be
3104 written into the file entry.
3105 Remarks:
3106 None
3107 *************************************************************************/
3108
3109 #ifdef ALLOW_WRITES
3110 CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle, BYTE mode, BOOL createFirstCluster)
3111 {
3112 CETYPE error = CE_GOOD;
3113
3114 #if defined(SUPPORT_LFN)
3115 LFN_ENTRY *lfno;
3116 unsigned short int *templfnPtr = (unsigned short int *)fo -> utf16LFNptr,*dest;
3117 unsigned short int tempString[MAX_UTF16_CHARS_IN_LFN_ENTRY];
3118 UINT16_VAL tempShift;
3119 BOOL firstTime = TRUE;
3120 BYTE checksum,sequenceNumber,reminder,tempCalc1,numberOfFileEntries;
3121 char index;
3122 char *src;
3123 #endif
3124
3125 FSerrno = CE_GOOD;
3126
3127 *fHandle = 0;
3128
3129 // figure out where to put this file in the directory stucture
3130 if(FindEmptyEntries(fo, fHandle))
3131 {
3132 #if defined(SUPPORT_LFN)
3133 // If LFN entry
3134 if(fo->utf16LFNlength)
3135 {
3136 // Alias the LFN to short file name
3137 if(!Alias_LFN_Object(fo))
3138 {
3139 // If Aliasing of LFN is unsucessful
3140 error = FSerrno = CE_FILENAME_EXISTS;
3141 return(error);
3142 }
3143
3144 src = fo -> name;
3145
3146 // Find the checksum for Short file name of LFN
3147 checksum = 0;
3148 for (index = 11; index != 0; index--)
3149 {
3150 checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *src++;
3151 }
3152
3153 // File Name + NULL character is file name length in LFN
3154 fileNameLength = fo->utf16LFNlength;
3155
3156 // Determine the number of entries for LFN
3157 reminder = tempCalc1 = fileNameLength % MAX_UTF16_CHARS_IN_LFN_ENTRY;
3158
3159 numberOfFileEntries = fileNameLength/MAX_UTF16_CHARS_IN_LFN_ENTRY;
3160
3161 if(tempCalc1 || (fileNameLength < MAX_UTF16_CHARS_IN_LFN_ENTRY))
3162 {
3163 numberOfFileEntries++;
3164 }
3165
3166 // Max sequence number for LFN root entry
3167 sequenceNumber = numberOfFileEntries | 0x40;
3168
3169 // Store the max sequence number entries in tempString
3170 if(tempCalc1)
3171 {
3172 index = 0;
3173 while(tempCalc1)
3174 {
3175 tempString[(BYTE)index++] = templfnPtr[fileNameLength - tempCalc1];
3176 tempCalc1--;
3177 }
3178
3179 // Store the remaining bytes of max sequence number entries with 0xFF
3180 for(;index < MAX_UTF16_CHARS_IN_LFN_ENTRY;index++)
3181 {
3182 tempString[(BYTE)index] = 0xFFFF;
3183 }
3184 }
3185 else
3186 {
3187 // Store the remaining bytes of max sequence number entries with 0xFF
3188 for(index = MAX_UTF16_CHARS_IN_LFN_ENTRY;index > 0;index--)
3189 {
3190 tempString[MAX_UTF16_CHARS_IN_LFN_ENTRY - (BYTE)index] = templfnPtr[fileNameLength - (BYTE)index];
3191 }
3192 }
3193
3194 dest = &tempString[12];
3195
3196 while(numberOfFileEntries)
3197 {
3198 fo->dirccls = fo->dirclus;
3199 lfno = (LFN_ENTRY *)Cache_File_Entry( fo, fHandle, TRUE);
3200
3201 if (lfno == NULL)
3202 {
3203 return CE_BADCACHEREAD;
3204 }
3205
3206 // Write the 32 byte LFN Object as per FAT specification
3207 lfno->LFN_SequenceNo = sequenceNumber--; // Sequence number,
3208
3209 lfno->LFN_Part3[1] = *dest--;
3210 lfno->LFN_Part3[0] = *dest--;
3211
3212 lfno->LFN_Part2[5] = *dest--;
3213 lfno->LFN_Part2[4] = *dest--;
3214 lfno->LFN_Part2[3] = *dest--;
3215 lfno->LFN_Part2[2] = *dest--;
3216 lfno->LFN_Part2[1] = *dest--;
3217 lfno->LFN_Part2[0] = *dest--;
3218
3219 tempShift.Val = *dest--;
3220 lfno->LFN_Part1[9] = tempShift.byte.HB;
3221 lfno->LFN_Part1[8] = tempShift.byte.LB;
3222 tempShift.Val = *dest--;
3223 lfno->LFN_Part1[7] = tempShift.byte.HB;
3224 lfno->LFN_Part1[6] = tempShift.byte.LB;
3225 tempShift.Val = *dest--;
3226 lfno->LFN_Part1[5] = tempShift.byte.HB;
3227 lfno->LFN_Part1[4] = tempShift.byte.LB;
3228 tempShift.Val = *dest--;
3229 lfno->LFN_Part1[3] = tempShift.byte.HB;
3230 lfno->LFN_Part1[2] = tempShift.byte.LB;
3231 tempShift.Val = *dest--;
3232 lfno->LFN_Part1[1] = tempShift.byte.HB;
3233 lfno->LFN_Part1[0] = tempShift.byte.LB;
3234
3235 lfno->LFN_Attribute = ATTR_LONG_NAME;
3236 lfno->LFN_Type = 0;
3237 lfno->LFN_Checksum = checksum;
3238 lfno->LFN_Reserved2 = 0;
3239
3240 // just write the last entry in
3241 if (Write_File_Entry(fo,fHandle) != TRUE)
3242 error = CE_WRITE_ERROR;
3243
3244 // 0x40 should be ORed with only max sequence number & in
3245 // all other cases it should not be present
3246 sequenceNumber &= (~0x40);
3247 *fHandle = *fHandle + 1;
3248 numberOfFileEntries--;
3249
3250 // Load the destination address only once and during first time,
3251 if(firstTime)
3252 {
3253 dest = (unsigned short int *)(fo -> utf16LFNptr + fileNameLength - reminder - 1);
3254 firstTime = FALSE;
3255 }
3256 }
3257 }
3258 #endif
3259
3260 // found the entry, now populate it
3261 if((error = PopulateEntries(fo, fHandle, mode)) == CE_GOOD)
3262 {
3263 if(createFirstCluster)
3264 // if everything is ok, create a first cluster
3265 error = CreateFirstCluster(fo);
3266 else
3267 {
3268
3269 }
3270 }
3271 }
3272 else
3273 {
3274 error = CE_DIR_FULL;
3275 }
3276
3277 FSerrno = error;
3278
3279 return(error);
3280 }
3281 #endif
3282
3283 /******************************************************
3284 Function:
3285 CETYPE CreateFirstCluster(FILEOBJ fo)
3286 Summary:
3287 Create the first cluster for a file
3288 Conditions:
3289 This function should not be called by the user.
3290 Input:
3291 fo - The file that contains the first cluster
3292 Return Values:
3293 CE_GOOD - First cluster created successfully
3294 CE_WRITE_ERROR - Cluster creation failed
3295 Side Effects:
3296 None
3297 Description:
3298 This function will find an unused cluster, link it to
3299 a file's directory entry, and write the entry back
3300 to the device.
3301 Remarks:
3302 None.
3303 ******************************************************/
3304
3305 #ifdef ALLOW_WRITES
3306 CETYPE CreateFirstCluster(FILEOBJ fo)
3307 {
3308 CETYPE error;
3309 DWORD cluster,TempMsbCluster;
3310 WORD fHandle;
3311 DIRENTRY dir;
3312 fHandle = fo->entry;
3313
3314 // Now create the first cluster (head cluster)
3315 if((error = FILECreateHeadCluster(fo,&cluster)) == CE_GOOD)
3316 {
3317 // load the file entry so the new cluster can be linked to it
3318 dir = LoadDirAttrib(fo, &fHandle);
3319
3320 // Now update the new cluster
3321 dir->DIR_FstClusLO = (cluster & 0x0000FFFF);
3322
3323
3324 #ifdef SUPPORT_FAT32 // If FAT32 supported.
3325 // Get the higher part of cluster and store it in directory entry.
3326 TempMsbCluster = (cluster & 0x0FFF0000); // Since only 28 bits usedin FAT32. Mask the higher MSB nibble.
3327 TempMsbCluster = TempMsbCluster >> 16; // Get the date into Lsb place.
3328 dir->DIR_FstClusHI = TempMsbCluster;
3329 #else // If FAT32 support not enabled
3330 TempMsbCluster = 0; // Just to avoid compiler warnigng.
3331 dir->DIR_FstClusHI = 0;
3332 #endif
3333
3334 // now write it
3335 if(Write_File_Entry(fo, &fHandle) != TRUE)
3336 error = CE_WRITE_ERROR;
3337 } // Create Cluster
3338
3339 return(error);
3340 }// End of CreateFirstCluster
3341 #endif
3342
3343 /**********************************************************
3344 Function:
3345 BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle)
3346 Summary:
3347 Find an empty dir entry
3348 Conditions:
3349 This function should not be called by the user.
3350 Input:
3351 fo - Pointer to file structure
3352 fHandle - Start of entries
3353 Return Values:
3354 TRUE - One found
3355 FALSE - None found
3356 Side Effects:
3357 None
3358 Description:
3359 This function will cache directory entries, starting
3360 with the one pointed to by the fHandle argument. It will
3361 then search through the entries until an unused one
3362 is found. If the end of the cluster chain for the
3363 directory is reached, a new cluster will be allocated
3364 to the directory (unless it's a FAT12 or FAT16 root)
3365 and the first entry of the new cluster will be used.
3366 Remarks:
3367 None.
3368 **********************************************************/
3369
3370 #ifdef ALLOW_WRITES
3371 BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle)
3372 {
3373 BYTE status = NOT_FOUND;
3374 BYTE amountfound,numberOfFileEntries;
3375 BYTE a = 0;
3376 WORD bHandle;
3377 DWORD b;
3378 DIRENTRY dir;
3379
3380 fo->dirccls = fo->dirclus;
3381 if((dir = Cache_File_Entry( fo, fHandle, TRUE)) == NULL)
3382 {
3383 status = CE_BADCACHEREAD;
3384 }
3385 else
3386 {
3387 #if defined(SUPPORT_LFN)
3388 // If LFN entry
3389 if(fo->utf16LFNlength)
3390 {
3391 // File Name + NULL character is file name length in LFN
3392 fileNameLength = fo->utf16LFNlength;
3393
3394 // Determine the number of entries for LFN
3395 a = fileNameLength % MAX_UTF16_CHARS_IN_LFN_ENTRY;
3396
3397 numberOfFileEntries = fileNameLength/MAX_UTF16_CHARS_IN_LFN_ENTRY;
3398
3399 if(a || (fileNameLength < MAX_UTF16_CHARS_IN_LFN_ENTRY))
3400 {
3401 numberOfFileEntries++;
3402 }
3403
3404 numberOfFileEntries = numberOfFileEntries + 1;
3405 }
3406 else
3407 #endif
3408 numberOfFileEntries = 1;
3409
3410 // while its still not found
3411 while(status == NOT_FOUND)
3412 {
3413 amountfound = 0;
3414 bHandle = *fHandle;
3415
3416 // find (number) continuous entries
3417 do
3418 {
3419 // Get the entry
3420 dir = Cache_File_Entry( fo, fHandle, FALSE);
3421
3422 // Read the first char of the file name
3423 if(dir != NULL) // Last entry of the cluster
3424 {
3425 a = dir->DIR_Name[0];
3426 }
3427 // increase number
3428 (*fHandle)++;
3429 }while((dir != (DIRENTRY)NULL) && ((a == DIR_DEL) || (a == DIR_EMPTY)) && (++amountfound < numberOfFileEntries));
3430
3431 // --- now why did we exit?
3432 if(dir == NULL) // Last entry of the cluster
3433 {
3434 //setup the current cluster
3435 b = fo->dirccls; // write it back
3436
3437 // make sure we are not the root directory
3438 if(b == FatRootDirClusterValue)
3439 {
3440 if (fo->dsk->type != FAT32)
3441 status = NO_MORE;
3442 else
3443 {
3444 fo->ccls = b;
3445
3446 if(FILEallocate_new_cluster(fo, 1) == CE_DISK_FULL)
3447 status = NO_MORE;
3448 else
3449 {
3450 *fHandle = bHandle;
3451 status = FOUND; // a new cluster will surely hold a new file name
3452 }
3453 }
3454 }
3455 else
3456 {
3457 fo->ccls = b;
3458
3459 if(FILEallocate_new_cluster(fo, 1) == CE_DISK_FULL)
3460 status = NO_MORE;
3461 else
3462 {
3463 *fHandle = bHandle;
3464 status = FOUND; // a new cluster will surely hold a new file name
3465 }
3466 }
3467 }
3468 else
3469 {
3470 if(amountfound == numberOfFileEntries)
3471 {
3472 status = FOUND;
3473 *fHandle = bHandle - numberOfFileEntries + 1;
3474 }
3475 }
3476 }// while
3477
3478 // copy the base handle over
3479 *fHandle = bHandle;
3480 }
3481
3482 if(status == FOUND)
3483 return(TRUE);
3484 else
3485 return(FALSE);
3486 }
3487 #endif
3488
3489 /**************************************************************************
3490 Function:
3491 BYTE PopulateEntries(FILEOBJ fo, WORD *fHandle, BYTE mode)
3492 Summary:
3493 Populate a dir entry with data
3494 Conditions:
3495 Should not be called by the user.
3496 Input:
3497 fo - Pointer to file structure
3498 fHandle - Location of the file
3499 mode - DIRECTORY mode or ARCHIVE mode
3500 Return Values:
3501 CE_GOOD - Population successful
3502 Side Effects:
3503 None
3504 Description:
3505 This function will write data into a new file entry. It will also
3506 load timestamp data (based on the method selected by the user) and
3507 update the timestamp variables.
3508 Remarks:
3509 None.
3510 **************************************************************************/
3511
3512 #ifdef ALLOW_WRITES
3513 BYTE PopulateEntries(FILEOBJ fo, WORD *fHandle, BYTE mode)
3514 {
3515 BYTE error = CE_GOOD;
3516 DIRENTRY dir;
3517
3518 fo->dirccls = fo->dirclus;
3519 dir = Cache_File_Entry( fo, fHandle, TRUE);
3520
3521 if (dir == NULL)
3522 return CE_BADCACHEREAD;
3523
3524 // copy the contents over
3525 strncpy(dir->DIR_Name,fo->name,DIR_NAMECOMP);
3526
3527 // setup no attributes
3528 if (mode == DIRECTORY)
3529 dir->DIR_Attr = ATTR_DIRECTORY;
3530 else
3531 dir->DIR_Attr = ATTR_ARCHIVE;
3532
3533 dir->DIR_NTRes = 0x00; // nt reserved
3534 dir->DIR_FstClusHI = 0x0000; // high word of this enty's first cluster number
3535 dir->DIR_FstClusLO = 0x0000; // low word of this entry's first cluster number
3536 dir->DIR_FileSize = 0x0; // file size in DWORD
3537
3538 // Timing information for uncontrolled clock mode
3539 #ifdef INCREMENTTIMESTAMP
3540 dir->DIR_CrtTimeTenth = 0xB2; // millisecond stamp
3541 dir->DIR_CrtTime = 0x7278; // time created
3542 dir->DIR_CrtDate = 0x32B0; // date created
3543 dir->DIR_LstAccDate = 0x32B0; // Last Access date
3544 dir->DIR_WrtTime = 0x7279; // last update time
3545 dir->DIR_WrtDate = 0x32B0; // last update date
3546 #endif
3547
3548 #ifdef USEREALTIMECLOCK
3549 CacheTime();
3550 dir->DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp
3551 dir->DIR_CrtTime = gTimeCrtTime; // time created //
3552 dir->DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004)
3553 dir->DIR_LstAccDate = gTimeAccDate; // Last Access date
3554 dir->DIR_WrtTime = gTimeWrtTime; // last update time
3555 dir->DIR_WrtDate = gTimeWrtDate; // last update date
3556 #endif
3557
3558 #ifdef USERDEFINEDCLOCK
3559 // The user will have set the time before this funciton is called
3560 dir->DIR_CrtTimeTenth = gTimeCrtMS;
3561 dir->DIR_CrtTime = gTimeCrtTime;
3562 dir->DIR_CrtDate = gTimeCrtDate;
3563 dir->DIR_LstAccDate = gTimeAccDate;
3564 dir->DIR_WrtTime = gTimeWrtTime;
3565 dir->DIR_WrtDate = gTimeWrtDate;
3566 #endif
3567
3568 fo->size = dir->DIR_FileSize;
3569 fo->time = dir->DIR_CrtTime;
3570 fo->date = dir->DIR_CrtDate;
3571 fo->attributes = dir->DIR_Attr;
3572 fo->entry = *fHandle;
3573
3574 // just write the last entry in
3575 if (Write_File_Entry(fo,fHandle) != TRUE)
3576 error = CE_WRITE_ERROR;
3577
3578 return(error);
3579 }
3580
3581 /*****************************************************************
3582 Function:
3583 BOOL Alias_LFN_Object(FILEOBJ fo)
3584 Summary:
3585 Find the Short file name of the LFN entry
3586 Conditions:
3587 Long file name should be present.
3588 Input:
3589 fo - Pointer to file structure
3590 Return Values:
3591 FOUND - Operation successful
3592 NOT_FOUND - Operation failed
3593 Side Effects:
3594 None
3595 Description:
3596 This function will find the short file name
3597 of the long file name as mentioned in the FAT
3598 specs.
3599 Remarks:
3600 None.
3601 *****************************************************************/
3602 #if defined(SUPPORT_LFN)
3603 BOOL Alias_LFN_Object(FILEOBJ fo)
3604 {
3605 FSFILE filePtr1;
3606 FSFILE filePtr2;
3607 unsigned long int index4;
3608 short int lfnIndex,index1,index2;
3609 BYTE tempVariable,index;
3610 char tempString[8];
3611 char *lfnAliasPtr;
3612 unsigned short int *templfnPtr;
3613 BOOL result = FALSE;
3614
3615 // copy file object over
3616 FileObjectCopy(&filePtr1, fo);
3617
3618 lfnAliasPtr = (char *)&filePtr1.name[0];
3619
3620 templfnPtr = (unsigned short int *)filePtr1.utf16LFNptr;
3621
3622 fileNameLength = fo->utf16LFNlength - 1;
3623
3624 // Initially fill the alias name with space characters
3625 for(index1 = 0;index1 < FILE_NAME_SIZE_8P3;index1++)
3626 {
3627 lfnAliasPtr[index1] = ' ';
3628 }
3629
3630 // find the location where '.' is present
3631 for(lfnIndex = fileNameLength - 1;lfnIndex > 0;lfnIndex--)
3632 {
3633 if (templfnPtr[lfnIndex] == '.')
3634 {
3635 break;
3636 }
3637 }
3638
3639 index1 = lfnIndex + 1;
3640
3641 tempVariable = 0;
3642 if(lfnIndex)
3643 {
3644 index2 = 8;
3645 // Complete the extension part as per the FAT specifications
3646 for(;((index1 < fileNameLength) && (tempVariable < 3));index1++)
3647 {
3648 // Convert lower-case to upper-case
3649 index = (BYTE)templfnPtr[index1];
3650 if ((index >= 0x61) && (index <= 0x7A))
3651 {
3652 lfnAliasPtr[index2++] = index - 0x20;
3653 }
3654 else if(index == ' ')
3655 {
3656 continue;
3657 }
3658 else if ((index == 0x2B) || (index == 0x2C) || (index == 0x3B) ||
3659 (index == 0x3D) || (index == 0x5B) || (index == 0x5D) ||
3660 (templfnPtr[index1] > 0xFF))
3661 {
3662 lfnAliasPtr[index2++] = '_';
3663 }
3664 else
3665 {
3666 lfnAliasPtr[index2++] = index;
3667 }
3668
3669 tempVariable++;
3670 }
3671
3672 index2 = lfnIndex;
3673 tempVariable = 0;
3674 }
3675 else
3676 {
3677 index2 = fileNameLength;
3678 }
3679
3680 // Fill the base part as per the FAT specifications
3681 for(index1 = 0;((index1 < index2) && (tempVariable < 6));index1++)
3682 {
3683 // Convert lower-case to upper-case
3684 index = (BYTE)templfnPtr[index1];
3685 if ((index >= 0x61) && (index <= 0x7A))
3686 {
3687 lfnAliasPtr[tempVariable] = index - 0x20;
3688 }
3689 else if(index == ' ')
3690 {
3691 continue;
3692 }
3693 else if ((index == 0x2B) || (index == 0x2C) || (index == 0x3B) ||
3694 (index == 0x3D) || (index == 0x5B) || (index == 0x5D) ||
3695 (templfnPtr[index1] > 0xFF))
3696 {
3697 lfnAliasPtr[tempVariable] = '_';
3698 }
3699 else
3700 {
3701 lfnAliasPtr[tempVariable] = index;
3702 }
3703 tempVariable++;
3704 }
3705
3706 // Aliasing of the predicted name should append ~1
3707 lfnAliasPtr[tempVariable] = '~';
3708 lfnAliasPtr[tempVariable + 1] = '1';
3709
3710 filePtr1.attributes = ATTR_ARCHIVE;
3711
3712 filePtr1.utf16LFNlength = 0;
3713
3714 // Try for 9999999 combinations before telling error to the user
3715 for(index4 = 1;index4 < (unsigned long int)10000000;index4++)
3716 {
3717 filePtr1.cluster = 0;
3718 filePtr1.ccls = 0;
3719 filePtr1.entry = 0;
3720
3721 // start at the current directory
3722 #ifdef ALLOW_DIRS
3723 filePtr1.dirclus = cwdptr->dirclus;
3724 filePtr1.dirccls = cwdptr->dirccls;
3725 #else
3726 filePtr1.dirclus = FatRootDirClusterValue;
3727 filePtr1.dirccls = FatRootDirClusterValue;
3728 #endif
3729
3730 // copy file object over
3731 FileObjectCopy(&filePtr2, &filePtr1);
3732
3733 // See if the file is found
3734 if(FILEfind (&filePtr2, &filePtr1, LOOK_FOR_MATCHING_ENTRY, 0) == CE_GOOD)
3735 {
3736 tempString[7] = index4 % (BYTE)10 + '0';
3737 tempString[6] = (index4 % (BYTE)100)/10 + '0';
3738 tempString[5] = (index4 % 1000)/100 + '0';
3739 tempString[4] = (index4 % 10000)/1000 + '0';
3740 tempString[3] = (index4 % 100000)/10000 + '0';
3741 tempString[2] = (index4 % 1000000)/100000 + '0';
3742 if((tempString[1] = ((index4 % 10000000)/1000000 + '0')) != '0')
3743 {
3744 tempString[index = 0] = '~';
3745 }
3746 else
3747 {
3748 for(index = 6;index > 0;index--)
3749 {
3750 if((tempString[index] == '0') && (tempString[index - 1] == '0'))
3751 {
3752 tempString[index] = '~';
3753 if(!filePtr1.AsciiEncodingType)
3754 {
3755 if(index % 2)
3756 {
3757 for(index2 = index - 1;index2 < 7;index2++)
3758 {
3759 tempString[index2] = tempString[index2 + 1];
3760 }
3761 tempString[7] = ' ';
3762 index--;
3763 }
3764 }
3765 break;
3766 }
3767 }
3768 }
3769
3770 if(index >= tempVariable)
3771 {
3772 index1 = tempVariable;
3773 }
3774 else
3775 {
3776 index1 = index;
3777 }
3778
3779 while(index < 8)
3780 {
3781 filePtr1.name[index1++] = tempString[index++];
3782 }
3783
3784 // Store the remaining bytes with leading spaces
3785 while(index1 < 8)
3786 {
3787 filePtr1.name[index1++] = ' ';
3788 }
3789
3790 }
3791 else
3792 {
3793 // short file name is found.Store it & quit
3794 lfnAliasPtr = &fo->name[0];
3795
3796 for(index = 0;index < FILE_NAME_SIZE_8P3;index++)
3797 {
3798 lfnAliasPtr[index] = filePtr1.name[index];
3799 }
3800
3801 result = TRUE;
3802 break;
3803 }
3804 }
3805
3806 return(result);
3807
3808 } // Alias_LFN_Object
3809 #endif
3810
3811 #ifdef USEREALTIMECLOCK
3812
3813 /*************************************************************************
3814 Function:
3815 void CacheTime (void)
3816 Summary:
3817 Automatically store timestamp information from the RTCC
3818 Conditions:
3819 RTCC module enabled. Should not be called by the user.
3820 Return Values:
3821 None
3822 Side Effects:
3823 Modifies global timing variables
3824 Description:
3825 This function will automatically load information from an RTCC
3826 module and use it to update the global timing variables. These can
3827 then be used to update file timestamps.
3828 Remarks:
3829 None.
3830 *************************************************************************/
3831
3832 void CacheTime (void)
3833 {
3834 WORD year, monthday, weekhour, minsec, c, result;
3835 BYTE ptr1, ptr0;
3836
3837 #if defined (__PIC32MX__) // Added support for PIC32. -Bud (3/4/2008)
3838
3839 unsigned int t0, t1;
3840 unsigned int d0, d1;
3841
3842 do // Get the time
3843 {
3844 t0=RTCTIME;
3845 t1=RTCTIME;
3846 }while(t0!=t1);
3847
3848 do // Get the date
3849 {
3850 d0=RTCDATE;
3851 d1=RTCDATE;
3852 }while(d0!=d1);
3853
3854 // Put them in place.
3855 year = (WORD)(d0 >> 24);
3856 monthday = (WORD)(d0 >> 8);
3857 weekhour = (WORD)((d0 & 0x0F) << 8);
3858 weekhour |= (WORD)(t0 >> 24);
3859 minsec = (WORD)(t0 >> 8);
3860
3861 #else
3862
3863 if(RCFGCALbits.RTCPTR0)
3864 ptr0 = 1;
3865 else
3866 ptr0 = 0;
3867 if (RCFGCALbits.RTCPTR1)
3868 ptr1 = 1;
3869 else
3870 ptr1 = 0;
3871
3872 RCFGCALbits.RTCPTR0 = 1;
3873 RCFGCALbits.RTCPTR1 = 1;
3874 year = RTCVAL;
3875 monthday = RTCVAL;
3876 weekhour = RTCVAL;
3877 minsec = RTCVAL;
3878
3879 if (ptr0 == 1)
3880 RCFGCALbits.RTCPTR0 = 1;
3881
3882 if (ptr1 == 1)
3883 RCFGCALbits.RTCPTR1 = 1;
3884
3885 #endif
3886
3887 c = 0;
3888 c += (year & 0x0F);
3889 c += ((year & 0xF0) >> 4) * 10;
3890 // c equals the last 2 digits of the year from 2000 to 2099
3891 // Add 20 to adjust it to FAT time (from 1980 to 2107)
3892 c += 20;
3893 // shift the result to bits
3894 result = c << 9;
3895
3896 if ((monthday & 0x1000) == 0x1000)
3897 {
3898 c = 10;
3899 }
3900 else
3901 {
3902 c = 0;
3903 }
3904 c += ((monthday & 0x0F00) >> 8);
3905 c <<= 5;
3906 result |= c;
3907
3908 c = (monthday & 0x00F0) >> 4;
3909 c *= 10;
3910 c += (monthday & 0x000F);
3911
3912 result |= c;
3913
3914 gTimeCrtDate = result;
3915 gTimeWrtDate = result;
3916 gTimeAccDate = result;
3917
3918 c = ((weekhour & 0x00F0) >> 4) * 10;
3919 c += (weekhour & 0x000F);
3920 result = c << 11;
3921 c = ((minsec & 0xF000) >> 12) * 10;
3922 c += (minsec & 0x0F00) >> 8;
3923 result |= (c << 5);
3924 c = ((minsec & 0x00F0) >> 4) * 10;
3925 c += (minsec & 0x000F);
3926
3927 // If seconds mod 2 is 1, add 1000 ms
3928 if (c % 2)
3929 gTimeCrtMS = 100;
3930 else
3931 gTimeCrtMS = 0;
3932
3933 c >>= 1;
3934 result |= c;
3935
3936 gTimeCrtTime = result;
3937 gTimeWrtTime = result;
3938 }
3939 #endif
3940
3941 #ifdef USERDEFINEDCLOCK
3942
3943 /***********************************************************************************************************
3944 Function:
3945 int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second)
3946 Summary:
3947 Manually set timestamp variables
3948 Conditions:
3949 USERDEFINEDCLOCK macro defined in FSconfig.h.
3950 Input:
3951 year - The year (1980\-2107)
3952 month - The month (1\-12)
3953 day - The day of the month (1\-31)
3954 hour - The hour (0\-23)
3955 minute - The minute (0\-59)
3956 second - The second (0\-59)
3957 Return Values:
3958 None
3959 Side Effects:
3960 Modifies global timing variables
3961 Description:
3962 Lets the user manually set the timing variables. The values passed in will be converted to the format
3963 used by the FAT timestamps.
3964 Remarks:
3965 Call this before creating a file or directory (set create time) and
3966 before closing a file (set last access time, last modified time)
3967 ***********************************************************************************************************/
3968
3969 int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second)
3970 {
3971 unsigned int result;
3972
3973 if ((year < 1980) || (year > 2107) || (month < 1) || (month > 12) ||
3974 (day < 1) || (day > 31) || (hour > 23) || (minute > 59) || (second > 59))
3975 {
3976 FSerrno = CE_INVALID_ARGUMENT;
3977 return -1;
3978 }
3979
3980 result = (year - 1980) << 9;
3981 result |= (unsigned int)((unsigned int)month << 5);
3982 result |= (day);
3983
3984 gTimeAccDate = result;
3985 gTimeCrtDate = result;
3986 gTimeWrtDate = result;
3987
3988 result = ((unsigned int)hour << 11);
3989 result |= (unsigned int)((unsigned int)minute << 5);
3990 result |= (second/2);
3991
3992 gTimeCrtTime = result;
3993 gTimeWrtTime = result;
3994
3995 if (second % 2)
3996 gTimeCrtMS = 100;
3997 else
3998 gTimeCrtMS = 0;
3999
4000 FSerrno = CE_GOOD;
4001 return 0;
4002 }
4003 #endif
4004
4005 #endif
4006
4007 /***********************************************************************
4008 Function:
4009 BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode)
4010 Summary;
4011 Allocate a new cluster to a file
4012 Conditions:
4013 Should not be called by the user.
4014 Input:
4015 fo - Pointer to file structure
4016 mode -
4017 - 0 - Allocate a cluster to a file
4018 - 1 - Allocate a cluster to a directory
4019 Return Values:
4020 CE_GOOD - Cluster allocated
4021 CE_DISK_FULL - No clusters available
4022 Side Effects:
4023 None
4024 Description:
4025 This function will find an empty cluster on the device using the
4026 FATfindEmptyCluster function. It will then mark it as the last
4027 cluster in the file in the FAT chain, and link the current last
4028 cluster of the passed file to the new cluster. If the new
4029 cluster is a directory cluster, it will be erased (so there are no
4030 extraneous directory entries). If it's allocated to a non-directory
4031 file, it doesn't need to be erased; extraneous data in the cluster
4032 will be unviewable because of the file size parameter.
4033 Remarks:
4034 None.
4035 ***********************************************************************/
4036
4037 #ifdef ALLOW_WRITES
4038 BYTE FILEallocate_new_cluster( FILEOBJ fo, BYTE mode)
4039 {
4040 DISK * dsk;
4041 DWORD c,curcls;
4042
4043 dsk = fo->dsk;
4044 c = fo->ccls;
4045
4046 // find the next empty cluster
4047 c = FATfindEmptyCluster(fo);
4048 if (c == 0) // "0" is just an indication as Disk full in the fn "FATfindEmptyCluster()"
4049 return CE_DISK_FULL;
4050
4051
4052 // mark the cluster as taken, and last in chain
4053 if(dsk->type == FAT12)
4054 WriteFAT( dsk, c, LAST_CLUSTER_FAT12, FALSE);
4055 else if (dsk->type == FAT16)
4056 WriteFAT( dsk, c, LAST_CLUSTER_FAT16, FALSE);
4057
4058 #ifdef SUPPORT_FAT32 // If FAT32 supported.
4059 else
4060 WriteFAT( dsk, c, LAST_CLUSTER_FAT32, FALSE);
4061 #endif
4062
4063 // link current cluster to the new one
4064 curcls = fo->ccls;
4065
4066 WriteFAT( dsk, curcls, c, FALSE);
4067
4068 // update the FILE structure
4069 fo->ccls = c;
4070
4071 // IF this is a dir, we need to erase the cluster
4072 // If it's a file, we can leave it- the file size
4073 // will limit the data we see to the data that's been
4074 // written
4075 if (mode == 1)
4076 return (EraseCluster(dsk, c));
4077 else
4078 return CE_GOOD;
4079
4080 } // allocate new cluster
4081 #endif
4082
4083 /***********************************************
4084 Function:
4085 DWORD FATfindEmptyCluster(FILEOBJ fo)
4086 Summary:
4087 Find the next available cluster on the device
4088 Conditions:
4089 This function should not be called by the
4090 user.
4091 Input:
4092 fo - Pointer to file structure
4093 Return Values:
4094 DWORD - Address of empty cluster
4095 0 - Could not find empty cluster
4096 Side Effects:
4097 None
4098 Description:
4099 This function will search through the FAT to
4100 find the next available cluster on the device.
4101 Remarks:
4102 Should not be called by user
4103 ***********************************************/
4104
4105 #ifdef ALLOW_WRITES
4106 DWORD FATfindEmptyCluster(FILEOBJ fo)
4107 {
4108 DISK * disk;
4109 DWORD value = 0x0;
4110 DWORD c,curcls, EndClusterLimit, ClusterFailValue;
4111
4112 disk = fo->dsk;
4113 c = fo->ccls;
4114
4115 /* Settings based on FAT type */
4116 switch (disk->type)
4117 {
4118 #ifdef SUPPORT_FAT32 // If FAT32 supported.
4119 case FAT32:
4120 EndClusterLimit = END_CLUSTER_FAT32;
4121 ClusterFailValue = CLUSTER_FAIL_FAT32;
4122 break;
4123 #endif
4124 case FAT12:
4125 EndClusterLimit = END_CLUSTER_FAT12;
4126 ClusterFailValue = CLUSTER_FAIL_FAT16;
4127 break;
4128 case FAT16:
4129 default:
4130 EndClusterLimit = END_CLUSTER_FAT16;
4131 ClusterFailValue = CLUSTER_FAIL_FAT16;
4132 break;
4133 }
4134
4135 // just in case
4136 if(c < 2)
4137 c = 2;
4138
4139 curcls = c;
4140 ReadFAT(disk, c);
4141
4142 // sequentially scan through the FAT looking for an empty cluster
4143 while(c)
4144 {
4145 // look at its value
4146 if ( (value = ReadFAT(disk, c)) == ClusterFailValue)
4147 {
4148 c = 0;
4149 break;
4150 }
4151
4152 // check if empty cluster found
4153 if (value == CLUSTER_EMPTY)
4154 break;
4155
4156 c++; // check next cluster in FAT
4157 // check if reached last cluster in FAT, re-start from top
4158 if ((value == EndClusterLimit) || (c >= (disk->maxcls+2)))
4159 c = 2;
4160
4161 // check if full circle done, disk full
4162 if ( c == curcls)
4163 {
4164 c = 0;
4165 break;
4166 }
4167 } // scanning for an empty cluster
4168
4169 return(c);
4170 }
4171 #endif
4172
4173
4174 /*********************************************************************************
4175 Function:
4176 void FSGetDiskProperties(FS_DISK_PROPERTIES* properties)
4177 Summary:
4178 Allows user to get the disk properties (size of disk, free space, etc)
4179 Conditions:
4180 1) ALLOW_GET_DISK_PROPERTIES must be defined in FSconfig.h
4181 2) a FS_DISK_PROPERTIES object must be created before the function is called
4182 3) the new_request member of the FS_DISK_PROPERTIES object must be set before
4183 calling the function for the first time. This will start a new search.
4184 4) this function should not be called while there is a file open. Close all
4185 files before calling this function.
4186 Input:
4187 properties - a pointer to a FS_DISK_PROPERTIES object where the results should
4188 be stored.
4189 Return Values:
4190 This function returns void. The properties_status of the previous call of this
4191 function is located in the properties.status field. This field has the
4192 following possible values:
4193
4194 FS_GET_PROPERTIES_NO_ERRORS - operation completed without error. Results
4195 are in the properties object passed into the function.
4196 FS_GET_PROPERTIES_DISK_NOT_MOUNTED - there is no mounted disk. Results in
4197 properties object is not valid
4198 FS_GET_PROPERTIES_CLUSTER_FAILURE - there was a failure trying to read a
4199 cluster from the drive. The results in the properties object is a partial
4200 result up until the point of the failure.
4201 FS_GET_PROPERTIES_STILL_WORKING - the search for free sectors is still in
4202 process. Continue calling this function with the same properties pointer
4203 until either the function completes or until the partial results meets the
4204 application needs. The properties object contains the partial results of
4205 the search and can be used by the application.
4206 Side Effects:
4207 Can cause errors if called when files are open. Close all files before
4208 calling this function.
4209
4210 Calling this function without setting the new_request member on the first
4211 call can result in undefined behavior and results.
4212
4213 Calling this function after a result is returned other than
4214 FS_GET_PROPERTIES_STILL_WORKING can result in undefined behavior and results.
4215 Description:
4216 This function returns the information about the mounted drive. The results
4217 member of the properties object passed into the function is populated with
4218 the information about the drive.
4219
4220 Before starting a new request, the new_request member of the properties
4221 input parameter should be set to TRUE. This will initiate a new search
4222 request.
4223
4224 This function will return before the search is complete with partial results.
4225 All of the results except the free_clusters will be correct after the first
4226 call. The free_clusters will contain the number of free clusters found up
4227 until that point, thus the free_clusters result will continue to grow until
4228 the entire drive is searched. If an application only needs to know that a
4229 certain number of bytes is available and doesn't need to know the total free
4230 size, then this function can be called until the required free size is
4231 verified. To continue a search, pass a pointer to the same FS_DISK_PROPERTIES
4232 object that was passed in to create the search.
4233
4234 A new search request sould be made once this function has returned a value
4235 other than FS_GET_PROPERTIES_STILL_WORKING. Continuing a completed search
4236 can result in undefined behavior or results.
4237
4238 Typical Usage:
4239 <code>
4240 FS_DISK_PROPERTIES disk_properties;
4241
4242 disk_properties.new_request = TRUE;
4243
4244 do
4245 {
4246 FSGetDiskProperties(&disk_properties);
4247 } while (disk_properties.properties_status == FS_GET_PROPERTIES_STILL_WORKING);
4248 </code>
4249
4250 results.disk_format - contains the format of the drive. Valid results are
4251 FAT12(1), FAT16(2), or FAT32(3).
4252
4253 results.sector_size - the sector size of the mounted drive. Valid values are
4254 512, 1024, 2048, and 4096.
4255
4256 results.sectors_per_cluster - the number sectors per cluster.
4257
4258 results.total_clusters - the number of total clusters on the drive. This
4259 can be used to calculate the total disk size (total_clusters *
4260 sectors_per_cluster * sector_size = total size of drive in bytes)
4261
4262 results.free_clusters - the number of free (unallocated) clusters on the drive.
4263 This can be used to calculate the total free disk size (free_clusters *
4264 sectors_per_cluster * sector_size = total size of drive in bytes)
4265
4266 Remarks:
4267 PIC24F size estimates:
4268 Flash - 400 bytes (-Os setting)
4269
4270 PIC24F speed estimates:
4271 Search takes approximately 7 seconds per Gigabyte of drive space. Speed
4272 will vary based on the number of sectors per cluster and the sector size.
4273 *********************************************************************************/
4274 #if defined(ALLOW_GET_DISK_PROPERTIES)
4275 void FSGetDiskProperties(FS_DISK_PROPERTIES* properties)
4276 {
4277 BYTE i;
4278 DWORD value = 0x0;
4279
4280 if(properties->new_request == TRUE)
4281 {
4282 properties->disk = &gDiskData;
4283 properties->results.free_clusters = 0;
4284 properties->new_request = FALSE;
4285
4286 if(properties->disk->mount != TRUE)
4287 {
4288 properties->properties_status = FS_GET_PROPERTIES_DISK_NOT_MOUNTED;
4289 return;
4290 }
4291
4292 properties->properties_status = FS_GET_PROPERTIES_STILL_WORKING;
4293
4294 properties->results.disk_format = properties->disk->type;
4295 properties->results.sector_size = properties->disk->sectorSize;
4296 properties->results.sectors_per_cluster = properties->disk->SecPerClus;
4297 properties->results.total_clusters = properties->disk->maxcls;
4298
4299 /* Settings based on FAT type */
4300 switch (properties->disk->type)
4301 {
4302 #ifdef SUPPORT_FAT32 // If FAT32 supported.
4303 case FAT32:
4304 properties->private.EndClusterLimit = END_CLUSTER_FAT32;
4305 properties->private.ClusterFailValue = CLUSTER_FAIL_FAT32;
4306 break;
4307 #endif
4308 case FAT16:
4309 properties->private.EndClusterLimit = END_CLUSTER_FAT16;
4310 properties->private.ClusterFailValue = CLUSTER_FAIL_FAT16;
4311 break;
4312 case FAT12:
4313 properties->private.EndClusterLimit = END_CLUSTER_FAT12;
4314 properties->private.ClusterFailValue = CLUSTER_FAIL_FAT16;
4315 break;
4316 }
4317
4318 properties->private.c = 2;
4319
4320 properties->private.curcls = properties->private.c;
4321 ReadFAT(properties->disk, properties->private.c);
4322 }
4323
4324 if(properties->disk == NULL)
4325 {
4326 properties->properties_status = FS_GET_PROPERTIES_DISK_NOT_MOUNTED;
4327 return;
4328 }
4329
4330 if(properties->properties_status != FS_GET_PROPERTIES_STILL_WORKING)
4331 {
4332 return;
4333 }
4334
4335 // sequentially scan through the FAT looking for an empty cluster
4336 for(i=0;i<255;i++)
4337 {
4338 // look at its value
4339 if ( (value = ReadFAT(properties->disk, properties->private.c)) == properties->private.ClusterFailValue)
4340 {
4341 properties->properties_status = FS_GET_PROPERTIES_CLUSTER_FAILURE;
4342 return;
4343 }
4344
4345 // check if empty cluster found
4346 if (value == CLUSTER_EMPTY)
4347 {
4348 properties->results.free_clusters++;
4349 }
4350
4351 properties->private.c++; // check next cluster in FAT
4352 // check if reached last cluster in FAT, re-start from top
4353 if ((value == properties->private.EndClusterLimit) || (properties->private.c >= (properties->results.total_clusters + 2)))
4354 properties->private.c = 2;
4355
4356 // check if full circle done, disk full
4357 if ( properties->private.c == properties->private.curcls)
4358 {
4359 properties->properties_status = FS_GET_PROPERTIES_NO_ERRORS;
4360 return;
4361 }
4362 } // scanning for an empty cluster
4363
4364 properties->properties_status = FS_GET_PROPERTIES_STILL_WORKING;
4365 return;
4366 }
4367 #endif
4368
4369 /************************************************************
4370 Function:
4371 int FSfclose(FSFILE *fo)
4372 Summary:
4373 Update file information and free FSFILE objects
4374 Conditions:
4375 File opened
4376 Input:
4377 fo - Pointer to the file to close
4378 Return Values:
4379 0 - File closed successfully
4380 EOF - Error closing the file
4381 Side Effects:
4382 The FSerrno variable will be changed.
4383 Description:
4384 This function will update the directory entry for the
4385 file pointed to by 'fo' with the information contained
4386 in 'fo,' including the new file size and attributes.
4387 Timestamp information will also be loaded based on the
4388 method selected by the user and written to the entry
4389 as the last modified time and date. The file entry will
4390 then be written to the device. Finally, the memory
4391 used for the specified file object will be freed from
4392 the dynamic heap or the array of FSFILE objects.
4393 Remarks:
4394 A function to flush data to the device without closing the
4395 file can be created by removing the portion of this
4396 function that frees the memory and the line that clears
4397 the write flag.
4398 ************************************************************/
4399
4400 int FSfclose(FSFILE *fo)
4401 {
4402 WORD fHandle;
4403 #ifndef FS_DYNAMIC_MEM
4404 WORD fIndex;
4405 #endif
4406 int error = 72;
4407 #ifdef ALLOW_WRITES
4408 DIRENTRY dir;
4409 #endif
4410
4411 FSerrno = CE_GOOD;
4412 fHandle = fo->entry;
4413
4414 #ifdef ALLOW_WRITES
4415 if(fo->flags.write)
4416 {
4417 if (gNeedDataWrite)
4418 {
4419 if (flushData())
4420 {
4421 FSerrno = CE_WRITE_ERROR;
4422 return EOF;
4423 }
4424 }
4425
4426 // Write the current FAT sector to the disk
4427 WriteFAT (fo->dsk, 0, 0, TRUE);
4428
4429 // Invalidate the currently cached FAT entry so that the next read will
4430 // result in an acutal read from the physical media instead of a read
4431 // from the RAM cache.
4432 gLastFATSectorRead = 0;
4433
4434 // Read the FAT entry from the physical media. This is required because
4435 // some physical media cache the entries in RAM and only write them
4436 // after a time expires for until the sector is accessed again.
4437 ReadFAT (fo->dsk, fo->ccls);
4438
4439 // Get the file entry
4440 dir = LoadDirAttrib(fo, &fHandle);
4441
4442 if (dir == NULL)
4443 {
4444 FSerrno = CE_BADCACHEREAD;
4445 error = EOF;
4446 return error;
4447 }
4448
4449 // update the time
4450 #ifdef INCREMENTTIMESTAMP
4451 IncrementTimeStamp(dir);
4452 #elif defined USERDEFINEDCLOCK
4453 dir->DIR_WrtTime = gTimeWrtTime;
4454 dir->DIR_WrtDate = gTimeWrtDate;
4455 #elif defined USEREALTIMECLOCK
4456 CacheTime();
4457 dir->DIR_WrtTime = gTimeWrtTime;
4458 dir->DIR_WrtDate = gTimeWrtDate;
4459 #endif
4460
4461 dir->DIR_FileSize = fo->size;
4462
4463 dir->DIR_Attr = fo->attributes;
4464
4465 // just write the last entry in
4466 if(Write_File_Entry(fo,&fHandle))
4467 {
4468 // Read the folder entry from the physical media. This is required because
4469 // some physical media cache the entries in RAM and only write them
4470 // after a time expires for until the sector is accessed again.
4471 dir = LoadDirAttrib(fo, &fHandle);
4472 error = 0;
4473 }
4474 else
4475 {
4476 FSerrno = CE_WRITE_ERROR;
4477 error = EOF;
4478 }
4479
4480 // it's now closed
4481 fo->flags.write = FALSE;
4482 }
4483 #endif
4484
4485 #ifdef FS_DYNAMIC_MEM
4486 #ifdef SUPPORT_LFN
4487 FS_free((unsigned char *)fo->utf16LFNptr);
4488 #endif
4489 FS_free((unsigned char *)fo);
4490 #else
4491
4492 for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ )
4493 {
4494 if( fo == &gFileArray[fIndex] )
4495 {
4496 gFileSlotOpen[fIndex] = TRUE;
4497 break;
4498 }
4499 }
4500 #endif
4501
4502 // File opened in read mode
4503 if (error == 72)
4504 error = 0;
4505
4506 return(error);
4507 } // FSfclose
4508
4509
4510 /*******************************************************
4511 Function:
4512 void IncrementTimeStamp(DIRENTRY dir)
4513 Summary:
4514 Automatically set the timestamp to "don't care" data
4515 Conditions:
4516 Should not be called by the user.
4517 Input:
4518 dir - Pointer to directory structure
4519 Return Values:
4520 None
4521 Side Effects:
4522 None
4523 Description:
4524 This function will increment the timestamp variable in
4525 the 'dir' directory entry. This is used for the
4526 don't-care timing method.
4527 Remarks:
4528 None
4529 *******************************************************/
4530 #ifdef INCREMENTTIMESTAMP
4531 void IncrementTimeStamp(DIRENTRY dir)
4532 {
4533 BYTE seconds;
4534 BYTE minutes;
4535 BYTE hours;
4536
4537 BYTE day;
4538 BYTE month;
4539 BYTE year;
4540
4541 seconds = (dir->DIR_WrtTime & 0x1f);
4542 minutes = ((dir->DIR_WrtTime & 0x07E0) >> 5);
4543 hours = ((dir->DIR_WrtTime & 0xF800) >> 11);
4544
4545 day = (dir->DIR_WrtDate & 0x1f);
4546 month = ((dir->DIR_WrtDate & 0x01E0) >> 5);
4547 year = ((dir->DIR_WrtDate & 0xFE00) >> 9);
4548
4549 if(seconds < 29)
4550 {
4551 // Increment number of seconds by 2
4552 // This clock method isn't intended to be accurate anyway
4553 seconds++;
4554 }
4555 else
4556 {
4557 seconds = 0x00;
4558
4559 if(minutes < 59)
4560 {
4561 minutes++;
4562 }
4563 else
4564 {
4565 minutes = 0;
4566
4567 if(hours < 23)
4568 {
4569 hours++;
4570 }
4571 else
4572 {
4573 hours = 0;
4574 if(day < 30)
4575 {
4576 day++;
4577 }
4578 else
4579 {
4580 day = 1;
4581
4582 if(month < 12)
4583 {
4584 month++;
4585 }
4586 else
4587 {
4588 month = 1;
4589 // new year
4590 year++;
4591 // This is only valid until 2107
4592 }
4593 }
4594 }
4595 }
4596 }
4597
4598 dir->DIR_WrtTime = (WORD)(seconds);
4599 dir->DIR_WrtTime |= ((WORD)(minutes) << 5);
4600 dir->DIR_WrtTime |= ((WORD)(hours) << 11);
4601
4602 dir->DIR_WrtDate = (WORD)(day);
4603 dir->DIR_WrtDate |= ((WORD)(month) << 5);
4604 dir->DIR_WrtDate |= ((WORD)(year) << 9);
4605 }
4606 #endif
4607
4608 /*****************************************************************
4609 Function:
4610 BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle)
4611 Summary:
4612 Fill a file object with specified dir entry data
4613 Conditions:
4614 This function should not be called by the user.
4615 Input:
4616 fo - Pointer to file structure
4617 fHandle - Passed member's location
4618 Return Values:
4619 FOUND - Operation successful
4620 NOT_FOUND - Operation failed
4621 Side Effects:
4622 None
4623 Description:
4624 This function will cache the sector of directory entries
4625 in the directory pointed to by the dirclus value in
4626 the FSFILE object 'fo' that contains the entry that
4627 corresponds to the fHandle offset. It will then copy
4628 the file information for that entry into the 'fo' FSFILE
4629 object.
4630 Remarks:
4631 None.
4632 *****************************************************************/
4633
4634 BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle)
4635 {
4636 DIRENTRY dir;
4637 BYTE index, a;
4638 BYTE character;
4639 BYTE status;
4640 BYTE test = 0;
4641
4642 // Get the entry
4643 if (((*fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) == 0) && (*fHandle != 0)) // 4-bit mask because 16-root entries max per sector
4644 {
4645 fo->dirccls = fo->dirclus;
4646 dir = Cache_File_Entry(fo, fHandle, TRUE);
4647 }
4648 else
4649 {
4650 dir = Cache_File_Entry (fo, fHandle, FALSE);
4651 }
4652
4653
4654 // Make sure there is a directory left
4655 if(dir == (DIRENTRY)NULL)
4656 {
4657 status = NO_MORE;
4658 }
4659 else
4660 {
4661 // Read the first char of the file name
4662 a = dir->DIR_Name[0];
4663
4664 // Check for empty or deleted directory
4665 if ( a == DIR_DEL)
4666 {
4667 status = NOT_FOUND;
4668 }
4669 else if ( a == DIR_EMPTY)
4670 {
4671 status = NO_MORE;
4672 }
4673 else
4674 {
4675 // Get the attributes
4676 a = dir->DIR_Attr;
4677
4678 // print the file name and extension
4679 for (index=0; index < DIR_NAMESIZE; index++)
4680 {
4681 character = dir->DIR_Name[index];
4682 character = (BYTE)toupper(character);
4683 fo->name[test++] = character;
4684 }
4685
4686 // Get the attributes
4687 a = dir->DIR_Attr;
4688
4689 // its possible to have an extension in a directory
4690 character = dir->DIR_Extension[0];
4691
4692 // Get the file extension if its there
4693 for (index=0; index < DIR_EXTENSION; index++)
4694 {
4695 character = dir->DIR_Extension[index];
4696 character = (BYTE)toupper(character);
4697 fo->name[test++] = character;
4698 }
4699
4700 // done and done with the name
4701 // fo->name[++test] = (BYTE)'\0';
4702
4703 // Now store the identifier
4704 fo->entry = *fHandle;
4705
4706 // see if we are still a good file
4707 a = dir->DIR_Name[0];
4708
4709 if(a == DIR_DEL)
4710 status = NOT_FOUND;
4711 else
4712 status = FOUND;
4713
4714 // Now store the size
4715 fo->size = (dir->DIR_FileSize);
4716
4717 fo->cluster = GetFullClusterNumber(dir); // Get Complete Cluster number.
4718
4719 /// -Get and store the attributes
4720 a = dir->DIR_Attr;
4721 fo->attributes = a;
4722
4723 // get the date and time
4724 if ((a & ATTR_DIRECTORY) != 0)
4725 {
4726 fo->time = dir->DIR_CrtTime;
4727 fo->date = dir->DIR_CrtDate;
4728 }
4729 else
4730 {
4731 fo->time = dir->DIR_WrtTime;
4732 fo->date = dir->DIR_WrtDate;
4733 }
4734
4735 }// deleted directory
4736 }// Ensure we are still good
4737 return(status);
4738 } // Fill_File_Object
4739
4740 /*****************************************************************
4741 Function:
4742 BYTE Fill_LFN_Object(FILEOBJ fo, LFN_ENTRY *lfno, WORD *fHandle)
4743 Summary:
4744 Fill a LFN object with specified entry data
4745 Conditions:
4746 This function should not be called by the user.
4747 Input:
4748 fo - Pointer to file structure
4749 lfno - Pointer to Long File Name Object
4750 fHandle - Passed member's location
4751 Return Values:
4752 FOUND - Operation successful
4753 NOT_FOUND - Operation failed
4754 Side Effects:
4755 None
4756 Description:
4757 This function will cache the sector of LFN entries
4758 in the directory pointed to by the dirclus value in
4759 the FSFILE object 'fo' that contains the entry that
4760 corresponds to the fHandle offset. It will then copy
4761 the file information for that entry into the 'fo' FSFILE
4762 object.
4763 Remarks:
4764 None.
4765 *****************************************************************/
4766 #if defined(SUPPORT_LFN)
4767 BYTE Fill_LFN_Object(FILEOBJ fo, LFN_ENTRY *lfno, WORD *fHandle)
4768 {
4769 DIRENTRY dir;
4770 BYTE tempVariable;
4771 BYTE *src,*dst;
4772 BYTE status;
4773
4774 // Get the entry
4775 if (((*fHandle & MASK_MAX_FILE_ENTRY_LIMIT_BITS) == 0) && (*fHandle != 0)) // 4-bit mask because 16-root entries max per sector
4776 {
4777 fo->dirccls = fo->dirclus;
4778 dir = Cache_File_Entry(fo, fHandle, TRUE);
4779 }
4780 else
4781 {
4782 dir = Cache_File_Entry (fo, fHandle, FALSE);
4783 }
4784
4785
4786 // Make sure there is a directory left
4787 if(dir == (DIRENTRY)NULL)
4788 {
4789 status = NO_MORE;
4790 }
4791 else
4792 {
4793 // Read the first char of the file name
4794 tempVariable = dir->DIR_Name[0];
4795
4796 // Check for empty or deleted directory
4797 if ( tempVariable == DIR_DEL)
4798 {
4799 status = NOT_FOUND;
4800 }
4801 else if ( tempVariable == DIR_EMPTY)
4802 {
4803 status = NO_MORE;
4804 }
4805 else
4806 {
4807 status = FOUND;
4808
4809 dst = (BYTE *)lfno;
4810 src = (BYTE *)dir;
4811
4812 // Copy the entry in the lfno object
4813 for(tempVariable = 0;tempVariable < 32;tempVariable++)
4814 {
4815 *dst++ = *src++;
4816 }
4817 }// deleted directory
4818 }// Ensure we are still good
4819 return(status);
4820 } // Fill_File_Object
4821 #endif
4822 /************************************************************************
4823 Function:
4824 DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle)
4825 Summary:
4826 Load file information from a directory entry and cache the entry
4827 Conditions:
4828 This function should not be called by the user.
4829 Input:
4830 fo - Pointer to file structure
4831 fHandle - Information location
4832 Return Values:
4833 DIRENTRY - Pointer to the directory entry
4834 NULL - Directory entry could not be loaded
4835 Side Effects:
4836 None
4837 Description:
4838 This function will cache the sector of directory entries
4839 in the directory pointed to by the dirclus value in
4840 the FSFILE object 'fo' that contains the entry that
4841 corresponds to the fHandle offset. It will then return a pointer
4842 to the directory entry in the global data buffer.
4843 Remarks:
4844 None.
4845 ************************************************************************/
4846
4847 DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle)
4848 {
4849 DIRENTRY dir;
4850 BYTE a;
4851
4852 fo->dirccls = fo->dirclus;
4853 // Get the entry
4854 dir = Cache_File_Entry( fo, fHandle, TRUE);
4855 if (dir == NULL)
4856 return NULL;
4857
4858 // Read the first char of the file name
4859 a = dir->DIR_Name[0];
4860
4861 // Make sure there is a directory left
4862 if(a == DIR_EMPTY)
4863 dir = (DIRENTRY)NULL;
4864
4865 if(dir != (DIRENTRY)NULL)
4866 {
4867 // Check for empty or deleted directory
4868 if ( a == DIR_DEL)
4869 dir = (DIRENTRY)NULL;
4870 else
4871 {
4872 // Get the attributes
4873 a = dir->DIR_Attr;
4874
4875 // scan through all the long dir entries
4876 while(a == ATTR_LONG_NAME)
4877 {
4878 (*fHandle)++;
4879 dir = Cache_File_Entry( fo, fHandle, FALSE);
4880 if (dir == NULL)
4881 return NULL;
4882 a = dir->DIR_Attr;
4883 } // long file name while loop
4884 } // deleted dir
4885 }// Ensure we are still good
4886
4887 return(dir);
4888 } // LoadDirAttrib
4889
4890
4891 /**************************************************************************
4892 Function:
4893 CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters)
4894 Summary:
4895 Erase a file
4896 Conditions:
4897 This function should not be called by the user.
4898 Input:
4899 fo - Pointer to file structure
4900 fHandle - Location of file information
4901 EraseClusters - If set to TRUE, delete the corresponding cluster of file
4902 Return Values:
4903 CE_GOOD - File erased successfully
4904 CE_FILE_NOT_FOUND - Could not find the file on the card
4905 CE_ERASE_FAIL - Internal Card erase failed
4906 Side Effects:
4907 None
4908 Description:
4909 This function will cache the sector of directory entries in the directory
4910 pointed to by the dirclus value in the FSFILE object 'fo' that contains
4911 the entry that corresponds to the fHandle offset. It will then mark that
4912 entry as deleted. If the EraseClusters argument is TRUE, the chain of
4913 clusters for that file will be marked as unused in the FAT by the
4914 FAT_erase_cluster_chain function.
4915 Remarks:
4916 None.
4917 **************************************************************************/
4918
4919 #ifdef ALLOW_WRITES
4920 CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters)
4921 {
4922 DIRENTRY dir;
4923 BYTE a;
4924 CETYPE status = CE_GOOD;
4925 DWORD clus = 0;
4926 DISK * disk;
4927
4928 BYTE numberOfFileEntries;
4929 BOOL forFirstTime = TRUE;
4930 #if defined(SUPPORT_LFN)
4931 BYTE tempCalc1;
4932 #endif
4933
4934 disk = fo->dsk;
4935
4936 #if defined(SUPPORT_LFN)
4937
4938 fileNameLength = fo->utf16LFNlength;
4939
4940 // Find the number of entries of LFN in the root directory
4941 if(fileNameLength)
4942 {
4943 tempCalc1 = fileNameLength % 13;
4944
4945 numberOfFileEntries = fileNameLength/13;
4946
4947 if(tempCalc1 || (fileNameLength < 13))
4948 {
4949 numberOfFileEntries = numberOfFileEntries + 2;
4950 }
4951 else
4952 {
4953 numberOfFileEntries++;
4954 }
4955 }
4956 else
4957 #endif
4958 {
4959 numberOfFileEntries = 1;
4960 }
4961
4962 FSerrno = CE_ERASE_FAIL;
4963
4964 // delete all the entries of LFN in root directory
4965 while(numberOfFileEntries--)
4966 {
4967 // reset the cluster
4968 fo->dirccls = fo->dirclus;
4969
4970 // load the sector
4971 dir = Cache_File_Entry(fo, fHandle, TRUE);
4972
4973 if (dir == NULL)
4974 {
4975 return CE_BADCACHEREAD;
4976 }
4977
4978 // Fill up the File Object with the information pointed to by fHandle
4979 a = dir->DIR_Name[0];
4980
4981 // see if there is something in the dir
4982 if((dir == (DIRENTRY)NULL) || (a == DIR_EMPTY) || (a == DIR_DEL))
4983 {
4984 status = CE_FILE_NOT_FOUND;
4985 break;
4986 }
4987 else
4988 {
4989 /* 8.3 File Name - entry*/
4990 dir->DIR_Name[0] = DIR_DEL; // mark as deleted
4991
4992 if(!(Write_File_Entry( fo, fHandle)))
4993 {
4994 status = CE_ERASE_FAIL;
4995 break;
4996 }
4997 }
4998
4999 if(forFirstTime)
5000 {
5001 // Get the starting cluster
5002 clus = GetFullClusterNumber(dir); // Get Complete Cluster number.
5003 forFirstTime = FALSE;
5004 }
5005
5006 *fHandle = *fHandle - 1;
5007 }
5008
5009 if(status == CE_GOOD)
5010 {
5011 if (clus != FatRootDirClusterValue) //
5012 {
5013 // If 'EraseClusters' is set to TRUE, erase the cluster chain corresponding to file
5014 if(EraseClusters)
5015 {
5016 /* Now remove the cluster allocation from the FAT */
5017 status = ((FAT_erase_cluster_chain(clus, disk)) ? CE_GOOD : CE_ERASE_FAIL);
5018 }
5019 }
5020
5021 FSerrno = status;
5022 }
5023
5024 return (status);
5025 }
5026 #endif
5027
5028 /***************************************************************
5029 Function:
5030 int FSrename (const rom char * fileName, FSFILE * fo)
5031 Summary:
5032 Change the name of a file or directory
5033 Conditions:
5034 File opened.
5035 Input:
5036 fileName - The new name of the file
5037 fo - The file to rename
5038 Return Values:
5039 0 - File was renamed successfully
5040 EOF - File was not renamed
5041 Side Effects:
5042 The FSerrno variable will be changed.
5043 Description:
5044 The FSrename function will rename a file. First, it will
5045 search through the current working directory to ensure the
5046 specified new filename is not already in use. If it isn't,
5047 the new filename will be written to the file entry of the
5048 file pointed to by 'fo.'
5049 Remarks:
5050 None
5051 ***************************************************************/
5052
5053 #ifdef ALLOW_WRITES
5054
5055 int FSrename (const char * fileName, FSFILE * fo)
5056 {
5057 WORD fHandle;
5058 FSFILE tempFo1,tempFo2;
5059 DIRENTRY dir;
5060 #ifdef SUPPORT_LFN
5061 DWORD TempMsbCluster;
5062 #else
5063 BYTE j;
5064 #endif
5065
5066 FSerrno = CE_GOOD;
5067
5068 if (MDD_WriteProtectState())
5069 {
5070 FSerrno = CE_WRITE_PROTECTED;
5071 return (-1);
5072 }
5073
5074 // copy file object over
5075 FileObjectCopy(&tempFo1, fo);
5076
5077 //Format the source string
5078 if(!FormatFileName(fileName, &tempFo1, 0) )
5079 {
5080 FSerrno = CE_INVALID_FILENAME;
5081 return -1;
5082 }
5083
5084 tempFo1.entry = 0;
5085
5086 // start at the current directory
5087 tempFo1.dirclus = cwdptr->dirclus;
5088 tempFo1.dirccls = cwdptr->dirccls;
5089
5090 // copy file object over
5091 FileObjectCopy(&tempFo2, &tempFo1);
5092
5093 // See if the file is found
5094 if(FILEfind (&tempFo2, &tempFo1, LOOK_FOR_MATCHING_ENTRY, 0) == CE_FILE_NOT_FOUND)
5095 {
5096 fHandle = fo->entry;
5097
5098 #ifdef SUPPORT_LFN
5099
5100 if(CE_GOOD != FILEerase(fo, &fHandle, FALSE))
5101 {
5102 FSerrno = CE_ERASE_FAIL;
5103 return -1;
5104 }
5105
5106 // Create the new entry as per the user requested name
5107 FSerrno = CreateFileEntry (&tempFo1, &fHandle, tempFo1.attributes, FALSE);
5108
5109 // load the file entry so the new cluster can be linked to it
5110 dir = LoadDirAttrib(&tempFo1, &fHandle);
5111
5112 // Now update the new cluster
5113 dir->DIR_FstClusLO = (fo->cluster & 0x0000FFFF);
5114
5115 #ifdef SUPPORT_FAT32 // If FAT32 supported.
5116 // Get the higher part of cluster and store it in directory entry.
5117 TempMsbCluster = (fo->cluster & 0x0FFF0000); // Since only 28 bits usedin FAT32. Mask the higher MSB nibble.
5118 TempMsbCluster = TempMsbCluster >> 16; // Get the date into Lsb place.
5119 dir->DIR_FstClusHI = TempMsbCluster;
5120 #else // If FAT32 support not enabled
5121 TempMsbCluster = 0; // Just to avoid compiler warnigng.
5122 dir->DIR_FstClusHI = 0;
5123 #endif
5124
5125 // Update the file size
5126 dir->DIR_FileSize = fo->size;
5127
5128 // now write it
5129 if(Write_File_Entry(&tempFo1, &fHandle) != TRUE)
5130 {
5131 FSerrno = CE_WRITE_ERROR;
5132 return -1;
5133 }
5134
5135 tempFo1.size = fo->size;
5136
5137 // copy file object over
5138 FileObjectCopy(fo, &tempFo1);
5139
5140 #else
5141
5142 // Get the file entry
5143 dir = LoadDirAttrib(fo, &fHandle);
5144
5145 for (j = 0; j < 11; j++)
5146 {
5147 fo->name[j] = tempFo1.name[j];
5148 dir->DIR_Name[j] = tempFo1.name[j];
5149 }
5150
5151 // just write the last entry in
5152 if(!Write_File_Entry(fo,&fHandle))
5153 {
5154 FSerrno = CE_WRITE_ERROR;
5155 return -1;
5156 }
5157
5158 #endif
5159 }
5160 else
5161 {
5162 FSerrno = CE_FILENAME_EXISTS;
5163 return -1;
5164 }
5165
5166 return 0;
5167 }
5168
5169 /***************************************************************
5170 Function:
5171 int wFSrename (const rom unsigned short int * fileName, FSFILE * fo)
5172 Summary:
5173 Change the name of a file or directory to the UTF16 input fileName
5174 Conditions:
5175 File opened.
5176 Input:
5177 fileName - The new name of the file
5178 fo - The file to rename
5179 Return Values:
5180 0 - File was renamed successfully
5181 EOF - File was not renamed
5182 Side Effects:
5183 The FSerrno variable will be changed.
5184 Description:
5185 The wFSrename function will rename a file. First, it will
5186 search through the current working directory to ensure the
5187 specified new UTF16 filename is not already in use. If it isn't,
5188 the new filename will be written to the file entry of the
5189 file pointed to by 'fo.'
5190 Remarks:
5191 None
5192 ***************************************************************/
5193 #ifdef SUPPORT_LFN
5194 int wFSrename (const unsigned short int * fileName, FSFILE * fo)
5195 {
5196 int result;
5197 utfModeFileName = TRUE;
5198 result = FSrename ((const char *)fileName,fo);
5199 utfModeFileName = FALSE;
5200 return result;
5201 }
5202 #endif
5203
5204 #endif // Allow writes
5205
5206 /*********************************************************************
5207 Function:
5208 FSFILE * wFSfopen (const unsigned short int * fileName, const char *mode)
5209 Summary:
5210 Open a UTF16 file.
5211 Conditions:
5212 For read modes, file exists; FSInit performed
5213 Input:
5214 fileName - The name of the file to open
5215 mode -
5216 - WRITE - Create a new file or replace an existing file
5217 - READ - Read data from an existing file
5218 - APPEND - Append data to an existing file
5219 - WRITEPLUS - Create a new file or replace an existing file (reads also enabled)
5220 - READPLUS - Read data from an existing file (writes also enabled)
5221 - APPENDPLUS - Append data to an existing file (reads also enabled)
5222 Return Values:
5223 FSFILE * - The pointer to the file object
5224 NULL - The file could not be opened
5225 Side Effects:
5226 The FSerrno variable will be changed.
5227 Description:
5228 This function will open a file or directory. First, RAM in the
5229 dynamic heap or static array will be allocated to a new FSFILE object.
5230 Then, the specified file name will be formatted to ensure that it's
5231 in 8.3 format or LFN format. Next, the FILEfind function will be used
5232 to search for the specified file name. If the name is found, one of three
5233 things will happen: if the file was opened in read mode, its file
5234 info will be loaded using the FILEopen function; if it was opened in
5235 write mode, it will be erased, and a new file will be constructed in
5236 its place; if it was opened in append mode, its file info will be
5237 loaded with FILEopen and the current location will be moved to the
5238 end of the file using the FSfseek function. If the file was not
5239 found by FILEfind, a new file will be created if the mode was specified as
5240 a write or append mode. In these cases, a pointer to the heap or
5241 static FSFILE object array will be returned. If the file was not
5242 found and the mode was specified as a read mode, the memory
5243 allocated to the file will be freed and the NULL pointer value
5244 will be returned.
5245 Remarks:
5246 None.
5247 *********************************************************************/
5248 #ifdef SUPPORT_LFN
5249 FSFILE * wFSfopen( const unsigned short int * fileName, const char *mode )
5250 {
5251 FSFILE *result;
5252 utfModeFileName = TRUE;
5253 result = FSfopen((const char *)fileName,mode);
5254 utfModeFileName = FALSE;
5255 return result;
5256 }
5257 #endif
5258
5259 /*********************************************************************
5260 Function:
5261 FSFILE * FSfopen (const char * fileName, const char *mode)
5262 Summary:
5263 Open a Ascii file
5264 Conditions:
5265 For read modes, file exists; FSInit performed
5266 Input:
5267 fileName - The name of the file to open
5268 mode -
5269 - WRITE - Create a new file or replace an existing file
5270 - READ - Read data from an existing file
5271 - APPEND - Append data to an existing file
5272 - WRITEPLUS - Create a new file or replace an existing file (reads also enabled)
5273 - READPLUS - Read data from an existing file (writes also enabled)
5274 - APPENDPLUS - Append data to an existing file (reads also enabled)
5275 Return Values:
5276 FSFILE * - The pointer to the file object
5277 NULL - The file could not be opened
5278 Side Effects:
5279 The FSerrno variable will be changed.
5280 Description:
5281 This function will open a file or directory. First, RAM in the
5282 dynamic heap or static array will be allocated to a new FSFILE object.
5283 Then, the specified file name will be formatted to ensure that it's
5284 in 8.3 format or LFN format. Next, the FILEfind function will be used
5285 to search for the specified file name. If the name is found, one of three
5286 things will happen: if the file was opened in read mode, its file
5287 info will be loaded using the FILEopen function; if it was opened in
5288 write mode, it will be erased, and a new file will be constructed in
5289 its place; if it was opened in append mode, its file info will be
5290 loaded with FILEopen and the current location will be moved to the
5291 end of the file using the FSfseek function. If the file was not
5292 found by FILEfind, a new file will be created if the mode was specified as
5293 a write or append mode. In these cases, a pointer to the heap or
5294 static FSFILE object array will be returned. If the file was not
5295 found and the mode was specified as a read mode, the memory
5296 allocated to the file will be freed and the NULL pointer value
5297 will be returned.
5298 Remarks:
5299 None.
5300 *********************************************************************/
5301
5302 FSFILE * FSfopen( const char * fileName, const char *mode )
5303 {
5304 FILEOBJ filePtr;
5305 #ifndef FS_DYNAMIC_MEM
5306 int fIndex;
5307 #endif
5308 BYTE ModeC;
5309 WORD fHandle;
5310 CETYPE final;
5311
5312 #ifdef FS_DYNAMIC_MEM
5313 filePtr = (FILEOBJ) FS_malloc(sizeof(FSFILE));
5314 #else
5315
5316 filePtr = NULL;
5317
5318 //Pick available file structure
5319 for( fIndex = 0; fIndex < FS_MAX_FILES_OPEN; fIndex++ )
5320 {
5321 if( gFileSlotOpen[fIndex] ) //this slot is available
5322 {
5323 gFileSlotOpen[fIndex] = FALSE;
5324 filePtr = &gFileArray[fIndex];
5325 break;
5326 }
5327 }
5328
5329 if( filePtr == NULL )
5330 {
5331 FSerrno = CE_TOO_MANY_FILES_OPEN;
5332 return NULL; //no file structure slot available
5333 }
5334 #endif
5335
5336 #if defined(SUPPORT_LFN)
5337 #if defined(FS_DYNAMIC_MEM)
5338 filePtr -> utf16LFNptr = (unsigned short int *)FS_malloc(514);
5339 #else
5340 filePtr->utf16LFNptr = &lfnData[fIndex][0];
5341 #endif
5342 #endif
5343
5344 //Format the source string.
5345 if( !FormatFileName(fileName, filePtr, 0) )
5346 {
5347 #ifdef FS_DYNAMIC_MEM
5348 #if defined(SUPPORT_LFN)
5349 FS_free((unsigned char *)filePtr->utf16LFNptr);
5350 #endif
5351 FS_free( (unsigned char *)filePtr );
5352 #else
5353 gFileSlotOpen[fIndex] = TRUE; //put this slot back to the pool
5354 #endif
5355
5356 FSerrno = CE_INVALID_FILENAME;
5357 return NULL; //bad filename
5358 }
5359
5360 //Read the mode character
5361 ModeC = mode[0];
5362
5363 filePtr->dsk = &gDiskData;
5364 filePtr->cluster = 0;
5365 filePtr->ccls = 0;
5366 filePtr->entry = 0;
5367 filePtr->attributes = ATTR_ARCHIVE;
5368
5369 // start at the current directory
5370 #ifdef ALLOW_DIRS
5371 filePtr->dirclus = cwdptr->dirclus;
5372 filePtr->dirccls = cwdptr->dirccls;
5373 #else
5374 filePtr->dirclus = FatRootDirClusterValue;
5375 filePtr->dirccls = FatRootDirClusterValue;
5376 #endif
5377
5378 // copy file object over
5379 FileObjectCopy(&gFileTemp, filePtr);
5380
5381 // See if the file is found
5382 if(FILEfind (filePtr, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0) == CE_GOOD)
5383 {
5384 // File is Found
5385 switch(ModeC)
5386 {
5387 #ifdef ALLOW_WRITES
5388 case 'w':
5389 case 'W':
5390 {
5391 // File exists, we want to create a new one, remove it first
5392 fHandle = filePtr->entry;
5393 final = FILEerase(filePtr, &fHandle, TRUE);
5394
5395 if (final == CE_GOOD)
5396 {
5397 // now create a new one
5398 final = CreateFileEntry (filePtr, &fHandle, 0, TRUE);
5399
5400 if (final == CE_GOOD)
5401 {
5402 final = FILEopen (filePtr, &fHandle, 'w');
5403
5404 if (filePtr->attributes & ATTR_DIRECTORY)
5405 {
5406 FSerrno = CE_INVALID_ARGUMENT;
5407 final = 0xFF;
5408 }
5409
5410 if (final == CE_GOOD)
5411 {
5412 final = FSfseek (filePtr, 0, SEEK_END);
5413 if (mode[1] == '+')
5414 filePtr->flags.read = 1;
5415 }
5416 }
5417 }
5418 break;
5419 }
5420
5421 case 'A':
5422 case 'a':
5423 {
5424 if(filePtr->size != 0)
5425 {
5426 fHandle = filePtr->entry;
5427
5428 final = FILEopen (filePtr, &fHandle, 'w');
5429
5430 if (filePtr->attributes & ATTR_DIRECTORY)
5431 {
5432 FSerrno = CE_INVALID_ARGUMENT;
5433 final = 0xFF;
5434 }
5435
5436 if (final == CE_GOOD)
5437 {
5438 final = FSfseek (filePtr, 0, SEEK_END);
5439 if (final != CE_GOOD)
5440 FSerrno = CE_SEEK_ERROR;
5441 else
5442 ReadFAT (&gDiskData, filePtr->ccls);
5443 if (mode[1] == '+')
5444 filePtr->flags.read = 1;
5445 }
5446 }
5447 else
5448 {
5449 fHandle = filePtr->entry;
5450 final = FILEerase(filePtr, &fHandle, TRUE);
5451
5452 if (final == CE_GOOD)
5453 {
5454 // now create a new one
5455 final = CreateFileEntry (filePtr, &fHandle, 0, TRUE);
5456
5457 if (final == CE_GOOD)
5458 {
5459 final = FILEopen (filePtr, &fHandle, 'w');
5460
5461 if (filePtr->attributes & ATTR_DIRECTORY)
5462 {
5463 FSerrno = CE_INVALID_ARGUMENT;
5464 final = 0xFF;
5465 }
5466
5467 if (final == CE_GOOD)
5468 {
5469 final = FSfseek (filePtr, 0, SEEK_END);
5470 if (final != CE_GOOD)
5471 FSerrno = CE_SEEK_ERROR;
5472 if (mode[1] == '+')
5473 filePtr->flags.read = 1;
5474 }
5475 }
5476 }
5477 }
5478 break;
5479 }
5480 #endif
5481 case 'R':
5482 case 'r':
5483 {
5484 fHandle = filePtr->entry;
5485
5486 final = FILEopen (filePtr, &fHandle, 'r');
5487 #ifdef ALLOW_WRITES
5488 if ((mode[1] == '+') && !(filePtr->attributes & ATTR_DIRECTORY))
5489 filePtr->flags.write = 1;
5490 #endif
5491 break;
5492 }
5493
5494 default:
5495 FSerrno = CE_INVALID_ARGUMENT;
5496 final = 0xFF;; //indicate error condition
5497 break;
5498 }
5499 }
5500 else
5501 {
5502 #ifdef ALLOW_WRITES
5503 // the file was not found, reset to the default asked
5504 FileObjectCopy(filePtr, &gFileTemp);
5505
5506 // File is not Found
5507 if((ModeC == 'w') || (ModeC == 'W') || (ModeC == 'a') || (ModeC == 'A'))
5508 {
5509 // use the user requested name
5510 fHandle = 0;
5511 final = CreateFileEntry (filePtr, &fHandle, 0, TRUE);
5512
5513 if (final == CE_GOOD)
5514 {
5515 final = FILEopen (filePtr, &fHandle, 'w');
5516 if (filePtr->attributes & ATTR_DIRECTORY)
5517 {
5518 FSerrno = CE_INVALID_ARGUMENT;
5519 final = 0xFF;
5520 }
5521
5522 if (final == CE_GOOD)
5523 {
5524 final = FSfseek (filePtr, 0, SEEK_END);
5525 if (final != CE_GOOD)
5526 FSerrno = CE_SEEK_ERROR;
5527 if (mode[1] == '+')
5528 filePtr->flags.read = 1;
5529 }
5530 }
5531 }
5532 else
5533 #endif
5534 final = CE_FILE_NOT_FOUND;
5535 }
5536
5537 if (MDD_WriteProtectState())
5538 {
5539 filePtr->flags.write = 0;;
5540 }
5541
5542 #ifdef FS_DYNAMIC_MEM
5543 if( final != CE_GOOD )
5544 {
5545 #ifdef SUPPORT_LFN
5546 FS_free((unsigned char *)filePtr->utf16LFNptr);
5547 #endif
5548 FS_free( (unsigned char *)filePtr );
5549 filePtr = NULL;
5550 }
5551 #else
5552 if( final != CE_GOOD )
5553 {
5554 gFileSlotOpen[fIndex] = TRUE; //put this slot back to the pool
5555 filePtr = NULL;
5556 }
5557 #endif
5558 else
5559 {
5560 FSerrno = CE_GOOD;
5561 }
5562
5563 return filePtr;
5564 }
5565
5566 /*******************************************************************
5567 Function:
5568 long FSftell (FSFILE * fo)
5569 Summary:
5570 Determine the current location in a file
5571 Conditions:
5572 File opened
5573 Input:
5574 fo - Pointer to file structure
5575 Return: Current location in the file
5576 Side Effects:
5577 The FSerrno variable will be changed
5578 Description:
5579 The FSftell function will return the current position in the
5580 file pointed to by 'fo' by returning the 'seek' variable in the
5581 FSFILE object, which is used to keep track of the absolute
5582 location of the current position in the file.
5583 Remarks:
5584 None
5585 *******************************************************************/
5586
5587 long FSftell (FSFILE * fo)
5588 {
5589 FSerrno = CE_GOOD;
5590 return (fo->seek);
5591 }
5592
5593
5594 #ifdef ALLOW_WRITES
5595
5596 /*********************************************************************
5597 Function:
5598 int FSremove (const char * fileName)
5599 Summary:
5600 Delete a Ascii file
5601 Conditions:
5602 File not opened, file exists
5603 Input:
5604 fileName - Name of the file to erase
5605 Return Values:
5606 0 - File removed
5607 EOF - File was not removed
5608 Side Effects:
5609 The FSerrno variable will be changed.
5610 Description:
5611 The FSremove function will attempt to find the specified file with
5612 the FILEfind function. If the file is found, it will be erased
5613 using the FILEerase function. The user can also provide ascii alias name
5614 of the ascii long file name as the input to this function to get it erased
5615 from the memory.
5616 Remarks:
5617 None
5618 **********************************************************************/
5619
5620 int FSremove (const char * fileName)
5621 {
5622 FILEOBJ fo = &tempCWDobj;
5623
5624 #ifdef SUPPORT_LFN
5625 FSFILE cwdTemp;
5626 char tempArray[514];
5627 LFN_ENTRY *lfno;
5628 WORD prevHandle;
5629 unsigned short int i = 0;
5630 #endif
5631 FSerrno = CE_GOOD;
5632
5633 if (MDD_WriteProtectState())
5634 {
5635 FSerrno = CE_WRITE_PROTECTED;
5636 return (-1);
5637 }
5638
5639 //Format the source string
5640 #if defined(SUPPORT_LFN)
5641 fo->utf16LFNptr = (unsigned short int *)&tempArray[0];
5642 #endif
5643
5644 if( !FormatFileName(fileName, fo, 0) )
5645 {
5646 FSerrno = CE_INVALID_FILENAME;
5647 return -1;
5648 }
5649
5650 fo->dsk = &gDiskData;
5651 fo->cluster = 0;
5652 fo->ccls = 0;
5653 fo->entry = 0;
5654 fo->attributes = ATTR_ARCHIVE;
5655
5656 #ifndef ALLOW_DIRS
5657 // start at the root directory
5658 fo->dirclus = FatRootDirClusterValue;
5659 fo->dirccls = FatRootDirClusterValue;
5660 #else
5661 fo->dirclus = cwdptr->dirclus;
5662 fo->dirccls = cwdptr->dirccls;
5663 #endif
5664
5665 // copy file object over
5666 FileObjectCopy(&gFileTemp, fo);
5667
5668 // See if the file is found
5669 if (FILEfind (fo, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0) != CE_GOOD)
5670 {
5671 FSerrno = CE_FILE_NOT_FOUND;
5672 return -1;
5673 }
5674
5675 if (fo->attributes & ATTR_DIRECTORY)
5676 {
5677 FSerrno = CE_DELETE_DIR;
5678 return -1;
5679 }
5680
5681 // Find the long file name assosciated with the short file name if present
5682 #ifdef SUPPORT_LFN
5683 if(!fo->utf16LFNlength)
5684 {
5685 FileObjectCopy (&cwdTemp, fo);
5686 prevHandle = fo->entry - 1;
5687 lfno = (LFN_ENTRY *)Cache_File_Entry (fo, &prevHandle, FALSE);
5688
5689 while((lfno->LFN_Attribute == ATTR_LONG_NAME) && (lfno->LFN_SequenceNo != DIR_DEL)
5690 && (lfno->LFN_SequenceNo != DIR_EMPTY))
5691 {
5692
5693 i = i + MAX_UTF16_CHARS_IN_LFN_ENTRY;
5694
5695 prevHandle = prevHandle - 1;
5696 lfno = (LFN_ENTRY *)Cache_File_Entry (fo, &prevHandle, FALSE);
5697 }
5698
5699 FileObjectCopy (fo, &cwdTemp);
5700
5701 // Find the length of LFN file
5702 fo->utf16LFNlength = i;
5703 }
5704 #endif
5705
5706 // Erase the file
5707 if( FILEerase(fo, &fo->entry, TRUE) == CE_GOOD )
5708 return 0;
5709 else
5710 {
5711 FSerrno = CE_ERASE_FAIL;
5712 return -1;
5713 }
5714 }
5715
5716 /*********************************************************************
5717 Function:
5718 int wFSremove (const unsigned short int * fileName)
5719 Summary:
5720 Delete a UTF16 file
5721 Conditions:
5722 File not opened, file exists
5723 Input:
5724 fileName - Name of the file to erase
5725 Return Values:
5726 0 - File removed
5727 EOF - File was not removed
5728 Side Effects:
5729 The FSerrno variable will be changed.
5730 Description:
5731 The wFSremove function will attempt to find the specified UTF16 file
5732 name with the FILEfind function. If the file is found, it will be erased
5733 using the FILEerase function.
5734 Remarks:
5735 None
5736 **********************************************************************/
5737 #ifdef SUPPORT_LFN
5738 int wFSremove (const unsigned short int * fileName)
5739 {
5740 int result;
5741 utfModeFileName = TRUE;
5742 result = FSremove ((const char *)fileName);
5743 utfModeFileName = FALSE;
5744 return result;
5745 }
5746 #endif
5747
5748 #endif
5749
5750 /*********************************************************
5751 Function:
5752 void FSrewind (FSFILE * fo)
5753 Summary:
5754 Set the current position in a file to the beginning
5755 Conditions:
5756 File opened.
5757 Input:
5758 fo - Pointer to file structure
5759 Return Values:
5760 None
5761 Side Effects:
5762 None.
5763 Description:
5764 The FSrewind funciton will reset the position of the
5765 specified file to the beginning of the file. This
5766 functionality is faster than using FSfseek to reset
5767 the position in the file.
5768 Remarks:
5769 None.
5770 *********************************************************/
5771
5772 void FSrewind (FSFILE * fo)
5773 {
5774 #ifdef ALLOW_WRITES
5775 if (gNeedDataWrite)
5776 flushData();
5777 #endif
5778 fo->seek = 0;
5779 fo->pos = 0;
5780 fo->sec = 0;
5781 fo->ccls = fo->cluster;
5782 gBufferOwner = NULL;
5783 return;
5784 }
5785
5786 /**************************************************************************
5787 Function:
5788 int FSerror (void)
5789 Summary:
5790 Return an error code for the last function call
5791 Conditions:
5792 The return value depends on the last function called.
5793 Input:
5794 None
5795 Side Effects:
5796 None.
5797 Return Values:
5798 FSInit -
5799 - CE_GOOD – No Error
5800 - CE_INIT_ERROR – The physical media could not be initialized
5801 - CE_BAD_SECTOR_READ – The MBR or the boot sector could not be
5802 read correctly
5803 - CE_BAD_PARITION – The MBR signature code was incorrect.
5804 - CE_NOT_FORMATTED – The boot sector signature code was incorrect or
5805 indicates an invalid number of bytes per sector.
5806 - CE_UNSUPPORTED_SECTOR_SIZE - The number of bytes per sector is unsupported
5807 - CE_CARDFAT32 – The physical media is FAT32 type (only an error
5808 when FAT32 support is disabled).
5809 - CE_UNSUPPORTED_FS – The device is formatted with an unsupported file
5810 system (not FAT12 or 16).
5811 FSfopen -
5812 - CE_GOOD – No Error
5813 - CE_NOT_INIT – The device has not been initialized.
5814 - CE_TOO_MANY_FILES_OPEN – The function could not allocate any
5815 additional file information to the array
5816 of FSFILE structures or the heap.
5817 - CE_INVALID_FILENAME – The file name argument was invalid.
5818 - CE_INVALID_ARGUMENT – The user attempted to open a directory in a
5819 write mode or specified an invalid mode argument.
5820 - CE_FILE_NOT_FOUND – The specified file (which was to be opened in read
5821 mode) does not exist on the device.
5822 - CE_BADCACHEREAD – A read from the device failed.
5823 - CE_ERASE_FAIL – The existing file could not be erased (when opening
5824 a file in WRITE mode).
5825 - CE_DIR_FULL – The directory is full.
5826 - CE_DISK_FULL– The data memory section is full.
5827 - CE_WRITE_ERROR – A write to the device failed.
5828 - CE_SEEK_ERROR – The current position in the file could not be set to
5829 the end (when the file was opened in APPEND mode).
5830 FSfclose -
5831 - CE_GOOD – No Error
5832 - CE_WRITE_ERROR – The existing data in the data buffer or the new file
5833 entry information could not be written to the device.
5834 - CE_BADCACHEREAD – The file entry information could not be cached
5835 FSfread -
5836 - CE_GOOD – No Error
5837 - CE_WRITEONLY – The file was opened in a write-only mode.
5838 - CE_WRITE_ERROR – The existing data in the data buffer could not be
5839 written to the device.
5840 - CE_BAD_SECTOR_READ – The data sector could not be read.
5841 - CE_EOF – The end of the file was reached.
5842 - CE_COULD_NOT_GET_CLUSTER – Additional clusters in the file could not be loaded.
5843 FSfwrite -
5844 - CE_GOOD – No Error
5845 - CE_READONLY – The file was opened in a read-only mode.
5846 - CE_WRITE_PROTECTED – The device write-protect check function indicated
5847 that the device has been write-protected.
5848 - CE_WRITE_ERROR – There was an error writing data to the device.
5849 - CE_BADCACHEREAD – The data sector to be modified could not be read from
5850 the device.
5851 - CE_DISK_FULL – All data clusters on the device are in use.
5852 FSfseek -
5853 - CE_GOOD – No Error
5854 - CE_WRITE_ERROR – The existing data in the data buffer could not be
5855 written to the device.
5856 - CE_INVALID_ARGUMENT – The specified offset exceeds the size of the file.
5857 - CE_BADCACHEREAD – The sector that contains the new current position
5858 could not be loaded.
5859 - CE_COULD_NOT_GET_CLUSTER – Additional clusters in the file could not be
5860 loaded/allocated.
5861 FSftell -
5862 - CE_GOOD – No Error
5863 FSattrib -
5864 - CE_GOOD – No Error
5865 - CE_INVALID_ARGUMENT – The attribute argument was invalid.
5866 - CE_BADCACHEREAD – The existing file entry information could not be
5867 loaded.
5868 - CE_WRITE_ERROR – The file entry information could not be written to
5869 the device.
5870 FSrename -
5871 - CE_GOOD – No Error
5872 - CE_FILENOTOPENED – A null file pointer was passed into the function.
5873 - CE_INVALID_FILENAME – The file name passed into the function was invalid.
5874 - CE_BADCACHEREAD – A read from the device failed.
5875 - CE_FILENAME_EXISTS – A file with the specified name already exists.
5876 - CE_WRITE_ERROR – The new file entry data could not be written to the
5877 device.
5878 FSfeof -
5879 - CE_GOOD – No Error
5880 FSformat -
5881 - CE_GOOD – No Error
5882 - CE_INIT_ERROR – The device could not be initialized.
5883 - CE_BADCACHEREAD – The master boot record or boot sector could not be
5884 loaded successfully.
5885 - CE_INVALID_ARGUMENT – The user selected to create their own boot sector on
5886 a device that has no master boot record, or the mode
5887 argument was invalid.
5888 - CE_WRITE_ERROR – The updated MBR/Boot sector could not be written to
5889 the device.
5890 - CE_BAD_PARTITION – The calculated number of sectors per clusters was
5891 invalid.
5892 - CE_NONSUPPORTED_SIZE – The card has too many sectors to be formatted as
5893 FAT12 or FAT16.
5894 FSremove -
5895 - CE_GOOD – No Error
5896 - CE_WRITE_PROTECTED – The device write-protect check function indicated
5897 that the device has been write-protected.
5898 - CE_INVALID_FILENAME – The specified filename was invalid.
5899 - CE_FILE_NOT_FOUND – The specified file could not be found.
5900 - CE_ERASE_FAIL – The file could not be erased.
5901 FSchdir -
5902 - CE_GOOD – No Error
5903 - CE_INVALID_ARGUMENT – The path string was mis-formed or the user tried to
5904 change to a non-directory file.
5905 - CE_BADCACHEREAD – A directory entry could not be cached.
5906 - CE_DIR_NOT_FOUND – Could not find a directory in the path.
5907 FSgetcwd -
5908 - CE_GOOD – No Error
5909 - CE_INVALID_ARGUMENT – The user passed a 0-length buffer into the function.
5910 - CE_BADCACHEREAD – A directory entry could not be cached.
5911 - CE_BAD_SECTOR_READ – The function could not determine a previous directory
5912 of the current working directory.
5913 FSmkdir -
5914 - CE_GOOD – No Error
5915 - CE_WRITE_PROTECTED – The device write-protect check function indicated
5916 that the device has been write-protected.
5917 - CE_INVALID_ARGUMENT – The path string was mis-formed.
5918 - CE_BADCACHEREAD – Could not successfully change to a recently created
5919 directory to store its dir entry information, or
5920 could not cache directory entry information.
5921 - CE_INVALID_FILENAME – One or more of the directory names has an invalid
5922 format.
5923 - CE_WRITE_ERROR – The existing data in the data buffer could not be
5924 written to the device or the dot/dotdot entries could
5925 not be written to a newly created directory.
5926 - CE_DIR_FULL – There are no available dir entries in the CWD.
5927 - CE_DISK_FULL – There are no available clusters in the data region of
5928 the device.
5929 FSrmdir -
5930 - CE_GOOD – No Error
5931 - CE_DIR_NOT_FOUND – The directory specified could not be found or the
5932 function could not change to a subdirectory within
5933 the directory to be deleted (when recursive delete is
5934 enabled).
5935 - CE_INVALID_ARGUMENT – The user tried to remove the CWD or root directory.
5936 - CE_BADCACHEREAD – A directory entry could not be cached.
5937 - CE_DIR_NOT_EMPTY – The directory to be deleted was not empty and
5938 recursive subdirectory removal was disabled.
5939 - CE_ERASE_FAIL – The directory or one of the directories or files
5940 within it could not be deleted.
5941 - CE_BAD_SECTOR_READ – The function could not determine a previous directory
5942 of the CWD.
5943 SetClockVars -
5944 - CE_GOOD – No Error
5945 - CE_INVALID_ARGUMENT – The time values passed into the function were
5946 invalid.
5947 FindFirst -
5948 - CE_GOOD – No Error
5949 - CE_INVALID_FILENAME – The specified filename was invalid.
5950 - CE_FILE_NOT_FOUND – No file matching the specified criteria was found.
5951 - CE_BADCACHEREAD – The file information for the file that was found
5952 could not be cached.
5953 FindNext -
5954 - CE_GOOD – No Error
5955 - CE_NOT_INIT – The SearchRec object was not initialized by a call to
5956 FindFirst.
5957 - CE_INVALID_ARGUMENT – The SearchRec object was initialized in a different
5958 directory from the CWD.
5959 - CE_INVALID_FILENAME – The filename is invalid.
5960 - CE_FILE_NOT_FOUND – No file matching the specified criteria was found.
5961 FSfprintf -
5962 - CE_GOOD – No Error
5963 - CE_WRITE_ERROR – Characters could not be written to the file.
5964 Description:
5965 The FSerror function will return the FSerrno variable. This global
5966 variable will have been set to an error value during the last call of a
5967 library function.
5968 Remarks:
5969 None
5970 **************************************************************************/
5971
5972 int FSerror (void)
5973 {
5974 return FSerrno;
5975 }
5976
5977
5978 /**************************************************************
5979 Function:
5980 void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource)
5981 Summary:
5982 Copy a file object
5983 Conditions:
5984 This function should not be called by the user.
5985 Input:
5986 foDest - The destination
5987 foSource - the source
5988 Return:
5989 None
5990 Side Effects:
5991 None
5992 Description:
5993 The FileObjectCopy function will make an exacy copy of
5994 a specified FSFILE object.
5995 Remarks:
5996 None
5997 **************************************************************/
5998
5999 void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource)
6000 {
6001 int size;
6002 BYTE *dest;
6003 BYTE *source;
6004 int Index;
6005
6006 dest = (BYTE *)foDest;
6007 source = (BYTE *)foSource;
6008
6009 size = sizeof(FSFILE);
6010
6011 for(Index=0;Index< size; Index++)
6012 {
6013 dest[Index] = source[Index];
6014 }
6015 }
6016
6017 /*************************************************************************
6018 Function:
6019 CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster)
6020 Summary:
6021 Create the first cluster of a file
6022 Conditions:
6023 This function should not be called by the user.
6024 Input:
6025 fo - Pointer to file structure
6026 cluster - Cluster location
6027 Return Values:
6028 CE_GOOD - File closed successfully
6029 CE_WRITE_ERROR - Could not write to the sector
6030 CE_DISK_FULL - All clusters in partition are taken
6031 Side Effects:
6032 None
6033 Description:
6034 The FILECreateHeadCluster function will create the first cluster
6035 of a file. First, it will find an empty cluster with the
6036 FATfindEmptyCluster function and mark it as the last cluster in the
6037 file. It will then erase the cluster using the EraseCluster function.
6038 Remarks:
6039 None.
6040 *************************************************************************/
6041
6042 #ifdef ALLOW_WRITES
6043 CETYPE FILECreateHeadCluster( FILEOBJ fo, DWORD *cluster)
6044 {
6045 DISK * disk;
6046 CETYPE error = CE_GOOD;
6047
6048 disk = fo->dsk;
6049
6050 // find the next empty cluster
6051 *cluster = FATfindEmptyCluster(fo);
6052
6053 if(*cluster == 0) // "0" is just an indication as Disk full in the fn "FATfindEmptyCluster()"
6054 {
6055 error = CE_DISK_FULL;
6056 }
6057 else
6058 {
6059 // mark the cluster as taken, and last in chain
6060 if(disk->type == FAT12)
6061 {
6062 if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT12, FALSE) == CLUSTER_FAIL_FAT16)
6063 {
6064 error = CE_WRITE_ERROR;
6065 }
6066 }
6067 else if(disk->type == FAT16)
6068 {
6069 if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT16, FALSE) == CLUSTER_FAIL_FAT16)
6070 {
6071 error = CE_WRITE_ERROR;
6072 }
6073 }
6074
6075 #ifdef SUPPORT_FAT32 // If FAT32 supported.
6076 else
6077 {
6078 if(WriteFAT( disk, *cluster, LAST_CLUSTER_FAT32, FALSE) == CLUSTER_FAIL_FAT32)
6079 {
6080 error = CE_WRITE_ERROR;
6081 }
6082 }
6083 #endif
6084
6085 // lets erase this cluster
6086 if(error == CE_GOOD)
6087 {
6088 error = EraseCluster(disk,*cluster);
6089 }
6090 }
6091
6092 return(error);
6093 } // allocate head cluster
6094 #endif
6095
6096 /*************************************************************************
6097 Function:
6098 BYTE EraseCluster(DISK *disk, DWORD cluster)
6099 Summary:
6100 Erase a cluster
6101 Conditions:
6102 This function should not be called by the user.
6103 Input:
6104 dsk - Disk structure
6105 cluster - Cluster to be erased
6106 Return Values:
6107 CE_GOOD - File closed successfully
6108 CE_WRITE_ERROR - Could not write to the sector
6109 Side Effects:
6110 None
6111 Description:
6112 The EraseCluster function will write a 0 value into every byte of
6113 the specified cluster.
6114 Remarks:
6115 None.
6116 *************************************************************************/
6117
6118 #ifdef ALLOW_WRITES
6119 BYTE EraseCluster(DISK *disk, DWORD cluster)
6120 {
6121 BYTE index;
6122 DWORD SectorAddress;
6123 BYTE error = CE_GOOD;
6124
6125 SectorAddress = Cluster2Sector(disk,cluster);
6126 if (gNeedDataWrite)
6127 if (flushData())
6128 return CE_WRITE_ERROR;
6129
6130 gBufferOwner = NULL;
6131
6132 if (gBufferZeroed == FALSE)
6133 {
6134 // clear out the memory first
6135 memset(disk->buffer, 0x00, disk->sectorSize);
6136 gBufferZeroed = TRUE;
6137 }
6138
6139 // Now clear them out
6140 for(index = 0; (index < disk->SecPerClus) && (error == CE_GOOD); index++)
6141 {
6142 if (MDD_SectorWrite( SectorAddress++, disk->buffer, FALSE) != TRUE)
6143 error = CE_WRITE_ERROR;
6144 }
6145
6146 return(error);
6147 }
6148 #endif
6149
6150
6151 #if defined (__C30__) || defined (__PIC32MX__)
6152
6153 /***************************************************
6154 Function:
6155 BYTE ReadByte(BYTE * pBuffer, WORD index)
6156 Summary:
6157 Read a byte from a buffer
6158 Conditions:
6159 This function should not be called by the user.
6160 Input:
6161 pBuffer - pointer to a buffer to read from
6162 index - index in the buffer to read to
6163 Return:
6164 BYTE - the byte read
6165 Side Effects:
6166 None
6167 Description:
6168 Reads a byte from a buffer
6169 Remarks:
6170 None.
6171 ***************************************************/
6172
6173 BYTE ReadByte( BYTE* pBuffer, WORD index )
6174 {
6175 return( pBuffer[index] );
6176 }
6177
6178
6179 /***************************************************
6180 Function:
6181 BYTE ReadWord(BYTE * pBuffer, WORD index)
6182 Summary:
6183 Read a 16-bit word from a buffer
6184 Conditions:
6185 This function should not be called by the user.
6186 Input:
6187 pBuffer - pointer to a buffer to read from
6188 index - index in the buffer to read to
6189 Return:
6190 WORD - the word read
6191 Side Effects:
6192 None
6193 Description:
6194 Reads a 16-bit word from a buffer
6195 Remarks:
6196 None.
6197 ***************************************************/
6198
6199 WORD ReadWord( BYTE* pBuffer, WORD index )
6200 {
6201 BYTE loByte, hiByte;
6202 WORD res;
6203
6204 loByte = pBuffer[index];
6205 hiByte = pBuffer[index+1];
6206 res = hiByte;
6207 res *= 0x100;
6208 res |= loByte;
6209 return( res );
6210 }
6211
6212
6213 /****************************************************
6214 Function:
6215 BYTE ReadDWord(BYTE * pBuffer, WORD index)
6216 Summary:
6217 Read a 32-bit double word from a buffer
6218 Conditions:
6219 This function should not be called by the user.
6220 Input:
6221 pBuffer - pointer to a buffer to read from
6222 index - index in the buffer to read to
6223 Return:
6224 DWORD - the double word read
6225 Side Effects:
6226 None
6227 Description:
6228 Reads a 32-bit double word from a buffer
6229 Remarks:
6230 None.
6231 ****************************************************/
6232
6233 DWORD ReadDWord( BYTE* pBuffer, WORD index )
6234 {
6235 WORD loWord, hiWord;
6236 DWORD result;
6237
6238 loWord = ReadWord( pBuffer, index );
6239 hiWord = ReadWord( pBuffer, index+2 );
6240
6241 result = hiWord;
6242 result *= 0x10000;
6243 result |= loWord;
6244 return result;
6245 }
6246
6247 #endif
6248
6249
6250
6251 /****************************************************
6252 Function:
6253 DWORD Cluster2Sector(DISK * dsk, DWORD cluster)
6254 Summary:
6255 Convert a cluster number to the corresponding sector
6256 Conditions:
6257 This function should not be called by the user.
6258 Input:
6259 disk - Disk structure
6260 cluster - Cluster to be converted
6261 Return:
6262 sector - Sector that corresponds to given cluster
6263 Side Effects:
6264 None
6265 Description:
6266 The Cluster2Sector function will calculate the
6267 sector number that corresponds to the first sector
6268 of the cluster whose value was passed into the
6269 function.
6270 Remarks:
6271 None.
6272 ****************************************************/
6273
6274 DWORD Cluster2Sector(DISK * dsk, DWORD cluster)
6275 {
6276 DWORD sector;
6277
6278 /* Rt: Settings based on FAT type */
6279 switch (dsk->type)
6280 {
6281 #ifdef SUPPORT_FAT32 // If FAT32 supported.
6282 case FAT32:
6283 /* In FAT32, there is no separate ROOT region. It is as well stored in DATA region */
6284 sector = (((DWORD)cluster-2) * dsk->SecPerClus) + dsk->data;
6285 break;
6286 #endif
6287 case FAT12:
6288 case FAT16:
6289 default:
6290 // The root dir takes up cluster 0 and 1
6291 if((cluster == 0) || (cluster == 1))
6292 sector = dsk->root + cluster;
6293 else
6294 sector = (((DWORD)cluster-2) * dsk->SecPerClus) + dsk->data;
6295 break;
6296 }
6297
6298 return(sector);
6299
6300 }
6301
6302
6303 /***************************************************************************
6304 Function:
6305 int FSattrib (FSFILE * file, unsigned char attributes)
6306 Summary:
6307 Change the attributes of a file
6308 Conditions:
6309 File opened
6310 Input:
6311 file - Pointer to file structure
6312 attributes - The attributes to set for the file
6313 - Attribute - Value - Indications
6314 - ATTR_READ_ONLY - 0x01 - The read-only attribute
6315 - ATTR_HIDDEN - 0x02 - The hidden attribute
6316 - ATTR_SYSTEM - 0x04 - The system attribute
6317 - ATTR_ARCHIVE - 0x20 - The archive attribute
6318 Return Values:
6319 0 - Attribute change was successful
6320 -1 - Attribute change was unsuccessful
6321 Side Effects:
6322 The FSerrno variable will be changed.
6323 Description:
6324 The FSattrib funciton will set the attributes of the specified file
6325 to the attributes passed in by the user. This function will load the
6326 file entry, replace the attributes with the ones specified, and write
6327 the attributes back. If the specified file is a directory, the
6328 directory attribute will be preserved.
6329 Remarks:
6330 None
6331 ***************************************************************************/
6332
6333 #ifdef ALLOW_WRITES
6334 int FSattrib (FSFILE * file, unsigned char attributes)
6335 {
6336 WORD fHandle;
6337 DIRENTRY dir;
6338
6339 FSerrno = CE_GOOD;
6340
6341 // Check for valid attributes
6342 if ((attributes & ~0x27) != 0)
6343 {
6344 FSerrno = CE_INVALID_ARGUMENT;
6345 return -1;
6346 }
6347
6348 fHandle = file->entry;
6349
6350 file->dirccls = file->dirclus;
6351
6352 // Get the file entry
6353 dir = LoadDirAttrib(file, &fHandle);
6354
6355 if (dir == NULL)
6356 {
6357 FSerrno = CE_BADCACHEREAD;
6358 return -1;
6359 }
6360
6361 // Ensure that we aren't trying to change the
6362 // attributes of a volume entry
6363 if (dir->DIR_Attr & ATTR_VOLUME)
6364 {
6365 FSerrno = CE_INVALID_ARGUMENT;
6366 return -1;
6367 }
6368
6369 // Don't remove the directory attribute from DIR files
6370 if (file->attributes & ATTR_DIRECTORY)
6371 file->attributes = attributes | ATTR_DIRECTORY;
6372 else
6373 file->attributes = attributes;
6374
6375 // just write the last entry in
6376 if(!Write_File_Entry(file,&fHandle))
6377 {
6378 FSerrno = CE_WRITE_ERROR;
6379 return -1;
6380 }
6381
6382 return 0;
6383 }
6384 #endif
6385
6386
6387 /*********************************************************************************
6388 Function:
6389 size_t FSfwrite(const void *data_to_write, size_t size, size_t n, FSFILE *stream)
6390 Summary:
6391 Write data to a file
6392 Conditions:
6393 File opened in WRITE, APPEND, WRITE+, APPEND+, READ+ mode
6394 Input:
6395 data_to_write - Pointer to source buffer
6396 size - Size of units in bytes
6397 n - Number of units to transfer
6398 stream - Pointer to file structure
6399 Return:
6400 size_t - number of units written
6401 Side Effects:
6402 The FSerrno variable will be changed.
6403 Description:
6404 The FSfwrite function will write data to a file. First, the sector that
6405 corresponds to the current position in the file will be loaded (if it hasn't
6406 already been cached in the global data buffer). Data will then be written to
6407 the device from the specified buffer until the specified amount has been written.
6408 If the end of a cluster is reached, the next cluster will be loaded, unless
6409 the end-of-file flag for the specified file has been set. If it has, a new
6410 cluster will be allocated to the file. Finally, the new position and filesize
6411 will be stored in the FSFILE object. The parameters 'size' and 'n' indicate how
6412 much data to write. 'Size' refers to the size of one object to write (in bytes),
6413 and 'n' will refer to the number of these objects to write. The value returned
6414 will be equal to 'n' unless an error occured.
6415 Remarks:
6416 None.
6417 *********************************************************************************/
6418
6419 #ifdef ALLOW_WRITES
6420 size_t FSfwrite(const void *data_to_write, size_t size, size_t n, FSFILE *stream)
6421 {
6422 DWORD count = size * n;
6423 BYTE * src = (BYTE *) data_to_write;
6424 DISK * dsk; // pointer to disk structure
6425 CETYPE error = CE_GOOD;
6426 WORD pos;
6427 DWORD l; // absolute lba of sector to load
6428 DWORD seek, filesize;
6429 WORD writeCount = 0;
6430
6431 // see if the file was opened in a write mode
6432 if(!(stream->flags.write))
6433 {
6434 FSerrno = CE_READONLY;
6435 error = CE_WRITE_ERROR;
6436 return 0;
6437 }
6438
6439 if (count == 0)
6440 return 0;
6441
6442 if (MDD_WriteProtectState())
6443 {
6444 FSerrno = CE_WRITE_PROTECTED;
6445 error = CE_WRITE_PROTECTED;
6446 return 0;
6447 }
6448
6449 gBufferZeroed = FALSE;
6450 dsk = stream->dsk;
6451 // get the stated position
6452 pos = stream->pos;
6453 seek = stream->seek;
6454 l = Cluster2Sector(dsk,stream->ccls);
6455 l += (WORD)stream->sec; // add the sector number to it
6456
6457 // Check if the current stream was the last one to use the
6458 // buffer. If not, check if we need to write data from the
6459 // old stream
6460 if (gBufferOwner != stream)
6461 {
6462 if (gNeedDataWrite)
6463 {
6464 if (flushData())
6465 {
6466 FSerrno = CE_WRITE_ERROR;
6467 return 0;
6468 }
6469 }
6470 gBufferOwner = stream;
6471 }
6472 if (gLastDataSectorRead != l)
6473 {
6474 if (gNeedDataWrite)
6475 {
6476 if (flushData())
6477 {
6478 FSerrno = CE_WRITE_ERROR;
6479 return 0;
6480 }
6481 }
6482
6483 gBufferZeroed = FALSE;
6484 if(!MDD_SectorRead( l, dsk->buffer) )
6485 {
6486 FSerrno = CE_BADCACHEREAD;
6487 error = CE_BAD_SECTOR_READ;
6488 }
6489 gLastDataSectorRead = l;
6490 }
6491 // exit loop if EOF reached
6492 filesize = stream->size;
6493
6494 // Loop while writing bytes
6495 while ((error == CE_GOOD) && (count > 0))
6496 {
6497 if( seek == filesize )
6498 stream->flags.FileWriteEOF = TRUE;
6499
6500 // load a new sector if necessary, multiples of sector
6501 if (pos == dsk->sectorSize)
6502 {
6503 BYTE needRead = TRUE;
6504
6505 if (gNeedDataWrite)
6506 if (flushData())
6507 {
6508 FSerrno = CE_WRITE_ERROR;
6509 return 0;
6510 }
6511
6512 // reset position
6513 pos = 0;
6514
6515 // point to the next sector
6516 stream->sec++;
6517
6518 // get a new cluster if necessary
6519 if (stream->sec == dsk->SecPerClus)
6520 {
6521 stream->sec = 0;
6522
6523 if(stream->flags.FileWriteEOF)
6524 {
6525 error = FILEallocate_new_cluster(stream, 0); // add new cluster to the file
6526 needRead = FALSE;
6527 }
6528 else
6529 error = FILEget_next_cluster( stream, 1);
6530 }
6531
6532 if (error == CE_DISK_FULL)
6533 {
6534 FSerrno = CE_DISK_FULL;
6535 return 0;
6536 }
6537
6538 if(error == CE_GOOD)
6539 {
6540 l = Cluster2Sector(dsk,stream->ccls);
6541 l += (WORD)stream->sec; // add the sector number to it
6542 gBufferOwner = stream;
6543 // If we just allocated a new cluster, then the cluster will
6544 // contain garbage data, so it doesn't matter what we write to it
6545 // Whatever is in the buffer will work fine
6546 if (needRead)
6547 {
6548 if( !MDD_SectorRead( l, dsk->buffer) )
6549 {
6550 FSerrno = CE_BADCACHEREAD;
6551 error = CE_BAD_SECTOR_READ;
6552 gLastDataSectorRead = 0xFFFFFFFF;
6553 return 0;
6554 }
6555 else
6556 {
6557 gLastDataSectorRead = l;
6558 }
6559 }
6560 else
6561 gLastDataSectorRead = l;
6562 }
6563 } // load new sector
6564
6565 if(error == CE_GOOD)
6566 {
6567 // Write one byte at a time
6568 RAMwrite(dsk->buffer, pos++, *(char *)src);
6569 src = src + 1; // compiler bug
6570 seek++;
6571 count--;
6572 writeCount++;
6573 // now increment the size of the part
6574 if(stream->flags.FileWriteEOF)
6575 filesize++;
6576 gNeedDataWrite = TRUE;
6577 }
6578 } // while count
6579
6580 // save off the positon
6581 stream->pos = pos;
6582
6583 // save off the seek
6584 stream->seek = seek;
6585
6586 // now the new size
6587 stream->size = filesize;
6588
6589 return(writeCount / size);
6590 } // fwrite
6591 #endif
6592
6593
6594 /**********************************************************
6595 Function:
6596 BYTE flushData (void)
6597 Summary:
6598 Flush unwritten data to a file
6599 Conditions:
6600 File opened in a write mode, data needs to be written
6601 Return Values:
6602 CE_GOOD - Data was updated successfully
6603 CE_WRITE_ERROR - Data could not be updated
6604 Side Effects:
6605 None
6606 Description:
6607 The flushData function is called when it is necessary to
6608 read new data into the global data buffer and the
6609 gNeedDataWrite variable indicates that there is data
6610 in the buffer that hasn't been written to the device.
6611 The flushData function will write the data from the
6612 buffer into the current cluster of the FSFILE object
6613 that is stored in the gBufferOwner global variable.
6614 Remarks:
6615 None
6616 **********************************************************/
6617
6618 #ifdef ALLOW_WRITES
6619 BYTE flushData (void)
6620 {
6621 DWORD l;
6622 DISK * dsk;
6623
6624 // This will either be the pointer to the last file, or the handle
6625 FILEOBJ stream = gBufferOwner;
6626
6627 dsk = stream->dsk;
6628
6629 // figure out the lba
6630 l = Cluster2Sector(dsk,stream->ccls);
6631 l += (WORD)stream->sec; // add the sector number to it
6632
6633 if(!MDD_SectorWrite( l, dsk->buffer, FALSE))
6634 {
6635 return CE_WRITE_ERROR;
6636 }
6637
6638 gNeedDataWrite = FALSE;
6639
6640 return CE_GOOD;
6641 }
6642 #endif
6643
6644 /****************************************************
6645 Function:
6646 int FSfeof( FSFILE * stream )
6647 Summary:
6648 Indicate whether the current file position is at the end
6649 Conditions:
6650 File is open in a read mode
6651 Input:
6652 stream - Pointer to the target file
6653 Return Values:
6654 Non-Zero - EOF reached
6655 0 - Not at end of File
6656 Side Effects:
6657 The FSerrno variable will be changed.
6658 Description:
6659 The FSfeof function will indicate that the end-of-
6660 file has been reached for the specified file by
6661 comparing the absolute location in the file to the
6662 size of the file.
6663 Remarks:
6664 None.
6665 ****************************************************/
6666
6667 int FSfeof( FSFILE * stream )
6668 {
6669 FSerrno = CE_GOOD;
6670 return( stream->seek == stream->size );
6671 }
6672
6673
6674 /**************************************************************************
6675 Function:
6676 size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream)
6677 Summary:
6678 Read data from a file
6679 Conditions:
6680 File is opened in a read mode
6681 Input:
6682 ptr - Destination buffer for read bytes
6683 size - Size of units in bytes
6684 n - Number of units to be read
6685 stream - File to be read from
6686 Return:
6687 size_t - number of units read
6688 Side Effects:
6689 The FSerrno variable will be changed.
6690 Description:
6691 The FSfread function will read data from the specified file. First,
6692 the appropriate sector of the file is loaded. Then, data is read into
6693 the specified buffer until the specified number of bytes have been read.
6694 When a cluster boundary is reached, a new cluster will be loaded. The
6695 parameters 'size' and 'n' indicate how much data to read. 'Size'
6696 refers to the size of one object to read (in bytes), and 'n' will refer
6697 to the number of these objects to read. The value returned will be equal
6698 to 'n' unless an error occured or the user tried to read beyond the end
6699 of the file.
6700 Remarks:
6701 None.
6702 **************************************************************************/
6703
6704 size_t FSfread (void *ptr, size_t size, size_t n, FSFILE *stream)
6705 {
6706 DWORD len = size * n;
6707 BYTE *pointer = (BYTE *) ptr;
6708 DISK *dsk; // Disk structure
6709 DWORD seek, sec_sel;
6710 WORD pos; //position within sector
6711 CETYPE error = CE_GOOD;
6712 WORD readCount = 0;
6713
6714 FSerrno = CE_GOOD;
6715
6716 dsk = (DISK *)stream->dsk;
6717 pos = stream->pos;
6718 seek = stream->seek;
6719
6720 if( !stream->flags.read )
6721 {
6722 FSerrno = CE_WRITEONLY;
6723 return 0; // CE_WRITEONLY
6724 }
6725
6726 #ifdef ALLOW_WRITES
6727 if (gNeedDataWrite)
6728 if (flushData() != CE_GOOD)
6729 {
6730 FSerrno = CE_WRITE_ERROR;
6731 return 0;
6732 }
6733 #endif
6734
6735 // if it not my buffer, then get it from the disk.
6736 if( (gBufferOwner != stream) && (pos != dsk->sectorSize))
6737 {
6738 gBufferOwner = stream;
6739 sec_sel = Cluster2Sector(dsk,stream->ccls);
6740 sec_sel += (WORD)stream->sec; // add the sector number to it
6741
6742 gBufferZeroed = FALSE;
6743 if( !MDD_SectorRead( sec_sel, dsk->buffer) )
6744 {
6745 FSerrno = CE_BAD_SECTOR_READ;
6746 error = CE_BAD_SECTOR_READ;
6747 return 0;
6748 }
6749 gLastDataSectorRead = sec_sel;
6750 }
6751
6752 //loop reading (count) bytes
6753 while( len )
6754 {
6755 if( seek == stream->size )
6756 {
6757 FSerrno = CE_EOF;
6758 error = CE_EOF;
6759 break;
6760 }
6761
6762 // In fopen, pos is init to 0 and the sect is loaded
6763 if( pos == dsk->sectorSize )
6764 {
6765 // reset position
6766 pos = 0;
6767 // point to the next sector
6768 stream->sec++;
6769
6770 // get a new cluster if necessary
6771 if( stream->sec == dsk->SecPerClus )
6772 {
6773 stream->sec = 0;
6774 if( (error = FILEget_next_cluster( stream, 1)) != CE_GOOD )
6775 {
6776 FSerrno = CE_COULD_NOT_GET_CLUSTER;
6777 break;
6778 }
6779 }
6780
6781 sec_sel = Cluster2Sector(dsk,stream->ccls);
6782 sec_sel += (WORD)stream->sec; // add the sector number to it
6783
6784
6785 gBufferOwner = stream;
6786 gBufferZeroed = FALSE;
6787 if( !MDD_SectorRead( sec_sel, dsk->buffer) )
6788 {
6789 FSerrno = CE_BAD_SECTOR_READ;
6790 error = CE_BAD_SECTOR_READ;
6791 break;
6792 }
6793 gLastDataSectorRead = sec_sel;
6794 }
6795
6796 // copy one byte at a time
6797 *pointer = RAMread( dsk->buffer, pos++ );
6798 pointer++;
6799 seek++;
6800 readCount++;
6801 len--;
6802 }
6803
6804 // save off the positon
6805 stream->pos = pos;
6806 // save off the seek
6807 stream->seek = seek;
6808
6809 return(readCount / size);
6810 } // fread
6811
6812
6813 /***************************************************************************
6814 Function:
6815 BYTE FormatFileName( const char* fileName, FILEOBJ fptr, BYTE mode )
6816 Summary:
6817 Format a file name into dir entry format
6818 Conditions:
6819 This function should not be called by the user.
6820 Input:
6821 fileName - The name to be formatted
6822 fN2 - The location the formatted name will be stored
6823 mode - Non-zero if parital string search chars are allowed
6824 Return Values:
6825 TRUE - Name formatted successfully
6826 FALSE - File name could not be formatted
6827 Side Effects:
6828 None
6829 Description:
6830 Format an 8.3 filename into FSFILE structure format. If filename is less
6831 than 8 chars, then it will be padded with spaces. If the extension name is
6832 fewer than 3 chars, then it will also be oadded with spaces. The
6833 ValidateChars function is used to ensure the characters in the specified
6834 filename are valid in this filesystem.
6835 Remarks:
6836 None.
6837 ***************************************************************************/
6838 BYTE FormatFileName( const char* fileName, FILEOBJ fptr, BYTE mode)
6839 {
6840 char *fN2;
6841 FILE_DIR_NAME_TYPE fileNameType;
6842 int temp,count1,count2,count3,count4;
6843 BOOL supportLFN = FALSE;
6844 char *localFileName = NULL;
6845
6846 // go with static allocation
6847 #if defined(SUPPORT_LFN)
6848 unsigned short int tempString[256];
6849 BOOL AscciIndication = TRUE;
6850 count1 = 256;
6851 #else
6852 unsigned short int tempString[13];
6853 count1 = 12;
6854 #endif
6855
6856 // Check whether the length of the file name is valid
6857 // for LFN support as well as Non LFN support
6858 #ifdef SUPPORT_LFN
6859 if(utfModeFileName)
6860 {
6861 utf16Filename = (unsigned short int *)fileName;
6862 fileNameLength = 0;
6863 while(utf16Filename[fileNameLength])
6864 {
6865 fileNameLength++;
6866 }
6867
6868 if((fileNameLength > count1) || (*utf16Filename == '.') ||
6869 (*utf16Filename == 0))
6870 {
6871 return FALSE;
6872 }
6873
6874 for (count1 = 0;count1 < fileNameLength; count1++)
6875 {
6876 tempString[count1] = utf16Filename[count1];
6877 }
6878
6879 utf16Filename = tempString;
6880 }
6881 else
6882 #endif
6883 {
6884 fileNameLength = strlen(fileName);
6885
6886 if((fileNameLength > count1) || (*fileName == '.') || (*fileName == 0))
6887 {
6888 return FALSE;
6889 }
6890
6891 asciiFilename = (char *)tempString;
6892 for (count1 = 0;count1 < fileNameLength; count1++)
6893 {
6894 asciiFilename[count1] = fileName[count1];
6895 }
6896 }
6897
6898 // Make sure the characters are valid
6899 fileNameType = ValidateChars(mode);
6900
6901 // If the file name doesn't follow 8P3 or LFN format, then return FALSE
6902 if(NAME_ERROR == fileNameType)
6903 {
6904 return FALSE;
6905 }
6906
6907 temp = fileNameLength;
6908
6909 #if defined(SUPPORT_LFN)
6910 fptr->AsciiEncodingType = TRUE;
6911 fptr->utf16LFNlength = 0;
6912 #endif
6913
6914 // If LFN is supported and the file name is UTF16 type or Ascii mixed type,
6915 // go for LFN support rather than trying to adjust in 8P3 format
6916 if(NAME_8P3_ASCII_MIXED_TYPE == fileNameType)
6917 {
6918 #if defined(SUPPORT_LFN)
6919 supportLFN = TRUE;
6920 #endif
6921 }
6922
6923 #if defined(SUPPORT_LFN)
6924 if(NAME_8P3_UTF16_TYPE == fileNameType)
6925 {
6926 for (count3 = 0; count3 < temp; count3++)
6927 {
6928 if(utf16Filename[count3] > 0xFF)
6929 {
6930 fileNameType = NAME_8P3_UTF16_NONASCII_TYPE;
6931 supportLFN = TRUE;
6932 break;
6933 }
6934 }
6935
6936 if(count3 == temp)
6937 {
6938 fileNameType = NAME_8P3_UTF16_ASCII_CAPS_TYPE;
6939
6940 for (count3 = 0; count3 < temp; count3++)
6941 {
6942 if((utf16Filename[count3] >= 0x61) && (utf16Filename[count3] <= 0x7A))
6943 {
6944 fileNameType = NAME_8P3_UTF16_ASCII_MIXED_TYPE;
6945 supportLFN = TRUE;
6946 break;
6947 }
6948 }
6949 }
6950 }
6951 #endif
6952
6953 // If the file name follows 8P3 type
6954 if((NAME_LFN_TYPE != fileNameType) && (FALSE == supportLFN))
6955 {
6956 for (count3 = 0; count3 < temp; count3++)
6957 {
6958 #ifdef SUPPORT_LFN
6959 if(utfModeFileName)
6960 {
6961 if(((utf16Filename[count3] == '.') && ((temp - count3) > 4)) ||
6962 (count3 > 8))
6963 {
6964 // UTF File name extension greater then 3 characters or
6965 // UTF File name greater then 8 charcters
6966 supportLFN = TRUE;
6967 break;
6968 }
6969 else if(utf16Filename[count3] == '.')
6970 {
6971 break;
6972 }
6973 }
6974 else
6975 #endif
6976 {
6977 if(((asciiFilename[count3] == '.') && ((temp - count3) > 4)) ||
6978 (count3 > 8))
6979 {
6980 // File extension greater then 3 characters or
6981 // File name greater then 8 charcters
6982 #if !defined(SUPPORT_LFN)
6983 return FALSE;
6984 #endif
6985 supportLFN = TRUE;
6986 break;
6987 }
6988 else if(asciiFilename[count3] == '.')
6989 {
6990 break;
6991 }
6992 }
6993 }
6994
6995 // If LFN not supported try to adjust in 8P3 format
6996 if(FALSE == supportLFN)
6997 {
6998 // point fN2 to short file name
6999 fN2 = fptr -> name;
7000
7001 // Load destination filename to be space intially.
7002 for (count1 = 0; count1 < FILE_NAME_SIZE_8P3; count1++)
7003 {
7004 *(fN2 + count1) = ' ';
7005 }
7006
7007 // multiply the length by 2 as each UTF word has 2 byte
7008 #ifdef SUPPORT_LFN
7009 if(utfModeFileName)
7010 {
7011 count4 = count3 * 2;
7012 temp = temp * 2;
7013 localFileName = (char *)utf16Filename;
7014 }
7015 else
7016 #endif
7017 {
7018 count4 = count3;
7019 localFileName = asciiFilename;
7020 }
7021
7022 //copy only file name ( not the extension part )
7023 for (count1 = 0,count2 = 0; (count2 < 8) && (count1 < count4);count1++ )
7024 {
7025 if(localFileName[count1])
7026 {
7027 fN2[count2] = localFileName[count1]; // Destination filename initially filled with SPACE. Now copy only available chars.
7028
7029 // Convert lower-case to upper-case
7030 if ((fN2[count2] >= 0x61) && (fN2[count2] <= 0x7A))
7031 {
7032 fN2[count2] -= 0x20;
7033 }
7034 count2++;
7035 }
7036 }
7037
7038 if(count4 < temp)
7039 {
7040 // Discard the '.' part
7041 count4++;
7042
7043 // Copy the extn to 8th position onwards. Ex: "FILE .Tx "
7044 for (count3 = 8; (count3 < 11) && (count4 < temp);count4++ )
7045 {
7046 if(localFileName[count4])
7047 {
7048 fN2[count3] = localFileName[count4];
7049
7050 // Convert lower-case to upper-case
7051 if ((fN2[count3] >= 0x61) && (fN2[count3] <= 0x7A))
7052 {
7053 fN2[count3] -= 0x20;
7054 }
7055 count3++;
7056 }
7057 }
7058 }
7059 }
7060 }
7061
7062 // If the file name follows LFN format
7063 if((NAME_LFN_TYPE == fileNameType) || (TRUE == supportLFN))
7064 {
7065 #if defined(SUPPORT_LFN)
7066
7067 // point fN2 to long file name
7068 fN2 = (char *)(fptr -> utf16LFNptr);
7069
7070 if(!utfModeFileName)
7071 {
7072 localFileName = asciiFilename;
7073 }
7074
7075 // Copy the LFN name in the adress specified by FSFILE pointer
7076 count2 = 0;
7077 for(count1 = 0;count1 < temp;count1++)
7078 {
7079 if(utfModeFileName)
7080 {
7081 fptr -> utf16LFNptr[count1] = utf16Filename[count1];
7082 if(AscciIndication)
7083 {
7084 if(utf16Filename[count1] > 0xFF)
7085 {
7086 fptr->AsciiEncodingType = FALSE;
7087 AscciIndication = FALSE;
7088 }
7089 }
7090 }
7091 else
7092 {
7093 fN2[count2++] = localFileName[count1];
7094 fN2[count2++] = (BYTE)0x00;
7095 }
7096 }
7097 fptr -> utf16LFNptr[count1] = 0x0000;
7098
7099 fptr->utf16LFNlength = fileNameLength + 1;
7100 #else
7101 return FALSE;
7102 #endif
7103 }
7104
7105 // Free the temporary heap used for intermediate execution
7106 return TRUE;
7107 }
7108
7109 #ifdef ALLOW_DIRS
7110
7111 /*************************************************************************
7112 Function:
7113 BYTE FormatDirName (char * string,FILEOBJ fptr, BYTE mode)
7114 Summary:
7115 Format a dir name into dir entry format
7116 Conditions:
7117 This function should not be called by the user.
7118 Input:
7119 string - The name to be formatted
7120 mode -
7121 - TRUE - Partial string search characters are allowed
7122 - FALSE - Partial string search characters are forbidden
7123 Return Values:
7124 TRUE - The name was formatted correctly
7125 FALSE - The name contained invalid characters
7126 Side Effects:
7127 None
7128 Description:
7129 Format an 8.3 filename into directory structure format. If the name is less
7130 than 8 chars, then it will be padded with spaces. If the extension name is
7131 fewer than 3 chars, then it will also be oadded with spaces. The
7132 ValidateChars function is used to ensure the characters in the specified
7133 directory name are valid in this filesystem.
7134 Remarks:
7135 None.
7136 *************************************************************************/
7137
7138 BYTE FormatDirName (char * string,FILEOBJ fptr, BYTE mode)
7139 {
7140 char tempString [12];
7141 FILE_DIR_NAME_TYPE fileNameType;
7142 int temp,count1,count2;
7143 BOOL supportLFN = FALSE;
7144 char *localFileName;
7145
7146 // go with static allocation
7147 #if defined(SUPPORT_LFN)
7148 int count3,count4;
7149 BOOL AscciIndication = TRUE;
7150 count1 = 256;
7151 #else
7152 count1 = 12;
7153 #endif
7154
7155 // Calculate the String length
7156 #ifdef SUPPORT_LFN
7157 if(utfModeFileName)
7158 {
7159 utf16Filename = (unsigned short int *)string;
7160 fileNameLength = 0;
7161 while(utf16Filename[fileNameLength])
7162 {
7163 fileNameLength++;
7164 }
7165 }
7166 else
7167 #endif
7168 {
7169 asciiFilename = string;
7170 fileNameLength = strlen(string);
7171 }
7172
7173 if(fileNameLength > count1)
7174 {
7175 return FALSE;
7176 }
7177
7178 // Make sure the characters are valid
7179 fileNameType = ValidateChars(mode);
7180
7181 // If the file name doesn't follow 8P3 or LFN format, then return FALSE
7182 if(NAME_ERROR == fileNameType)
7183 {
7184 return FALSE;
7185 }
7186
7187 temp = fileNameLength;
7188
7189 #if defined(SUPPORT_LFN)
7190 fptr->AsciiEncodingType = TRUE;
7191 fptr->utf16LFNlength = 0;
7192 #endif
7193
7194 // If LFN is supported and the file name is UTF16 type or Ascii mixed type,
7195 // go for LFN support rather than trying to adjust in 8P3 format
7196 if(NAME_8P3_ASCII_MIXED_TYPE == fileNameType)
7197 {
7198 #if defined(SUPPORT_LFN)
7199 supportLFN = TRUE;
7200 #endif
7201 }
7202
7203 #if defined(SUPPORT_LFN)
7204 if(NAME_8P3_UTF16_TYPE == fileNameType)
7205 {
7206 for (count3 = 0; count3 < temp; count3++)
7207 {
7208 if(utf16Filename[count3] > 0xFF)
7209 {
7210 fileNameType = NAME_8P3_UTF16_NONASCII_TYPE;
7211 supportLFN = TRUE;
7212 break;
7213 }
7214 }
7215
7216 if(count3 == temp)
7217 {
7218 fileNameType = NAME_8P3_UTF16_ASCII_CAPS_TYPE;
7219
7220 for (count3 = 0; count3 < temp; count3++)
7221 {
7222 if((utf16Filename[count3] >= 0x61) && (utf16Filename[count3] <= 0x7A))
7223 {
7224 fileNameType = NAME_8P3_UTF16_ASCII_MIXED_TYPE;
7225 supportLFN = TRUE;
7226 break;
7227 }
7228 }
7229 }
7230 }
7231 #endif
7232
7233 // If the file name follows LFN format
7234 if((NAME_LFN_TYPE == fileNameType) || (TRUE == supportLFN))
7235 {
7236 #if !defined(SUPPORT_LFN)
7237 return FALSE;
7238 #else
7239 fptr -> utf16LFNptr = (unsigned short int *)string;
7240
7241 if(utfModeFileName)
7242 {
7243 if(utf16Filename != (unsigned short int *)string)
7244 {
7245 // Copy the validated/Fomated name in the UTF16 string
7246 for(count1 = 0; count1 < temp; count1++)
7247 {
7248 fptr -> utf16LFNptr[count1] = utf16Filename[count1];
7249 if(AscciIndication)
7250 {
7251 if(utf16Filename[count1] > 0xFF)
7252 {
7253 fptr->AsciiEncodingType = FALSE;
7254 AscciIndication = FALSE;
7255 }
7256 }
7257 }
7258 fptr -> utf16LFNptr[count1] = 0x0000;
7259 }
7260 else
7261 {
7262 for(count1 = 0; count1 < temp; count1++)
7263 {
7264 if(AscciIndication)
7265 {
7266 if(utf16Filename[count1] > 0xFF)
7267 {
7268 fptr->AsciiEncodingType = FALSE;
7269 AscciIndication = FALSE;
7270 break;
7271 }
7272 }
7273 }
7274 }
7275 }
7276 else
7277 {
7278 #ifdef FS_DYNAMIC_MEM
7279 unsigned short int *tempAsciiLFN = (unsigned short int *)FS_malloc((temp + 1) * 2);
7280 #else
7281 unsigned short int tempAsciiLFN[temp + 1];
7282 #endif
7283
7284 localFileName = (char *)tempAsciiLFN;
7285
7286 // Copy the validated/Fomated name in the Ascii string
7287 count2 = 0;
7288 for(count1 = 0; count1 < temp; count1++)
7289 {
7290 localFileName[count2++] = asciiFilename[count1];
7291 localFileName[count2++] = (BYTE)0x00;
7292 }
7293
7294 // Copy the validated/Fomated name in the UTF16 string
7295 for(count1 = 0; count1 < temp; count1++)
7296 {
7297 fptr -> utf16LFNptr[count1] = tempAsciiLFN[count1];
7298 }
7299
7300 #ifdef FS_DYNAMIC_MEM
7301 FS_free((unsigned char *)tempAsciiLFN);
7302 #endif
7303 fptr -> utf16LFNptr[count1] = 0x0000;
7304 }
7305
7306 fptr->utf16LFNlength = fileNameLength + 1;
7307 #endif
7308 }
7309 else
7310 {
7311 #ifdef SUPPORT_LFN
7312 if(utfModeFileName)
7313 {
7314 localFileName = (char *)utf16Filename;
7315
7316 // Copy the name part in the temporary string
7317 count4 = 0;
7318 for (count3 = 0; (count3 < temp) && (utf16Filename[count3] != '.') && (utf16Filename[count3] != 0); count3++)
7319 {
7320 count1 = count3 * 2;
7321 if(localFileName[count1])
7322 {
7323 tempString[count4] = localFileName[count1];
7324 count4++;
7325 if(count4 == 8)
7326 break;
7327 }
7328
7329 if(localFileName[count1 + 1])
7330 {
7331 tempString[count4] = localFileName[count1 + 1];
7332 count4++;
7333 if(count4 == 8)
7334 break;
7335 }
7336 }
7337
7338 // File the remaining name portion with spaces
7339 while (count4 < 8)
7340 {
7341 tempString [count4++] = 0x20;
7342 }
7343
7344 // Copy the extension part in the temporary string
7345 if (utf16Filename[count3] == '.')
7346 {
7347 count1 = count3 * 2 + 2;
7348 while (localFileName[count1] != 0)
7349 {
7350 if(localFileName[count3])
7351 {
7352 tempString[count4] = localFileName[count3];
7353 count4++;
7354 if(count4 == 11)
7355 break;
7356 }
7357 }
7358 }
7359
7360 count1 = count4;
7361 }
7362 else
7363 #endif
7364 {
7365 // Copy the name part in the temporary string
7366 for (count1 = 0; (count1 < 8) && (*(asciiFilename + count1) != '.') && (*(asciiFilename + count1) != 0); count1++)
7367 {
7368 tempString[count1] = *(asciiFilename + count1);
7369 }
7370
7371 count2 = count1;
7372
7373 // File the remaining name portion with spaces
7374 while (count1 < 8)
7375 {
7376 tempString [count1++] = 0x20;
7377 }
7378
7379 // Copy the extension part in the temporary string
7380 if (*(asciiFilename + count2) == '.')
7381 {
7382 count2++;
7383 while (*(asciiFilename + count2) != 0)
7384 {
7385 tempString[count1++] = *(asciiFilename + count2++);
7386 }
7387 }
7388 }
7389
7390 // File the remaining portion with spaces
7391 while (count1 < FILE_NAME_SIZE_8P3)
7392 {
7393 tempString[count1++] = 0x20;
7394 }
7395
7396 tempString[FILE_NAME_SIZE_8P3] = 0;
7397
7398 // Forbidden
7399 if (tempString[0] == 0x20)
7400 {
7401 tempString[0] = '_';
7402 }
7403
7404 // point fN2 to short file name
7405 localFileName = fptr -> name;
7406
7407 // Copy the formated name in string
7408 for (count1 = 0; count1 < TOTAL_FILE_SIZE_8P3; count1++)
7409 {
7410 localFileName[count1] = tempString[count1];
7411
7412 // Convert lower-case to upper-case
7413 if ((localFileName[count1] >= 0x61) && (localFileName[count1] <= 0x7A))
7414 {
7415 localFileName[count1] -= 0x20;
7416 }
7417 }
7418 }
7419
7420 return TRUE;
7421 }
7422 #endif
7423
7424
7425 /*************************************************************
7426 Function:
7427 FILE_DIR_NAME_TYPE ValidateChars(BYTE mode)
7428 Summary:
7429 Validate the characters in a given file name
7430 Conditions:
7431 This function should not be called by the user.
7432 Input:
7433 fileName - The name to be validated
7434 mode - Determines if partial string search is allowed
7435 Return Values:
7436 TRUE - Name was validated
7437 FALSE - File name was not valid
7438 Side Effects:
7439 None
7440 Description:
7441 The ValidateChars function will compare characters in a
7442 specified filename to determine if they're permissable
7443 in the FAT file system. Lower-case characters will be
7444 converted to upper-case. If the mode argument is specifed
7445 to be 'TRUE,' partial string search characters are allowed.
7446 Remarks:
7447 None.
7448 *************************************************************/
7449 FILE_DIR_NAME_TYPE ValidateChars(BYTE mode)
7450 {
7451 FILE_DIR_NAME_TYPE fileNameType;
7452 unsigned short int count1;
7453 #if defined(SUPPORT_LFN)
7454 unsigned short int utf16Value;
7455 unsigned short int count2;
7456 int count3;
7457 #endif
7458 unsigned char radix = FALSE,asciiValue;
7459
7460 #if defined(SUPPORT_LFN)
7461
7462 // Remove the spaces if they are present before the file name
7463 for (count1 = 0; count1 < fileNameLength; count1++)
7464 {
7465 if(utfModeFileName)
7466 {
7467 if((utf16Filename[count1] != ' ') && (utf16Filename[count1] != '.'))
7468 {
7469 utf16Filename = utf16Filename + count1;
7470 break;
7471 }
7472 }
7473 else if((asciiFilename[count1] != ' ') && (asciiFilename[count1] != '.'))
7474 {
7475 asciiFilename = asciiFilename + count1;
7476 break;
7477 }
7478 }
7479
7480 count2 = 0;
7481
7482 // Remove the spaces & dots if they are present after the file name
7483 for (count3 = fileNameLength - count1 - 1; count3 > 0; count3--)
7484 {
7485 if(utfModeFileName)
7486 {
7487 if((utf16Filename[count3] != ' ') && (utf16Filename[count3] != '.'))
7488 {
7489 break;
7490 }
7491 }
7492 else if((asciiFilename[count3] != ' ') && (asciiFilename[count3] != '.'))
7493 {
7494 break;
7495 }
7496
7497 count2++;
7498 }
7499
7500 fileNameLength = fileNameLength - count1 - count2;
7501
7502 if(( fileNameLength > MAX_FILE_NAME_LENGTH_LFN ) || (fileNameLength == 0))// 255
7503 return NAME_ERROR; //long file name
7504
7505 #endif
7506
7507 // If the string length is greater then 8P3 length, then assume
7508 // the file name as LFN type provided there are no errors in the
7509 // below for loop.
7510 #ifdef SUPPORT_LFN
7511 if(utfModeFileName)
7512 {
7513 if((fileNameLength * 2) > (TOTAL_FILE_SIZE_8P3 * 2))
7514 {
7515 fileNameType = NAME_LFN_TYPE;
7516 }
7517 else
7518 {
7519 fileNameType = NAME_8P3_UTF16_TYPE;
7520 }
7521 }
7522 else
7523 #endif
7524 {
7525 if(fileNameLength > TOTAL_FILE_SIZE_8P3)
7526 {
7527 fileNameType = NAME_LFN_TYPE;
7528 }
7529 else
7530 {
7531 fileNameType = NAME_8P3_ASCII_CAPS_TYPE;
7532 }
7533 }
7534
7535 for( count1 = 0; count1 < fileNameLength; count1++ )
7536 {
7537 #ifdef SUPPORT_LFN
7538 if(utfModeFileName)
7539 {
7540 utf16Value = utf16Filename[count1];
7541 // Characters not valid for either of 8P3 & LFN format
7542 if (((utf16Value < 0x20) && (utf16Value != 0x05)) || (utf16Value == 0x22) ||
7543 (utf16Value == 0x2F) || (utf16Value == 0x3A) || (utf16Value == 0x3C) ||
7544 (utf16Value == 0x3E) || (utf16Value == 0x5C) || (utf16Value == 0x7C))
7545 {
7546 return NAME_ERROR;
7547 }
7548
7549 // Check for partial string search chars
7550 if (mode == FALSE)
7551 {
7552 if ((utf16Value == '*') || (utf16Value == '?'))
7553 {
7554 return NAME_ERROR;
7555 }
7556 }
7557
7558 if(fileNameType != NAME_LFN_TYPE)
7559 {
7560 // Characters valid for LFN format only
7561 if ((utf16Value == 0x20) || (utf16Value == 0x2B) || (utf16Value == 0x2C) ||
7562 (utf16Value == 0x3B) || (utf16Value == 0x3D) || (utf16Value == 0x5B) ||
7563 (utf16Value == 0x5D) || ((utf16Value == 0x2E) && (radix == TRUE)))
7564 {
7565 fileNameType = NAME_LFN_TYPE;
7566 continue;
7567 }
7568
7569 // only one radix ('.') character is allowed in 8P3 format, where as
7570 // multiple radices can be present in LFN format
7571 if (utf16Filename[count1] == 0x2E)
7572 {
7573 radix = TRUE;
7574 }
7575 }
7576 }
7577 else
7578 #endif
7579 {
7580 asciiValue = asciiFilename[count1];
7581 if(((asciiValue < 0x20) && (asciiValue != 0x05)) || (asciiValue == 0x22) ||
7582 (asciiValue == 0x2F) || (asciiValue == 0x3A) || (asciiValue == 0x3C) ||
7583 (asciiValue == 0x3E) || (asciiValue == 0x5C) || (asciiValue == 0x7C))
7584 {
7585 return NAME_ERROR;
7586 }
7587
7588 // Check for partial string search chars
7589 if (mode == FALSE)
7590 {
7591 if ((asciiValue == '*') || (asciiValue == '?'))
7592 {
7593 return NAME_ERROR;
7594 }
7595 }
7596
7597 if(fileNameType != NAME_LFN_TYPE)
7598 {
7599 // Characters valid for LFN format only
7600 if ((asciiValue == 0x20) || (asciiValue == 0x2B) || (asciiValue == 0x2C) ||
7601 (asciiValue == 0x3B) || (asciiValue == 0x3D) || (asciiValue == 0x5B) ||
7602 (asciiValue == 0x5D) || ((asciiValue == 0x2E) && (radix == TRUE)))
7603 {
7604 fileNameType = NAME_LFN_TYPE;
7605 continue;
7606 }
7607
7608 // only one radix ('.') character is allowed in 8P3 format, where as
7609 // multiple radices can be present in LFN format
7610 if (asciiValue == 0x2E)
7611 {
7612 radix = TRUE;
7613 }
7614
7615 // If the characters are mixed type & are within 8P3 length range
7616 // then store file type as 8P3 mixed type format
7617 if(fileNameType != NAME_8P3_ASCII_MIXED_TYPE)
7618 {
7619 if((asciiValue >= 0x61) && (asciiValue <= 0x7A))
7620 {
7621 fileNameType = NAME_8P3_ASCII_MIXED_TYPE;
7622 }
7623 }
7624 }
7625 }
7626 }
7627
7628 return fileNameType;
7629 }
7630
7631
7632 /**********************************************************************
7633 Function:
7634 int FSfseek(FSFILE *stream, long offset, int whence)
7635 Summary:
7636 Change the current position in a file
7637 Conditions:
7638 File opened
7639 Input:
7640 stream - Pointer to file structure
7641 offset - Offset from base location
7642 whence -
7643 - SEEK_SET - Seek from start of file
7644 - SEEK_CUR - Seek from current location
7645 - SEEK_END - Seek from end of file (subtract offset)
7646 Return Values:
7647 0 - Operation successful
7648 -1 - Operation unsuccesful
7649 Side Effects:
7650 The FSerrno variable will be changed.
7651 Description:
7652 The FSfseek function will change the current position in the file to
7653 one specified by the user. First, an absolute offset is calculated
7654 using the offset and base location passed in by the user. Then, the
7655 position variables are updated, and the sector number that corresponds
7656 to the new location. That sector is then loaded. If the offset
7657 falls exactly on a cluster boundary, a new cluster will be allocated
7658 to the file and the position will be set to the first byte of that
7659 cluster.
7660 Remarks:
7661 None
7662 **********************************************************************/
7663
7664 int FSfseek(FSFILE *stream, long offset, int whence)
7665 {
7666 DWORD numsector, temp; // lba of first sector of first cluster
7667 DISK* dsk; // pointer to disk structure
7668 BYTE test;
7669 long offset2 = offset;
7670
7671 dsk = stream->dsk;
7672
7673 switch(whence)
7674 {
7675 case SEEK_CUR:
7676 // Apply the offset to the current position
7677 offset2 += stream->seek;
7678 break;
7679 case SEEK_END:
7680 // Apply the offset to the end of the file
7681 offset2 = stream->size - offset2;
7682 break;
7683 case SEEK_SET:
7684 // automatically there
7685 default:
7686 break;
7687 }
7688
7689 #ifdef ALLOW_WRITES
7690 if (gNeedDataWrite)
7691 if (flushData())
7692 {
7693 FSerrno = CE_WRITE_ERROR;
7694 return EOF;
7695 }
7696 #endif
7697
7698 // start from the beginning
7699 temp = stream->cluster;
7700 stream->ccls = temp;
7701
7702 temp = stream->size;
7703
7704 if (offset2 > temp)
7705 {
7706 FSerrno = CE_INVALID_ARGUMENT;
7707 return (-1); // past the limits
7708 }
7709 else
7710 {
7711 // if we are writing we are no longer at the end
7712 stream->flags.FileWriteEOF = FALSE;
7713
7714 // set the new postion
7715 stream->seek = offset2;
7716
7717 // figure out how many sectors
7718 numsector = offset2 / dsk->sectorSize;
7719
7720 // figure out how many bytes off of the offset
7721 offset2 = offset2 - (numsector * dsk->sectorSize);
7722 stream->pos = offset2;
7723
7724 // figure out how many clusters
7725 temp = numsector / dsk->SecPerClus;
7726
7727 // figure out the stranded sectors
7728 numsector = numsector - (dsk->SecPerClus * temp);
7729 stream->sec = numsector;
7730
7731 // if we are in the current cluster stay there
7732 if (temp > 0)
7733 {
7734 test = FILEget_next_cluster(stream, temp);
7735 if (test != CE_GOOD)
7736 {
7737 if (test == CE_FAT_EOF)
7738 {
7739 #ifdef ALLOW_WRITES
7740 if (stream->flags.write)
7741 {
7742 // load the previous cluster
7743 stream->ccls = stream->cluster;
7744 // Don't perform this operation if there's only one cluster
7745 if (temp != 1)
7746 test = FILEget_next_cluster(stream, temp - 1);
7747 if (FILEallocate_new_cluster(stream, 0) != CE_GOOD)
7748 {
7749 FSerrno = CE_COULD_NOT_GET_CLUSTER;
7750 return -1;
7751 }
7752 // sec and pos should already be zero
7753 }
7754 else
7755 {
7756 #endif
7757 stream->ccls = stream->cluster;
7758 test = FILEget_next_cluster(stream, temp - 1);
7759 if (test != CE_GOOD)
7760 {
7761 FSerrno = CE_COULD_NOT_GET_CLUSTER;
7762 return (-1);
7763 }
7764 stream->pos = dsk->sectorSize;
7765 stream->sec = dsk->SecPerClus - 1;
7766 #ifdef ALLOW_WRITES
7767 }
7768 #endif
7769 }
7770 else
7771 {
7772 FSerrno = CE_COULD_NOT_GET_CLUSTER;
7773 return (-1); // past the limits
7774 }
7775 }
7776 }
7777
7778 // Determine the lba of the selected sector and load
7779 temp = Cluster2Sector(dsk,stream->ccls);
7780
7781 // now the extra sectors
7782 numsector = stream->sec;
7783 temp += numsector;
7784
7785 gBufferOwner = NULL;
7786 gBufferZeroed = FALSE;
7787 if( !MDD_SectorRead(temp, dsk->buffer) )
7788 {
7789 FSerrno = CE_BADCACHEREAD;
7790 return (-1); // Bad read
7791 }
7792 gLastDataSectorRead = temp;
7793 }
7794
7795 FSerrno = CE_GOOD;
7796
7797 return (0);
7798 }
7799
7800
7801 // FSfopenpgm, FSremovepgm, and FSrenamepgm will only work on PIC18s
7802 #ifdef __18CXX
7803 #ifdef ALLOW_PGMFUNCTIONS
7804
7805 #ifdef ALLOW_WRITES
7806
7807 /*****************************************************************
7808 Function:
7809 int FSrenamepgm(const rom char * fileName, FSFILE * fo)
7810 Summary:
7811 Rename a file named with a ROM string on PIC18
7812 Conditions:
7813 File opened.
7814 Input:
7815 fileName - The new name of the file (in ROM)
7816 fo - The file to rename
7817 Return Values:
7818 0 - File renamed successfully
7819 -1 - File could not be renamed
7820 Side Effects:
7821 The FSerrno variable will be changed.
7822 Description:
7823 The Fsrenamepgm function will copy the rom fileName specified
7824 by the user into a RAM array and pass that array into the
7825 FSrename function.
7826 Remarks:
7827 This function is for use with PIC18 when passing arguments in ROM.
7828 *****************************************************************/
7829
7830 int FSrenamepgm (const rom char * fileName, FSFILE * fo)
7831 {
7832 #if defined(SUPPORT_LFN)
7833 char tempArray[257];
7834 unsigned short int count;
7835 #else
7836 char tempArray[13];
7837 BYTE count;
7838 #endif
7839
7840 *fileName;
7841 for(count = 0; count < sizeof(tempArray); count++)
7842 {
7843 _asm TBLRDPOSTINC _endasm
7844 tempArray[count] = TABLAT;
7845 }//end for(...)
7846
7847 return FSrename (tempArray, fo);
7848 }
7849 #endif
7850
7851 /******************************************************************************
7852 Function:
7853 FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode)
7854 Summary:
7855 Open a Ascii file named with a ROM string on PIC18
7856 Conditions:
7857 For read modes, file exists; FSInit performed
7858 Input:
7859 fileName - The name of the file to be opened (ROM)
7860 mode - The mode the file will be opened in (ROM)
7861 Return Values:
7862 FSFILE * - A pointer to the file object
7863 NULL - File could not be opened
7864 Side Effects:
7865 The FSerrno variable will be changed.
7866 Description:
7867 The FSfopenpgm function will copy a PIC18 ROM fileName and mode argument
7868 into RAM arrays, and then pass those arrays to the FSfopen function.
7869 Remarks:
7870 This function is for use with PIC18 when passing arguments in ROM.
7871 ******************************************************************************/
7872
7873
7874 FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode)
7875 {
7876 #if defined(SUPPORT_LFN)
7877 char tempArray[257];
7878 unsigned short int count = 0;
7879 #else
7880 char tempArray[13];
7881 BYTE count = 0;
7882 #endif
7883 char M[2];
7884
7885 for(;;)
7886 {
7887 tempArray[count] = fileName[count];
7888 if(tempArray[count])
7889 count++;
7890 else
7891 break;
7892 }
7893
7894 for (count = 0; count < 2; count++)
7895 {
7896 M[count] = *(mode + count);
7897 }
7898
7899 return FSfopen(tempArray, M);
7900 }
7901
7902 /*************************************************************
7903 Function:
7904 int FSremovepgm (const rom char * fileName)
7905 Summary:
7906 Delete a file named with a ROM string on PIC18
7907 Conditions:
7908 File not opened; file exists
7909 Input:
7910 fileName - The name of the file to be deleted (ROM)
7911 Return Values:
7912 0 - File was removed successfully
7913 -1 - File could not be removed
7914 Side Effects:
7915 The FSerrno variable will be changed.
7916 Description:
7917 The FSremovepgm function will copy a PIC18 ROM fileName argument
7918 into a RAM array, and then pass that array to the FSremove function.
7919 Remarks:
7920 This function is for use with PIC18 when passing arguments in ROM.
7921 *************************************************************/
7922 #ifdef ALLOW_WRITES
7923 int FSremovepgm (const rom char * fileName)
7924 {
7925 #ifdef SUPPORT_LFN
7926 char tempArray[257];
7927 unsigned short int count;
7928 #else
7929 char tempArray[13];
7930 BYTE count;
7931 #endif
7932
7933 *fileName;
7934 for(count = 0; count < sizeof(tempArray); count++)
7935 {
7936 _asm TBLRDPOSTINC _endasm
7937 tempArray[count] = TABLAT;
7938 }//end for(...)
7939
7940 return FSremove (tempArray);
7941 }
7942 #endif
7943
7944 /**************************************************************************************
7945 Function:
7946 int FindFirstpgm (const char * fileName, unsigned int attr, SearchRec * rec)
7947 Summary:
7948 Find a file named with a ROM string on PIC18
7949 Conditions:
7950 None
7951 Input:
7952 fileName - The name of the file to be found (ROM)
7953 attr - The attributes of the file to be found
7954 rec - Pointer to a search record to store the file info in
7955 Return Values:
7956 0 - File was found
7957 -1 - No file matching the given parameters was found
7958 Side Effects:
7959 Search criteria from previous FindFirst call on passed SearchRec object will be lost.
7960 The FSerrno variable will be changed.
7961 Description:
7962 The FindFirstpgm function will copy a PIC18 ROM fileName argument
7963 into a RAM array, and then pass that array to the FindFirst function.
7964 Remarks:
7965 Call FindFirstpgm or FindFirst before calling FindNext.
7966 This function is for use with PIC18 when passing arguments in ROM.
7967 **************************************************************************************/
7968 #ifdef ALLOW_FILESEARCH
7969 int FindFirstpgm (const rom char * fileName, unsigned int attr, SearchRec * rec)
7970 {
7971 #if defined(SUPPORT_LFN)
7972 char tempArray[257];
7973 unsigned short int count;
7974 #else
7975 char tempArray[13];
7976 BYTE count;
7977 #endif
7978
7979 *fileName;
7980 for(count = 0; count < sizeof(tempArray); count++)
7981 {
7982 _asm TBLRDPOSTINC _endasm
7983 tempArray[count] = TABLAT;
7984 }//end for
7985
7986 return FindFirst (tempArray,attr,rec);
7987 }
7988 #endif
7989 #endif
7990 #endif
7991
7992
7993 /***********************************************
7994 Function:
7995 DWORD ReadFAT (DISK *dsk, DWORD ccls)
7996 Summary:
7997 Read the next entry from the FAT
7998 Conditions:
7999 This function should not be called by the user.
8000 Input:
8001 dsk - The disk structure
8002 ccls - The current cluster
8003 Return:
8004 DWORD - The next cluster in a file chain
8005 Side Effects:
8006 None
8007 Description:
8008 The ReadFAT function will read the FAT and
8009 determine the next cluster value after the
8010 cluster specified by 'ccls.' Note that the
8011 FAT sector that is read is stored in the
8012 global FAT cache buffer.
8013 Remarks:
8014 None.
8015 ***********************************************/
8016
8017 DWORD ReadFAT (DISK *dsk, DWORD ccls)
8018 {
8019 BYTE q;
8020 DWORD p, l; // "l" is the sector Address
8021 DWORD c = 0, d, ClusterFailValue,LastClusterLimit; // ClusterEntries
8022
8023 gBufferZeroed = FALSE;
8024
8025 /* Settings based on FAT type */
8026 switch (dsk->type)
8027 {
8028 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8029 case FAT32:
8030 p = (DWORD)ccls * 4;
8031 q = 0; // "q" not used for FAT32, only initialized to remove a warning
8032 ClusterFailValue = CLUSTER_FAIL_FAT32;
8033 LastClusterLimit = LAST_CLUSTER_FAT32;
8034 break;
8035 #endif
8036 case FAT12:
8037 p = (DWORD) ccls *3; // Mulby1.5 to find cluster pos in FAT
8038 q = p&1;
8039 p >>= 1;
8040 ClusterFailValue = CLUSTER_FAIL_FAT16;
8041 LastClusterLimit = LAST_CLUSTER_FAT12;
8042 break;
8043 case FAT16:
8044 default:
8045 p = (DWORD)ccls *2; // Mulby 2 to find cluster pos in FAT
8046 q = 0; // "q" not used for FAT16, only initialized to remove a warning
8047 ClusterFailValue = CLUSTER_FAIL_FAT16;
8048 LastClusterLimit = LAST_CLUSTER_FAT16;
8049 break;
8050 }
8051
8052 l = dsk->fat + (p / dsk->sectorSize); //
8053 p &= dsk->sectorSize - 1; // Restrict 'p' within the FATbuffer size
8054
8055 // Check if the appropriate FAT sector is already loaded
8056 if (gLastFATSectorRead == l)
8057 {
8058 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8059 if (dsk->type == FAT32)
8060 c = RAMreadD (gFATBuffer, p);
8061 else
8062 #endif
8063 if(dsk->type == FAT16)
8064 c = RAMreadW (gFATBuffer, p);
8065 else if(dsk->type == FAT12)
8066 {
8067 c = RAMread (gFATBuffer, p);
8068 if (q)
8069 {
8070 c >>= 4;
8071 }
8072 // Check if the MSB is across the sector boundry
8073 p = (p +1) & (dsk->sectorSize-1);
8074 if (p == 0)
8075 {
8076 // Start by writing the sector we just worked on to the card
8077 // if we need to
8078 #ifdef ALLOW_WRITES
8079 if (gNeedFATWrite)
8080 if(WriteFAT (dsk, 0, 0, TRUE))
8081 return ClusterFailValue;
8082 #endif
8083 if (!MDD_SectorRead (l+1, gFATBuffer))
8084 {
8085 gLastFATSectorRead = 0xFFFF;
8086 return ClusterFailValue;
8087 }
8088 else
8089 {
8090 gLastFATSectorRead = l +1;
8091 }
8092 }
8093 d = RAMread (gFATBuffer, p);
8094 if (q)
8095 {
8096 c += (d <<4);
8097 }
8098 else
8099 {
8100 c += ((d & 0x0F)<<8);
8101 }
8102 }
8103 }
8104 else
8105 {
8106 // If there's a currently open FAT sector,
8107 // write it back before reading into the buffer
8108 #ifdef ALLOW_WRITES
8109 if (gNeedFATWrite)
8110 {
8111 if(WriteFAT (dsk, 0, 0, TRUE))
8112 return ClusterFailValue;
8113 }
8114 #endif
8115 if (!MDD_SectorRead (l, gFATBuffer))
8116 {
8117 gLastFATSectorRead = 0xFFFF; // Note: It is Sector not Cluster.
8118 return ClusterFailValue;
8119 }
8120 else
8121 {
8122 gLastFATSectorRead = l;
8123
8124 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8125 if (dsk->type == FAT32)
8126 c = RAMreadD (gFATBuffer, p);
8127 else
8128 #endif
8129 if(dsk->type == FAT16)
8130 c = RAMreadW (gFATBuffer, p);
8131 else if (dsk->type == FAT12)
8132 {
8133 c = RAMread (gFATBuffer, p);
8134 if (q)
8135 {
8136 c >>= 4;
8137 }
8138 p = (p +1) & (dsk->sectorSize-1);
8139 d = RAMread (gFATBuffer, p);
8140 if (q)
8141 {
8142 c += (d <<4);
8143 }
8144 else
8145 {
8146 c += ((d & 0x0F)<<8);
8147 }
8148 }
8149 }
8150 }
8151
8152 // Normalize it so 0xFFFF is an error
8153 if (c >= LastClusterLimit)
8154 c = LastClusterLimit;
8155
8156 return c;
8157 } // ReadFAT
8158
8159
8160
8161 /****************************************************************************
8162 Function:
8163 WORD WriteFAT (DISK *dsk, DWORD ccls, WORD value, BYTE forceWrite)
8164 Summary:
8165 Write an entry to the FAT
8166 Conditions:
8167 This function should not be called by the user.
8168 Input:
8169 dsk - The disk structure
8170 ccls - The current cluster
8171 value - The value to write in
8172 forceWrite - Force the function to write the current FAT sector
8173 Return:
8174 0 - The FAT write was successful
8175 FAIL - The FAT could not be written
8176 Side Effects:
8177 None
8178 Description:
8179 The WriteFAT function writes an entry to the FAT. If the function
8180 is called and the 'forceWrite' argument is TRUE, the function will
8181 write the existing FAT data to the device. Otherwise, the function
8182 will replace a single entry in the FAT buffer (indicated by 'ccls')
8183 with a new value (indicated by 'value.')
8184 Remarks:
8185 None.
8186 ****************************************************************************/
8187
8188 #ifdef ALLOW_WRITES
8189 DWORD WriteFAT (DISK *dsk, DWORD ccls, DWORD value, BYTE forceWrite)
8190 {
8191 BYTE i, q, c;
8192 DWORD p, li, l, ClusterFailValue;
8193
8194 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8195 if ((dsk->type != FAT32) && (dsk->type != FAT16) && (dsk->type != FAT12))
8196 return CLUSTER_FAIL_FAT32;
8197 #else // If FAT32 support not enabled
8198 if ((dsk->type != FAT16) && (dsk->type != FAT12))
8199 return CLUSTER_FAIL_FAT16;
8200 #endif
8201
8202 /* Settings based on FAT type */
8203 switch (dsk->type)
8204 {
8205 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8206 case FAT32:
8207 ClusterFailValue = CLUSTER_FAIL_FAT32;
8208 break;
8209 #endif
8210 case FAT12:
8211 case FAT16:
8212 default:
8213 ClusterFailValue = CLUSTER_FAIL_FAT16;
8214 break;
8215 }
8216
8217 gBufferZeroed = FALSE;
8218
8219 // The only purpose for calling this function with forceWrite
8220 // is to write the current FAT sector to the card
8221 if (forceWrite)
8222 {
8223 for (i = 0, li = gLastFATSectorRead; i < dsk->fatcopy; i++, li += dsk->fatsize)
8224 {
8225 if (!MDD_SectorWrite (li, gFATBuffer, FALSE))
8226 {
8227 return ClusterFailValue;
8228 }
8229 }
8230
8231 gNeedFATWrite = FALSE;
8232
8233 return 0;
8234 }
8235
8236 /* Settings based on FAT type */
8237 switch (dsk->type)
8238 {
8239 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8240 case FAT32:
8241 p = (DWORD)ccls *4; // "p" is the position in "gFATBuffer" for corresponding cluster.
8242 q = 0; // "q" not used for FAT32, only initialized to remove a warning
8243 break;
8244 #endif
8245 case FAT12:
8246 p = (DWORD) ccls * 3; // "p" is the position in "gFATBuffer" for corresponding cluster.
8247 q = p & 1; // Odd or even?
8248 p >>= 1;
8249 break;
8250 case FAT16:
8251 default:
8252 p = (DWORD) ccls *2; // "p" is the position in "gFATBuffer" for corresponding cluster.
8253 q = 0; // "q" not used for FAT16, only initialized to remove a warning
8254 break;
8255 }
8256
8257 l = dsk->fat + (p / dsk->sectorSize); //
8258 p &= dsk->sectorSize - 1; // Restrict 'p' within the FATbuffer size
8259
8260 if (gLastFATSectorRead != l)
8261 {
8262 // If we are loading a new sector then write
8263 // the current one to the card if we need to
8264 if (gNeedFATWrite)
8265 {
8266 for (i = 0, li = gLastFATSectorRead; i < dsk->fatcopy; i++, li += dsk->fatsize)
8267 {
8268 if (!MDD_SectorWrite (li, gFATBuffer, FALSE))
8269 {
8270 return ClusterFailValue;
8271 }
8272 }
8273
8274 gNeedFATWrite = FALSE;
8275 }
8276
8277 // Load the new sector
8278 if (!MDD_SectorRead (l, gFATBuffer))
8279 {
8280 gLastFATSectorRead = 0xFFFF;
8281 return ClusterFailValue;
8282 }
8283 else
8284 {
8285 gLastFATSectorRead = l;
8286 }
8287 }
8288
8289 #ifdef SUPPORT_FAT32 // If FAT32 supported.
8290 if (dsk->type == FAT32) // Refer page 16 of FAT requirement.
8291 {
8292 RAMwrite (gFATBuffer, p, ((value & 0x000000ff))); // lsb,1st byte of cluster value
8293 RAMwrite (gFATBuffer, p+1, ((value & 0x0000ff00) >> 8));
8294 RAMwrite (gFATBuffer, p+2, ((value & 0x00ff0000) >> 16));
8295 RAMwrite (gFATBuffer, p+3, ((value & 0x0f000000) >> 24)); // the MSB nibble is supposed to be "0" in FAT32. So mask it.
8296 }
8297 else
8298
8299 #endif
8300 {
8301 if (dsk->type == FAT16)
8302 {
8303 RAMwrite (gFATBuffer, p, value); //lsB
8304 RAMwrite (gFATBuffer, p+1, ((value&0x0000ff00) >> 8)); // msB
8305 }
8306 else if (dsk->type == FAT12)
8307 {
8308 // Get the current byte from the FAT
8309 c = RAMread (gFATBuffer, p);
8310 if (q)
8311 {
8312 c = ((value & 0x0F) << 4) | ( c & 0x0F);
8313 }
8314 else
8315 {
8316 c = (value & 0xFF);
8317 }
8318 // Write in those bits
8319 RAMwrite (gFATBuffer, p, c);
8320
8321 // FAT12 entries can cross sector boundaries
8322 // Check if we need to load a new sector
8323 p = (p +1) & (dsk->sectorSize-1);
8324 if (p == 0)
8325 {
8326 // call this function to update the FAT on the card
8327 if (WriteFAT (dsk, 0,0,TRUE))
8328 return ClusterFailValue;
8329
8330 // Load the next sector
8331 if (!MDD_SectorRead (l +1, gFATBuffer))
8332 {
8333 gLastFATSectorRead = 0xFFFF;
8334 return ClusterFailValue;
8335 }
8336 else
8337 {
8338 gLastFATSectorRead = l + 1;
8339 }
8340 }
8341
8342 // Get the second byte of the table entry
8343 c = RAMread (gFATBuffer, p);
8344 if (q)
8345 {
8346 c = (value >> 4);
8347 }
8348 else
8349 {
8350 c = ((value >> 8) & 0x0F) | (c & 0xF0);
8351 }
8352 RAMwrite (gFATBuffer, p, c);
8353 }
8354 }
8355 gNeedFATWrite = TRUE;
8356
8357 return 0;
8358 }
8359 #endif
8360
8361
8362 #ifdef ALLOW_DIRS
8363
8364 // This string is used by dir functions to hold dir names temporarily
8365 #if defined(SUPPORT_LFN)
8366 char tempDirectoryString [522];
8367 #else
8368 char tempDirectoryString [14];
8369 #endif
8370 /**************************************************************************
8371 Function:
8372 int FSchdir (char * path)
8373 Summary:
8374 Change the current working directory as per the path specified in Ascii format
8375 Conditions:
8376 None
8377 Input:
8378 path - The path of the directory to change to.
8379 Return Values:
8380 0 - The current working directory was changed successfully
8381 EOF - The current working directory could not be changed
8382 Side Effects:
8383 The current working directory may be changed. The FSerrno variable will
8384 be changed.
8385 Description:
8386 The FSchdir function passes a RAM pointer to the path to the
8387 chdirhelper function.
8388 Remarks:
8389 None
8390 **************************************************************************/
8391
8392 int FSchdir (char * path)
8393 {
8394 return chdirhelper (0, path, NULL);
8395 }
8396
8397 /**************************************************************************
8398 Function:
8399 int wFSchdir (unsigned short int * path)
8400 Summary:
8401 Change the current working directory as per the path specified in UTF16 format
8402 Conditions:
8403 None
8404 Input:
8405 path - The path of the directory to change to.
8406 Return Values:
8407 0 - The current working directory was changed successfully
8408 EOF - The current working directory could not be changed
8409 Side Effects:
8410 The current working directory may be changed. The FSerrno variable will
8411 be changed.
8412 Description:
8413 The wFSchdir function passes a RAM pointer to the path to the
8414 chdirhelper function.
8415 Remarks:
8416 None
8417 **************************************************************************/
8418 #ifdef SUPPORT_LFN
8419 int wFSchdir (unsigned short int * path)
8420 {
8421 int result;
8422 utfModeFileName = TRUE;
8423 result = chdirhelper (0, (char *)path, NULL);
8424 utfModeFileName = FALSE;
8425 return result;
8426 }
8427 #endif
8428
8429 /**************************************************************************
8430 Function:
8431 int FSchdirpgm (const rom char * path)
8432 Summary:
8433 Changed the CWD with a path in ROM on PIC18
8434 Conditions:
8435 None
8436 Input:
8437 path - The path of the directory to change to (ROM)
8438 Return Values:
8439 0 - The current working directory was changed successfully
8440 EOF - The current working directory could not be changed
8441 Side Effects:
8442 The current working directory may be changed. The FSerrno variable will
8443 be changed.
8444 Description:
8445 The FSchdirpgm function passes a PIC18 ROM path pointer to the
8446 chdirhelper function.
8447 Remarks:
8448 This function is for use with PIC18 when passing arguments in ROM
8449 **************************************************************************/
8450
8451 #ifdef ALLOW_PGMFUNCTIONS
8452 int FSchdirpgm (const rom char * path)
8453 {
8454 return chdirhelper (1, NULL, path);
8455 }
8456
8457 /**************************************************************************
8458 Function:
8459 int wFSchdirpgm (const rom unsigned short int * path)
8460 Summary:
8461 Changed the CWD with a path in ROM on PIC18
8462 Conditions:
8463 None
8464 Input:
8465 path - The path of the directory to change to (ROM)
8466 Return Values:
8467 0 - The current working directory was changed successfully
8468 EOF - The current working directory could not be changed
8469 Side Effects:
8470 The current working directory may be changed. The FSerrno variable will
8471 be changed.
8472 Description:
8473 The FSchdirpgm function passes a PIC18 ROM path pointer to the
8474 chdirhelper function.
8475 Remarks:
8476 This function is for use with PIC18 when passing arguments in ROM
8477 **************************************************************************/
8478 #ifdef SUPPORT_LFN
8479 int wFSchdirpgm (const rom unsigned short int * path)
8480 {
8481 int result;
8482 utfModeFileName = TRUE;
8483 result = chdirhelper (1, NULL, (const char *)path);
8484 utfModeFileName = FALSE;
8485 return result;
8486 }
8487 #endif
8488
8489 #endif
8490
8491 /*************************************************************************
8492 Function:
8493 // PIC24/30/33/32
8494 int chdirhelper (BYTE mode, char * ramptr, char * romptr);
8495 // PIC18
8496 int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr);
8497 Summary:
8498 Helper function for FSchdir
8499 Conditions:
8500 None
8501 Input:
8502 mode - Indicates which path pointer to use
8503 ramptr - Pointer to the path specified in RAM
8504 romptr - Pointer to the path specified in ROM
8505 Return Values:
8506 0 - Directory was changed successfully.
8507 EOF - Directory could not be changed.
8508 Side Effects:
8509 The current working directory will be changed. The FSerrno variable
8510 will be changed. Any unwritten data in the data buffer will be written
8511 to the device.
8512 Description:
8513 This helper function is used by the FSchdir function. If the path
8514 argument is specified in ROM for PIC18 this function will be able to
8515 parse it correctly. The function will loop through a switch statement
8516 to process the tokens in the path string. Dot or dotdot entries are
8517 handled in the first case statement. A backslash character is handled
8518 in the second case statement (note that this case statement will only
8519 be used if backslash is the first character in the path; backslash
8520 token delimiters will automatically be skipped after each token in the
8521 path is processed). The third case statement will handle actual
8522 directory name strings.
8523 Remarks:
8524 None.
8525 *************************************************************************/
8526
8527 #ifdef ALLOW_PGMFUNCTIONS
8528 int chdirhelper (BYTE mode, char * ramptr, const rom char * romptr)
8529 #else
8530 int chdirhelper (BYTE mode, char * ramptr, char * romptr)
8531 #endif
8532 {
8533 unsigned short int i,j,k = 0;
8534 WORD curent = 1;
8535 DIRENTRY entry;
8536 char * temppath = ramptr;
8537 #ifdef ALLOW_PGMFUNCTIONS
8538 rom char * temppath2 = romptr;
8539 rom unsigned short int * utf16path2 = (rom unsigned short int *)romptr;
8540 #endif
8541 #ifdef SUPPORT_LFN
8542 unsigned short int *utf16path = (unsigned short int *)ramptr;
8543 #endif
8544
8545 FSFILE tempCWDobj2;
8546 FILEOBJ tempCWD = &tempCWDobj2;
8547
8548 FileObjectCopy (tempCWD, cwdptr);
8549
8550 FSerrno = CE_GOOD;
8551
8552 // Check the first char of the path
8553 #ifdef ALLOW_PGMFUNCTIONS
8554 if (mode)
8555 {
8556 #ifdef SUPPORT_LFN
8557 if(utfModeFileName)
8558 {
8559 i = *utf16path2;
8560 }
8561 else
8562 #endif
8563 {
8564 i = *temppath2;
8565 }
8566 }
8567 else
8568 #endif
8569 {
8570 #ifdef SUPPORT_LFN
8571 if(utfModeFileName)
8572 {
8573 i = *utf16path;
8574 }
8575 else
8576 #endif
8577 {
8578 i = *temppath;
8579 }
8580 }
8581
8582 // if NULL character return error
8583 if (i == 0)
8584 {
8585 FSerrno = CE_INVALID_ARGUMENT;
8586 return -1;
8587 }
8588
8589 while(1)
8590 {
8591 switch (i)
8592 {
8593 // First case: dot or dotdot entry
8594 case '.':
8595 // Move past the dot
8596 #ifdef ALLOW_PGMFUNCTIONS
8597 if (mode)
8598 {
8599 #ifdef SUPPORT_LFN
8600 if(utfModeFileName)
8601 {
8602 utf16path2++;
8603 i = *utf16path2;
8604 }
8605 else
8606 #endif
8607 {
8608 temppath2++;
8609 i = *temppath2;
8610 }
8611 }
8612 else
8613 {
8614 #endif
8615 #ifdef SUPPORT_LFN
8616 if(utfModeFileName)
8617 {
8618 utf16path++;
8619 i = *utf16path;
8620 }
8621 else
8622 #endif
8623 {
8624 temppath++;
8625 i = *temppath;
8626 }
8627 #ifdef ALLOW_PGMFUNCTIONS
8628 }
8629 #endif
8630 // Check if it's a dotdot entry
8631 if (i == '.')
8632 {
8633 // Increment the path variable
8634 #ifdef ALLOW_PGMFUNCTIONS
8635 if (mode)
8636 {
8637 #ifdef SUPPORT_LFN
8638 if(utfModeFileName)
8639 {
8640 utf16path2++;
8641 i = *utf16path2;
8642 }
8643 else
8644 #endif
8645 {
8646 temppath2++;
8647 i = *temppath2;
8648 }
8649 }
8650 else
8651 {
8652 #endif
8653 #ifdef SUPPORT_LFN
8654 if(utfModeFileName)
8655 {
8656 utf16path++;
8657 i = *utf16path;
8658 }
8659 else
8660 #endif
8661 {
8662 temppath++;
8663 i = *temppath;
8664 }
8665 #ifdef ALLOW_PGMFUNCTIONS
8666 }
8667 #endif
8668 // Check if we're in the root
8669 if (tempCWD->dirclus == FatRootDirClusterValue)
8670 {
8671 // Fails if there's a dotdot chdir from the root
8672 FSerrno = CE_INVALID_ARGUMENT;
8673 return -1;
8674 }
8675 else
8676 {
8677 // Cache the dotdot entry
8678 tempCWD->dirccls = tempCWD->dirclus;
8679 curent = 1;
8680 entry = Cache_File_Entry (tempCWD, &curent, TRUE);
8681 if (entry == NULL)
8682 {
8683 FSerrno = CE_BADCACHEREAD;
8684 return -1;
8685 }
8686
8687 // Get the cluster
8688 tempCWD->dirclus = GetFullClusterNumber(entry); // Get Complete Cluster number.
8689 tempCWD->dirccls = tempCWD->dirclus;
8690
8691 // If we changed to root, record the name
8692 if (tempCWD->dirclus == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT) // "0" is the value of Dotdot entry for Root in both FAT types.
8693 {
8694 j = 0;
8695 tempCWD->name[j++] = '\\';
8696 // if(utfModeFileName)
8697 // {
8698 // tempCWD->name[j++] = 0x00;
8699 // }
8700 for (;j < 11;)
8701 {
8702 tempCWD->name[j] = 0x20;
8703 ++j;
8704 }
8705
8706 /* While moving to Root, get the Root cluster value */
8707 tempCWD->dirccls = FatRootDirClusterValue;
8708 tempCWD->dirclus = FatRootDirClusterValue;
8709 }
8710 else
8711 {
8712 // Otherwise set the name to ..
8713 j = 0;
8714 tempCWD->name[j++] = '.';
8715 // if(utfModeFileName)
8716 // {
8717 // tempCWD->name[j++] = 0x00;
8718 // tempCWD->name[j++] = '.';
8719 // tempCWD->name[j++] = 0x00;
8720 // }
8721 // else
8722 {
8723 tempCWD->name[j++] = '.';
8724 }
8725 for (; j < 11;)
8726 {
8727 tempCWD->name[j] = 0x20;
8728 ++j;
8729 }
8730 }
8731 // Cache the dot entry
8732 curent = 0;
8733 if (Cache_File_Entry(tempCWD, &curent, TRUE) == NULL)
8734 {
8735 FSerrno = CE_BADCACHEREAD;
8736 return -1;
8737 }
8738 // Move past the next backslash, if necessary
8739 while (i == '\\')
8740 {
8741 #ifdef ALLOW_PGMFUNCTIONS
8742 if (mode)
8743 {
8744 #ifdef SUPPORT_LFN
8745 if(utfModeFileName)
8746 {
8747 utf16path2++;
8748 i = *utf16path2;
8749 }
8750 else
8751 #endif
8752 {
8753 temppath2++;
8754 i = *temppath2;
8755 }
8756 }
8757 else
8758 {
8759 #endif
8760 #ifdef SUPPORT_LFN
8761 if(utfModeFileName)
8762 {
8763 utf16path++;
8764 i = *utf16path;
8765 }
8766 else
8767 #endif
8768 {
8769 temppath++;
8770 i = *temppath;
8771 }
8772 #ifdef ALLOW_PGMFUNCTIONS
8773 }
8774 #endif
8775 }
8776 // Copy and return, if we're at the end
8777 if (i == 0)
8778 {
8779 FileObjectCopy (cwdptr, tempCWD);
8780 return 0;
8781 }
8782 }
8783 }
8784 else
8785 {
8786 // If we ended with a . entry,
8787 // just return what we have
8788 if (i == 0)
8789 {
8790 FileObjectCopy (cwdptr, tempCWD);
8791 return 0;
8792 }
8793 else
8794 {
8795 if (i == '\\')
8796 {
8797 while (i == '\\')
8798 {
8799 #ifdef ALLOW_PGMFUNCTIONS
8800 if (mode)
8801 {
8802 #ifdef SUPPORT_LFN
8803 if(utfModeFileName)
8804 {
8805 utf16path2++;
8806 i = *utf16path2;
8807 }
8808 else
8809 #endif
8810 {
8811 temppath2++;
8812 i = *temppath2;
8813 }
8814 }
8815 else
8816 {
8817 #endif
8818 #ifdef SUPPORT_LFN
8819 if(utfModeFileName)
8820 {
8821 utf16path++;
8822 i = *utf16path;
8823 }
8824 else
8825 #endif
8826 {
8827 temppath++;
8828 i = *temppath;
8829 }
8830 #ifdef ALLOW_PGMFUNCTIONS
8831 }
8832 #endif
8833 }
8834 if (i == 0)
8835 {
8836 FileObjectCopy (cwdptr, tempCWD);
8837 return 0;
8838 }
8839 }
8840 else
8841 {
8842 // Anything else after a dot doesn't make sense
8843 FSerrno = CE_INVALID_ARGUMENT;
8844 return -1;
8845 }
8846 }
8847 }
8848
8849 break;
8850
8851 // Second case: the first char is the root backslash
8852 // We will ONLY switch to this case if the first char
8853 // of the path is a backslash
8854 case '\\':
8855 // Increment pointer to second char
8856 #ifdef ALLOW_PGMFUNCTIONS
8857 if (mode)
8858 {
8859 #ifdef SUPPORT_LFN
8860 if(utfModeFileName)
8861 {
8862 utf16path2++;
8863 i = *utf16path2;
8864 }
8865 else
8866 #endif
8867 {
8868 temppath2++;
8869 i = *temppath2;
8870 }
8871 }
8872 else
8873 {
8874 #endif
8875 #ifdef SUPPORT_LFN
8876 if(utfModeFileName)
8877 {
8878 utf16path++;
8879 i = *utf16path;
8880 }
8881 else
8882 #endif
8883 {
8884 temppath++;
8885 i = *temppath;
8886 }
8887 #ifdef ALLOW_PGMFUNCTIONS
8888 }
8889 #endif
8890 // Can't start the path with multiple backslashes
8891 if (i == '\\')
8892 {
8893 FSerrno = CE_INVALID_ARGUMENT;
8894 return -1;
8895 }
8896
8897 if (i == 0)
8898 {
8899 // The user is changing directory to
8900 // the root
8901 cwdptr->dirclus = FatRootDirClusterValue;
8902 cwdptr->dirccls = FatRootDirClusterValue;
8903 j = 0;
8904 cwdptr->name[j++] = '\\';
8905 // if(utfModeFileName)
8906 // {
8907 // cwdptr->name[j++] = 0x00;
8908 // }
8909 for (; j < 11;)
8910 {
8911 cwdptr->name[j] = 0x20;
8912 ++j;
8913 }
8914 return 0;
8915 }
8916 else
8917 {
8918 // Our first char is the root dir switch
8919 tempCWD->dirclus = FatRootDirClusterValue;
8920 tempCWD->dirccls = FatRootDirClusterValue;
8921 j = 0;
8922 tempCWD->name[j++] = '\\';
8923 // if(utfModeFileName)
8924 // {
8925 // tempCWD->name[j++] = 0x00;
8926 // }
8927 for (; j < 11;)
8928 {
8929 tempCWD->name[j] = 0x20;
8930 ++j;
8931 }
8932 }
8933 break;
8934
8935 default:
8936 // We should be at the beginning of a string of letters/numbers
8937 j = 0;
8938 #ifdef ALLOW_PGMFUNCTIONS
8939 if (mode)
8940 {
8941 #ifdef SUPPORT_LFN
8942 if(utfModeFileName)
8943 {
8944 // Change directories as specified
8945 k = 512;
8946
8947 // Parse the next token
8948 while ((i != 0) && (i != '\\') && (j < k))
8949 {
8950 tempDirectoryString[j++] = i;
8951 tempDirectoryString[j++] = i >> 8;
8952 i = *(++utf16path2);
8953 }
8954
8955 tempDirectoryString[j++] = 0;
8956 }
8957 else
8958 #endif
8959 {
8960 #if defined(SUPPORT_LFN)
8961 k = 256;
8962 #else
8963 k = 12;
8964 #endif
8965
8966 // Parse the next token
8967 while ((i != 0) && (i != '\\') && (j < k))
8968 {
8969 tempDirectoryString[j++] = i;
8970 i = *(++temppath2);
8971 }
8972 }
8973 }
8974 else
8975 {
8976 #endif
8977 #ifdef SUPPORT_LFN
8978 if(utfModeFileName)
8979 {
8980 // Change directories as specified
8981 k = 512;
8982
8983 // Parse the next token
8984 while ((i != 0) && (i != '\\') && (j < k))
8985 {
8986 tempDirectoryString[j++] = i;
8987 tempDirectoryString[j++] = i >> 8;
8988 i = *(++utf16path);
8989 }
8990
8991 tempDirectoryString[j++] = 0;
8992 }
8993 else
8994 #endif
8995 {
8996 #if defined(SUPPORT_LFN)
8997 k = 256;
8998 #else
8999 k = 12;
9000 #endif
9001
9002 // Parse the next token
9003 while ((i != 0) && (i != '\\') && (j < k))
9004 {
9005 tempDirectoryString[j++] = i;
9006 i = *(++temppath);
9007 }
9008 }
9009 #ifdef ALLOW_PGMFUNCTIONS
9010 }
9011 #endif
9012
9013 tempDirectoryString[j++] = 0;
9014
9015 // We got a whole 12 chars
9016 // There could be more- truncate it
9017 if (j > k)
9018 {
9019 while ((i != 0) && (i != '\\'))
9020 {
9021 #ifdef ALLOW_PGMFUNCTIONS
9022 if (mode)
9023 {
9024 #ifdef SUPPORT_LFN
9025 if(utfModeFileName)
9026 {
9027 i = *(++utf16path2);
9028 }
9029 else
9030 #endif
9031 {
9032 i = *(++temppath2);
9033 }
9034 }
9035 else
9036 {
9037 #endif
9038 #ifdef SUPPORT_LFN
9039 if(utfModeFileName)
9040 {
9041 i = *(++utf16path);
9042 }
9043 else
9044 #endif
9045 {
9046 i = *(++temppath);
9047 }
9048 #ifdef ALLOW_PGMFUNCTIONS
9049 }
9050 #endif
9051 }
9052 }
9053
9054 if (FormatDirName (tempDirectoryString, tempCWD,0) == FALSE)
9055 return -1;
9056
9057 // copy file object over
9058 FileObjectCopy(&gFileTemp, tempCWD);
9059
9060 // See if the directory is there
9061 if(FILEfind (&gFileTemp, tempCWD, LOOK_FOR_MATCHING_ENTRY, 0) != CE_GOOD)
9062 {
9063 // Couldn't find the DIR
9064 FSerrno = CE_DIR_NOT_FOUND;
9065 return -1;
9066 }
9067 else
9068 {
9069 // Found the file
9070 // Check to make sure it's actually a directory
9071 if ((gFileTemp.attributes & ATTR_DIRECTORY) == 0 )
9072 {
9073 FSerrno = CE_INVALID_ARGUMENT;
9074 return -1;
9075 }
9076
9077 // Get the new name
9078 #if defined(SUPPORT_LFN)
9079 if(!tempCWD->utf16LFNlength)
9080 #endif
9081 for (j = 0; j < 11; j++)
9082 {
9083 tempCWD->name[j] = gFileTemp.name[j];
9084 }
9085
9086 tempCWD->dirclus = gFileTemp.cluster;
9087 tempCWD->dirccls = tempCWD->dirclus;
9088 }
9089
9090 if (i == 0)
9091 {
9092 // If we're at the end of the string, we're done
9093 FileObjectCopy (cwdptr, tempCWD);
9094 return 0;
9095 }
9096 else
9097 {
9098 while (i == '\\')
9099 {
9100 // If we get to another backslash, increment past it
9101 #ifdef ALLOW_PGMFUNCTIONS
9102 if (mode)
9103 {
9104 #ifdef SUPPORT_LFN
9105 if(utfModeFileName)
9106 {
9107 utf16path2++;
9108 i = *utf16path2;
9109 }
9110 else
9111 #endif
9112 {
9113 temppath2++;
9114 i = *temppath2;
9115 }
9116 }
9117 else
9118 {
9119 #endif
9120 #ifdef SUPPORT_LFN
9121 if(utfModeFileName)
9122 {
9123 utf16path++;
9124 i = *utf16path;
9125 }
9126 else
9127 #endif
9128 {
9129 temppath++;
9130 i = *temppath;
9131 }
9132 #ifdef ALLOW_PGMFUNCTIONS
9133 }
9134 #endif
9135 if (i == 0)
9136 {
9137 FileObjectCopy (cwdptr, tempCWD);
9138 return 0;
9139 }
9140 }
9141 }
9142 break;
9143 }
9144 } // loop
9145 }
9146
9147
9148
9149 // This string is used by FSgetcwd to return the cwd name if the path
9150 // passed into the function is NULL
9151 char defaultArray [10];
9152
9153
9154 /**************************************************************
9155 Function:
9156 char * FSgetcwd (char * path, int numchars)
9157 Summary:
9158 Get the current working directory path in Ascii format
9159 Conditions:
9160 None
9161 Input:
9162 path - Pointer to the array to return the cwd name in
9163 numchars - Number of chars in the path
9164 Return Values:
9165 char * - The cwd name string pointer (path or defaultArray)
9166 NULL - The current working directory name could not be loaded.
9167 Side Effects:
9168 The FSerrno variable will be changed
9169 Description:
9170 The FSgetcwd function will get the name of the current
9171 working directory and return it to the user. The name
9172 will be copied into the buffer pointed to by 'path,'
9173 starting at the root directory and copying as many chars
9174 as possible before the end of the buffer. The buffer
9175 size is indicated by the 'numchars' argument. The first
9176 thing this function will do is load the name of the current
9177 working directory, if it isn't already present. This could
9178 occur if the user switched to the dotdot entry of a
9179 subdirectory immediately before calling this function. The
9180 function will then copy the current working directory name
9181 into the buffer backwards, and insert a backslash character.
9182 Next, the function will continuously switch to the previous
9183 directories and copy their names backwards into the buffer
9184 until it reaches the root. If the buffer overflows, it
9185 will be treated as a circular buffer, and data will be
9186 copied over existing characters, starting at the beginning.
9187 Once the root directory is reached, the text in the buffer
9188 will be swapped, so that the buffer contains as much of the
9189 current working directory name as possible, starting at the
9190 root.
9191 Remarks:
9192 None
9193 **************************************************************/
9194 char * FSgetcwd (char * path, int numchars)
9195 {
9196 // If path is passed in as null, set up a default
9197 // array with 10 characters
9198 unsigned short int totalchars = (path == NULL) ? 10 : numchars;
9199 char * returnPointer;
9200 char * bufferEnd;
9201 FILEOBJ tempCWD = &gFileTemp;
9202 BYTE bufferOverflow = FALSE;
9203 signed char j;
9204 DWORD curclus;
9205 WORD fHandle, tempindex;
9206 short int i = 0, index = 0;
9207 char aChar;
9208 DIRENTRY entry;
9209
9210 #if defined(SUPPORT_LFN)
9211 WORD prevHandle;
9212 UINT16_VAL tempShift;
9213 FSFILE cwdTemp;
9214 LFN_ENTRY *lfno;
9215 unsigned short int *tempLFN = (unsigned short int *)&tempDirectoryString[0];
9216 #endif
9217
9218 FSerrno = CE_GOOD;
9219
9220 // Set up the return value
9221 if (path == NULL)
9222 returnPointer = defaultArray;
9223 else
9224 {
9225 returnPointer = path;
9226 if (numchars == 0)
9227 {
9228 FSerrno = CE_INVALID_ARGUMENT;
9229 return NULL;
9230 }
9231 }
9232
9233 bufferEnd = returnPointer + totalchars - 1;
9234
9235 FileObjectCopy (tempCWD, cwdptr);
9236
9237 if (((tempCWD->name[0] == '.') && (tempCWD->name[1] == '.'))
9238 #if defined(SUPPORT_LFN)
9239 || tempCWD->utf16LFNlength
9240 #endif
9241 )
9242 {
9243 // We last changed directory into a dotdot entry
9244 // Save the value of the current directory
9245 curclus = tempCWD->dirclus;
9246 // Put this dir's dotdot entry into the dirclus
9247 // Our cwd absolutely is not the root
9248 fHandle = 1;
9249 tempCWD->dirccls = tempCWD->dirclus;
9250 entry = Cache_File_Entry (tempCWD,&fHandle, TRUE);
9251 if (entry == NULL)
9252 {
9253 FSerrno = CE_BADCACHEREAD;
9254 return NULL;
9255 }
9256
9257 // Get the cluster
9258 TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number.
9259
9260 // For FAT32, if the .. entry is 0, the cluster won't be 0
9261 #ifdef SUPPORT_FAT32
9262 if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT)
9263 {
9264 tempCWD->dirclus = FatRootDirClusterValue;
9265 }
9266 else
9267 #endif
9268 tempCWD->dirclus = TempClusterCalc;
9269
9270 tempCWD->dirccls = tempCWD->dirclus;
9271
9272 // Find the direntry for the entry we were just in
9273 fHandle = 0;
9274 entry = Cache_File_Entry (tempCWD, &fHandle, TRUE);
9275 if (entry == NULL)
9276 {
9277 FSerrno = CE_BADCACHEREAD;
9278 return NULL;
9279 }
9280
9281 // Get the cluster
9282 TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number.
9283
9284 while ((TempClusterCalc != curclus) ||
9285 ((TempClusterCalc == curclus) &&
9286 (((unsigned char)entry->DIR_Name[0] == 0xE5) || (entry->DIR_Attr == ATTR_VOLUME) || (entry->DIR_Attr == ATTR_LONG_NAME))))
9287 {
9288 fHandle++;
9289 entry = Cache_File_Entry (tempCWD, &fHandle, FALSE);
9290 if (entry == NULL)
9291 {
9292 FSerrno = CE_BADCACHEREAD;
9293 return NULL;
9294 }
9295
9296 // Get the cluster
9297 TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number in a loop.
9298 }
9299
9300 #if defined(SUPPORT_LFN)
9301 FileObjectCopy (&cwdTemp, tempCWD);
9302 prevHandle = fHandle - 1;
9303 lfno = (LFN_ENTRY *)Cache_File_Entry (tempCWD, &prevHandle, FALSE);
9304
9305 while((lfno->LFN_Attribute == ATTR_LONG_NAME) && (lfno->LFN_SequenceNo != DIR_DEL)
9306 && (lfno->LFN_SequenceNo != DIR_EMPTY))
9307 {
9308 tempShift.byte.LB = lfno->LFN_Part1[0];
9309 tempShift.byte.HB = lfno->LFN_Part1[1];
9310 tempLFN[i++] = tempShift.Val;
9311 tempShift.byte.LB = lfno->LFN_Part1[2];
9312 tempShift.byte.HB = lfno->LFN_Part1[3];
9313 tempLFN[i++] = tempShift.Val;
9314 tempShift.byte.LB = lfno->LFN_Part1[4];
9315 tempShift.byte.HB = lfno->LFN_Part1[5];
9316 tempLFN[i++] = tempShift.Val;
9317 tempShift.byte.LB = lfno->LFN_Part1[6];
9318 tempShift.byte.HB = lfno->LFN_Part1[7];
9319 tempLFN[i++] = tempShift.Val;
9320 tempShift.byte.LB = lfno->LFN_Part1[8];
9321 tempShift.byte.HB = lfno->LFN_Part1[9];
9322 tempLFN[i++] = tempShift.Val;
9323
9324 tempLFN[i++] = lfno->LFN_Part2[0];
9325 tempLFN[i++] = lfno->LFN_Part2[1];
9326 tempLFN[i++] = lfno->LFN_Part2[2];
9327 tempLFN[i++] = lfno->LFN_Part2[3];
9328 tempLFN[i++] = lfno->LFN_Part2[4];
9329 tempLFN[i++] = lfno->LFN_Part2[5];
9330
9331 tempLFN[i++] = lfno->LFN_Part3[0];
9332 tempLFN[i++] = lfno->LFN_Part3[1];
9333
9334 prevHandle = prevHandle - 1;
9335 lfno = (LFN_ENTRY *)Cache_File_Entry (tempCWD, &prevHandle, FALSE);
9336 }
9337 FileObjectCopy (tempCWD, &cwdTemp);
9338 #endif
9339
9340 if(i == 0)
9341 {
9342 for (j = 0; j < 11; j++)
9343 {
9344 tempCWD->name[j] = entry->DIR_Name[j];
9345 cwdptr->name[j] = entry->DIR_Name[j];
9346 }
9347 #if defined(SUPPORT_LFN)
9348 cwdptr->utf16LFNlength = 0;
9349 tempCWD->utf16LFNlength = 0;
9350 #endif
9351 }
9352 #if defined(SUPPORT_LFN)
9353 else
9354 {
9355 tempCWD->utf16LFNlength = i;
9356 for(j = 12;j >= 0;j--)
9357 {
9358 if((tempLFN[i - j - 1]) == 0x0000)
9359 {
9360 tempCWD->utf16LFNlength = i - j;
9361 break;
9362 }
9363 }
9364 cwdptr->utf16LFNlength = tempCWD->utf16LFNlength;
9365 tempCWD->utf16LFNptr = (unsigned short int *)&tempDirectoryString[0];
9366 cwdptr->utf16LFNptr = (unsigned short int *)&tempDirectoryString[0];
9367 }
9368 #endif
9369 // Reset our temp dir back to that cluster
9370 tempCWD->dirclus = curclus;
9371 tempCWD->dirccls = curclus;
9372 // This will set us at the cwd, but it will actually
9373 // have the name in the name field this time
9374 }
9375
9376 // There's actually some kind of name value in the cwd
9377 #if defined(SUPPORT_LFN)
9378 if (((tempCWD->name[0] == '\\') && (tempCWD->utf16LFNlength == 0x0000)) ||
9379 ((tempCWD->utf16LFNlength != 0x0000) && (tempCWD->utf16LFNptr[0] == (unsigned short int)'\\')) || (numchars == 0x02))
9380 #else
9381 if ((tempCWD->name[0] == '\\') || (numchars == 0x02))
9382 #endif
9383 {
9384 // Easy, our CWD is the root
9385 *returnPointer = '\\';
9386 *(returnPointer + 1) = 0;
9387 return returnPointer;
9388 }
9389 else
9390 {
9391 index = 0;
9392 // Loop until we get back to the root
9393 while (tempCWD->dirclus != FatRootDirClusterValue)
9394 {
9395 #if defined(SUPPORT_LFN)
9396 if(tempCWD->utf16LFNlength)
9397 {
9398 i = tempCWD->utf16LFNlength * 2 - 3;
9399 while(i >= 0)
9400 {
9401 #ifdef SUPPORT_LFN
9402 if(twoByteMode)
9403 {
9404 returnPointer[index++] = tempDirectoryString[i--];
9405 if (index == totalchars)
9406 {
9407 index = 0;
9408 bufferOverflow = TRUE;
9409 }
9410 }
9411 else
9412 #endif
9413 {
9414 if(tempDirectoryString[i])
9415 {
9416 returnPointer[index++] = tempDirectoryString[i];
9417 if (index == totalchars)
9418 {
9419 index = 0;
9420 bufferOverflow = TRUE;
9421 }
9422
9423 }
9424 i--;
9425 }
9426 }
9427 }
9428 else
9429 #endif
9430 {
9431 j = 10;
9432 while (tempCWD->name[j] == 0x20)
9433 j--;
9434 if (j >= 8)
9435 {
9436 while (j >= 8)
9437 {
9438 *(returnPointer + index++) = tempCWD->name[j--];
9439 // This is a circular buffer
9440 // Any unnecessary values will be overwritten
9441 if (index == totalchars)
9442 {
9443 index = 0;
9444 bufferOverflow = TRUE;
9445 }
9446
9447 #ifdef SUPPORT_LFN
9448 if(twoByteMode)
9449 {
9450 returnPointer[index++] = 0x00;
9451 if (index == totalchars)
9452 {
9453 index = 0;
9454 bufferOverflow = TRUE;
9455 }
9456 }
9457 #endif
9458 }
9459
9460 *(returnPointer + index++) = '.';
9461 if (index == totalchars)
9462 {
9463 index = 0;
9464 bufferOverflow = TRUE;
9465 }
9466
9467 #ifdef SUPPORT_LFN
9468 if(twoByteMode)
9469 {
9470 returnPointer[index++] = 0x00;
9471 if (index == totalchars)
9472 {
9473 index = 0;
9474 bufferOverflow = TRUE;
9475 }
9476 }
9477 #endif
9478 }
9479
9480 while (tempCWD->name[j] == 0x20)
9481 j--;
9482
9483 while (j >= 0)
9484 {
9485 *(returnPointer + index++) = tempCWD->name[j--];
9486 // This is a circular buffer
9487 // Any unnecessary values will be overwritten
9488 if (index == totalchars)
9489 {
9490 index = 0;
9491 bufferOverflow = TRUE;
9492 }
9493
9494 #ifdef SUPPORT_LFN
9495 if(twoByteMode)
9496 {
9497 returnPointer[index++] = 0x00;
9498 if (index == totalchars)
9499 {
9500 index = 0;
9501 bufferOverflow = TRUE;
9502 }
9503 }
9504 #endif
9505 }
9506 }
9507
9508 #ifdef SUPPORT_LFN
9509 if(twoByteMode)
9510 {
9511 returnPointer[index++] = 0x00;
9512 if (index == totalchars)
9513 {
9514 index = 0;
9515 bufferOverflow = TRUE;
9516 }
9517 }
9518 #endif
9519
9520 // Put a backslash delimiter in front of the dir name
9521 *(returnPointer + index++) = '\\';
9522 if (index == totalchars)
9523 {
9524 index = 0;
9525 bufferOverflow = TRUE;
9526 }
9527
9528 // Load the previous entry
9529 tempCWD->dirccls = tempCWD->dirclus;
9530 if (GetPreviousEntry (tempCWD))
9531 {
9532 FSerrno = CE_BAD_SECTOR_READ;
9533 return NULL;
9534 }
9535 }
9536 }
9537
9538 // Point the index back at the last char in the string
9539 index--;
9540
9541 i = 0;
9542 // Swap the chars in the buffer so they are in the right places
9543 if (bufferOverflow)
9544 {
9545 tempindex = index;
9546 // Swap the overflowed values in the buffer
9547 while ((index - i) > 0)
9548 {
9549 aChar = *(returnPointer + i);
9550 *(returnPointer + i) = * (returnPointer + index);
9551 *(returnPointer + index) = aChar;
9552 index--;
9553 i++;
9554 }
9555
9556 // Point at the non-overflowed values
9557 i = tempindex + 1;
9558 index = bufferEnd - returnPointer;
9559
9560 // Swap the non-overflowed values into the right places
9561 while ((index - i) > 0)
9562 {
9563 aChar = *(returnPointer + i);
9564 *(returnPointer + i) = * (returnPointer + index);
9565 *(returnPointer + index) = aChar;
9566 index--;
9567 i++;
9568 }
9569 // All the values should be in the right place now
9570 // Null-terminate the string
9571 *(bufferEnd) = 0;
9572 }
9573 else
9574 {
9575 // There was no overflow, just do one set of swaps
9576 tempindex = index;
9577 while ((index - i) > 0)
9578 {
9579 aChar = *(returnPointer + i);
9580 *(returnPointer + i) = * (returnPointer + index);
9581 *(returnPointer + index) = aChar;
9582 index--;
9583 i++;
9584 }
9585 *(returnPointer + tempindex + 1) = 0;
9586 }
9587
9588 return returnPointer;
9589 }
9590
9591 #ifdef SUPPORT_LFN
9592
9593 /**************************************************************
9594 Function:
9595 char * wFSgetcwd (unsigned short int * path, int numchars)
9596 Summary:
9597 Get the current working directory path in UTF16 format
9598 Conditions:
9599 None
9600 Input:
9601 path - Pointer to the array to return the cwd name in
9602 numchars - Number of chars in the path
9603 Return Values:
9604 char * - The cwd name string pointer (path or defaultArray)
9605 NULL - The current working directory name could not be loaded.
9606 Side Effects:
9607 The FSerrno variable will be changed
9608 Description:
9609 The FSgetcwd function will get the name of the current
9610 working directory and return it to the user. The name
9611 will be copied into the buffer pointed to by 'path,'
9612 starting at the root directory and copying as many chars
9613 as possible before the end of the buffer. The buffer
9614 size is indicated by the 'numchars' argument. The first
9615 thing this function will do is load the name of the current
9616 working directory, if it isn't already present. This could
9617 occur if the user switched to the dotdot entry of a
9618 subdirectory immediately before calling this function. The
9619 function will then copy the current working directory name
9620 into the buffer backwards, and insert a backslash character.
9621 Next, the function will continuously switch to the previous
9622 directories and copy their names backwards into the buffer
9623 until it reaches the root. If the buffer overflows, it
9624 will be treated as a circular buffer, and data will be
9625 copied over existing characters, starting at the beginning.
9626 Once the root directory is reached, the text in the buffer
9627 will be swapped, so that the buffer contains as much of the
9628 current working directory name as possible, starting at the
9629 root.
9630 Remarks:
9631 None
9632 **************************************************************/
9633 char * wFSgetcwd (unsigned short int * path, int numchars)
9634 {
9635 char *result;
9636 twoByteMode = TRUE;
9637 result = FSgetcwd ((char *)path,numchars);
9638 twoByteMode = FALSE;
9639 return result;
9640 }
9641 #endif
9642
9643 /**************************************************************************
9644 Function:
9645 void GetPreviousEntry (FSFILE * fo)
9646 Summary:
9647 Get the file entry info for the parent dir of the specified dir
9648 Conditions:
9649 Should not be called by the user.
9650 Input:
9651 fo - The file to get the previous entry of
9652 Return Values:
9653 0 - The previous entry was successfully retrieved
9654 -1 - The previous entry could not be retrieved
9655 Side Effects:
9656 None
9657 Description:
9658 The GetPreviousEntry function is used by the FSgetcwd function to
9659 load the previous (parent) directory. This function will load the
9660 parent directory and then search through the file entries in that
9661 directory for one that matches the cluster number of the original
9662 directory. When the matching entry is found, the name of the
9663 original directory is copied into the 'fo' FSFILE object.
9664 Remarks:
9665 None.
9666 **************************************************************************/
9667
9668 BYTE GetPreviousEntry (FSFILE * fo)
9669 {
9670 int i,j;
9671 WORD fHandle = 1;
9672 DWORD dirclus;
9673 DIRENTRY dirptr;
9674
9675 #ifdef SUPPORT_LFN
9676 unsigned short int *tempLFN = (unsigned short int *)&tempDirectoryString[0];
9677 FSFILE cwdTemp;
9678 LFN_ENTRY *lfno;
9679 WORD prevHandle;
9680 UINT16_VAL tempShift;
9681 #endif
9682
9683 // Load the previous entry
9684 dirptr = Cache_File_Entry (fo, &fHandle, TRUE);
9685 if (dirptr == NULL)
9686 return -1;
9687
9688 // Get the cluster
9689 TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number.
9690
9691 if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT)
9692 {
9693 // The previous directory is the root
9694 fo->name[0] = '\\';
9695 for (i = 0; i < 11; i++)
9696 {
9697 fo->name[i] = 0x20;
9698 }
9699 fo->dirclus = FatRootDirClusterValue;
9700 fo->dirccls = FatRootDirClusterValue;
9701 }
9702 else
9703 {
9704 // Get the directory name
9705 // Save the previous cluster value
9706 // Get the cluster
9707
9708 dirclus = TempClusterCalc;
9709 fo->dirclus = TempClusterCalc;
9710 fo->dirccls = TempClusterCalc;
9711
9712
9713 // Load the previous previous cluster
9714 dirptr = Cache_File_Entry (fo, &fHandle, TRUE);
9715 if (dirptr == NULL)
9716 return -1;
9717
9718 // Get the cluster
9719 TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number.
9720 #ifdef SUPPORT_FAT32
9721 // If we're using FAT32 and the previous previous cluster is the root, the
9722 // value in the dotdot entry will be 0, but the actual cluster won't
9723 if (TempClusterCalc == VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT)
9724 {
9725 fo->dirclus = FatRootDirClusterValue;
9726 }
9727 else
9728 #endif
9729 fo->dirclus = TempClusterCalc;
9730
9731 fo->dirccls = fo->dirclus;
9732
9733 fHandle = 0;
9734 dirptr = Cache_File_Entry (fo, &fHandle, TRUE);
9735 if (dirptr == NULL)
9736 return -1;
9737 // Look through it until we get the name
9738 // of the previous cluster
9739 // Get the cluster
9740 TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number.
9741 while ((TempClusterCalc != dirclus) ||
9742 ((TempClusterCalc == dirclus) &&
9743 (((unsigned char)dirptr->DIR_Name[0] == 0xE5) || (dirptr->DIR_Attr == ATTR_VOLUME) || (dirptr->DIR_Attr == ATTR_LONG_NAME))))
9744 {
9745 // Look through the entries until we get the
9746 // right one
9747 dirptr = Cache_File_Entry (fo, &fHandle, FALSE);
9748 if (dirptr == NULL)
9749 return -1;
9750 fHandle++;
9751
9752 TempClusterCalc = GetFullClusterNumber(dirptr); // Get complete cluster number in a loop.
9753 }
9754
9755 // The name should be in the entry now
9756 // Copy the actual directory location back
9757 fo->dirclus = dirclus;
9758 fo->dirccls = dirclus;
9759 }
9760
9761 i = 0;
9762 #ifdef SUPPORT_LFN
9763 FileObjectCopy (&cwdTemp, fo);
9764 prevHandle = fHandle - 2;
9765 lfno = (LFN_ENTRY *)Cache_File_Entry (fo, &prevHandle, FALSE);
9766
9767 // Get the long file name of the short file name(if present)
9768 while((lfno->LFN_Attribute == ATTR_LONG_NAME) && (lfno->LFN_SequenceNo != DIR_DEL)
9769 && (lfno->LFN_SequenceNo != DIR_EMPTY))
9770 {
9771 tempShift.byte.LB = lfno->LFN_Part1[0];
9772 tempShift.byte.HB = lfno->LFN_Part1[1];
9773 tempLFN[i++] = tempShift.Val;
9774 tempShift.byte.LB = lfno->LFN_Part1[2];
9775 tempShift.byte.HB = lfno->LFN_Part1[3];
9776 tempLFN[i++] = tempShift.Val;
9777 tempShift.byte.LB = lfno->LFN_Part1[4];
9778 tempShift.byte.HB = lfno->LFN_Part1[5];
9779 tempLFN[i++] = tempShift.Val;
9780 tempShift.byte.LB = lfno->LFN_Part1[6];
9781 tempShift.byte.HB = lfno->LFN_Part1[7];
9782 tempLFN[i++] = tempShift.Val;
9783 tempShift.byte.LB = lfno->LFN_Part1[8];
9784 tempShift.byte.HB = lfno->LFN_Part1[9];
9785 tempLFN[i++] = tempShift.Val;
9786
9787 tempLFN[i++] = lfno->LFN_Part2[0];
9788 tempLFN[i++] = lfno->LFN_Part2[1];
9789 tempLFN[i++] = lfno->LFN_Part2[2];
9790 tempLFN[i++] = lfno->LFN_Part2[3];
9791 tempLFN[i++] = lfno->LFN_Part2[4];
9792 tempLFN[i++] = lfno->LFN_Part2[5];
9793
9794 tempLFN[i++] = lfno->LFN_Part3[0];
9795 tempLFN[i++] = lfno->LFN_Part3[1];
9796
9797 prevHandle = prevHandle - 1;
9798 lfno = (LFN_ENTRY *)Cache_File_Entry (fo, &prevHandle, FALSE);
9799 }
9800
9801 FileObjectCopy (fo, &cwdTemp);
9802 #endif
9803
9804 if(i == 0)
9805 {
9806 for (j = 0; j < 11; j++)
9807 fo->name[j] = dirptr->DIR_Name[j];
9808 #ifdef SUPPORT_LFN
9809 fo->utf16LFNlength = 0;
9810 #endif
9811 }
9812 #ifdef SUPPORT_LFN
9813 else
9814 {
9815 fo->utf16LFNlength = i;
9816
9817 for(j = 12;j >= 0;j--)
9818 {
9819 if((tempLFN[i - j - 1]) == 0x0000)
9820 {
9821 fo->utf16LFNlength = i - j;
9822 break;
9823 }
9824 }
9825
9826 fo->utf16LFNptr = (unsigned short int *)&tempDirectoryString[0];
9827 }
9828 #endif
9829
9830 return 0;
9831 }
9832
9833
9834 /**************************************************************************
9835 Function:
9836 int FSmkdir (char * path)
9837 Summary:
9838 Create a directory as per the Ascii input path
9839 Conditions:
9840 None
9841 Input:
9842 path - The path of directories to create.
9843 Return Values:
9844 0 - The specified directory was created successfully
9845 EOF - The specified directory could not be created
9846 Side Effects:
9847 Will create all non-existent directories in the path. The FSerrno
9848 variable will be changed.
9849 Description:
9850 The FSmkdir function passes a RAM pointer to the path to the
9851 mkdirhelper function.
9852 Remarks:
9853 None
9854 **************************************************************************/
9855
9856 #ifdef ALLOW_WRITES
9857 int FSmkdir (char * path)
9858 {
9859 return mkdirhelper (0, path, NULL);
9860 }
9861
9862 /**************************************************************************
9863 Function:
9864 int wFSmkdir (unsigned short int * path)
9865 Summary:
9866 Create a directory as per the UTF16 input path
9867 Conditions:
9868 None
9869 Input:
9870 path - The path of directories to create.
9871 Return Values:
9872 0 - The specified directory was created successfully
9873 EOF - The specified directory could not be created
9874 Side Effects:
9875 Will create all non-existent directories in the path. The FSerrno
9876 variable will be changed.
9877 Description:
9878 The wFSmkdir function passes a RAM pointer to the path to the
9879 mkdirhelper function.
9880 Remarks:
9881 None
9882 **************************************************************************/
9883 #ifdef SUPPORT_LFN
9884 int wFSmkdir (unsigned short int * path)
9885 {
9886 int result;
9887 utfModeFileName = TRUE;
9888 result = mkdirhelper (0, (char *)path, NULL);
9889 utfModeFileName = FALSE;
9890 return result;
9891 }
9892 #endif
9893
9894 /**************************************************************************
9895 Function:
9896 int FSmkdirpgm (const rom char * path)
9897 Summary:
9898 Create a directory with a path in ROM on PIC18
9899 Conditions:
9900 None
9901 Input:
9902 path - The path of directories to create (ROM)
9903 Return Values:
9904 0 - The specified directory was created successfully
9905 EOF - The specified directory could not be created
9906 Side Effects:
9907 Will create all non-existent directories in the path. The FSerrno
9908 variable will be changed.
9909 Description:
9910 The FSmkdirpgm function passes a PIC18 ROM path pointer to the
9911 mkdirhelper function.
9912 Remarks:
9913 This function is for use with PIC18 when passing arugments in ROM
9914 **************************************************************************/
9915
9916 #ifdef ALLOW_PGMFUNCTIONS
9917 int FSmkdirpgm (const rom char * path)
9918 {
9919 return mkdirhelper (1, NULL, path);
9920 }
9921
9922 /**************************************************************************
9923 Function:
9924 int wFSmkdirpgm (const rom unsigned short int * path)
9925 Summary:
9926 Create a directory with a path in ROM on PIC18
9927 Conditions:
9928 None
9929 Input:
9930 path - The path of directories to create (ROM)
9931 Return Values:
9932 0 - The specified directory was created successfully
9933 EOF - The specified directory could not be created
9934 Side Effects:
9935 Will create all non-existent directories in the path. The FSerrno
9936 variable will be changed.
9937 Description:
9938 The FSmkdirpgm function passes a PIC18 ROM path pointer to the
9939 mkdirhelper function.
9940 Remarks:
9941 This function is for use with PIC18 when passing arugments in ROM
9942 **************************************************************************/
9943 #ifdef SUPPORT_LFN
9944 int wFSmkdirpgm (const rom unsigned short int * path)
9945 {
9946 int result;
9947 utfModeFileName = TRUE;
9948 result = mkdirhelper (1, NULL, (const char *)path);
9949 utfModeFileName = FALSE;
9950 return result;
9951 }
9952 #endif
9953
9954 #endif
9955
9956 /*************************************************************************
9957 Function:
9958 // PIC24/30/33/32
9959 int mkdirhelper (BYTE mode, char * ramptr, char * romptr)
9960 // PIC18
9961 int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr)
9962 Summary:
9963 Helper function for FSmkdir
9964 Conditions:
9965 None
9966 Input:
9967 mode - Indicates which path pointer to use
9968 ramptr - Pointer to the path specified in RAM
9969 romptr - Pointer to the path specified in ROM
9970 Return Values:
9971 0 - Directory was created
9972 -1 - Directory could not be created
9973 Side Effects:
9974 Will create all non-existant directories in the path.
9975 The FSerrno variable will be changed.
9976 Description:
9977 This helper function is used by the FSchdir function. If the path
9978 argument is specified in ROM for PIC18 this function will be able
9979 to parse it correctly. This function will first scan through the path
9980 to ensure that any DIR names don't exceed 11 characters. It will then
9981 backup the current working directory and begin changing directories
9982 through the path until it reaches a directory than can't be changed to.
9983 It will then create the specified directory and change directories to
9984 the new directory. The function will continue creating and changing to
9985 directories until the end of the path is reached. The function will
9986 then restore the original current working directory.
9987 Remarks:
9988 None
9989 **************************************************************************/
9990
9991 #ifdef ALLOW_PGMFUNCTIONS
9992 int mkdirhelper (BYTE mode, char * ramptr, const rom char * romptr)
9993 #else
9994 int mkdirhelper (BYTE mode, char * ramptr, char * romptr)
9995 #endif
9996 {
9997 unsigned short int i,j = 0,k = 0;
9998 char * temppath = ramptr;
9999 #ifdef ALLOW_PGMFUNCTIONS
10000 rom char * temppath2 = romptr;
10001 rom unsigned short int * utf16path2 = (rom unsigned short int *)romptr;
10002 #endif
10003 unsigned short int *utf16path = (unsigned short int *)ramptr;
10004 FILEOBJ tempCWD = &tempCWDobj;
10005
10006 #ifdef __18CXX
10007 char dotdotPath[] = "..";
10008 char dotdotPath1[5] = {'.','\0','.','\0','\0'};
10009 #endif
10010
10011 // Do Dynamic allocation if the macro is defined or
10012 // go with static allocation
10013 #if defined(SUPPORT_LFN)
10014 char tempArray[514];
10015 #else
10016 char tempArray[14];
10017 #endif
10018
10019 FSerrno = CE_GOOD;
10020
10021 if (MDD_WriteProtectState())
10022 {
10023 FSerrno = CE_WRITE_PROTECTED;
10024 return (-1);
10025 }
10026
10027 #ifdef ALLOW_PGMFUNCTIONS
10028 if (mode == 1)
10029 {
10030 #ifdef SUPPORT_LFN
10031 if(utfModeFileName)
10032 {
10033 // Scan for too-long file names
10034 while (1)
10035 {
10036 i = 0;
10037 while((*utf16path2 != 0) && (*utf16path2 != '.')&& (*utf16path2 != '\\'))
10038 {
10039 utf16path2++;
10040 i++;
10041 }
10042
10043 if (i > 256)
10044 {
10045 FSerrno = CE_INVALID_ARGUMENT;
10046 return -1;
10047 }
10048
10049 j = 0;
10050 if (*utf16path2 == '.')
10051 {
10052 utf16path2++;
10053 while ((*utf16path2 != 0) && (*utf16path2 != '\\'))
10054 {
10055 utf16path2++;
10056 j++;
10057 }
10058 if ((i + j) > 256)
10059 {
10060 FSerrno = CE_INVALID_ARGUMENT;
10061 return -1;
10062 }
10063 }
10064
10065 if((i + j) > k)
10066 {
10067 k = (i + j);
10068 }
10069
10070 while (*utf16path2 == '\\')
10071 utf16path2++;
10072 if (*utf16path2 == 0)
10073 break;
10074 }
10075 }
10076 else
10077 #endif
10078 {
10079 // Scan for too-long file names
10080 while (1)
10081 {
10082 i = 0;
10083 while((*temppath2 != 0) && (*temppath2 != '.')&& (*temppath2 != '\\'))
10084 {
10085 temppath2++;
10086 i++;
10087 }
10088
10089 #if defined(SUPPORT_LFN)
10090 if (i > 256)
10091 {
10092 FSerrno = CE_INVALID_ARGUMENT;
10093 return -1;
10094 }
10095 #else
10096 if (i > 8)
10097 {
10098 FSerrno = CE_INVALID_ARGUMENT;
10099 return -1;
10100 }
10101 #endif
10102
10103 j = 0;
10104 if (*temppath2 == '.')
10105 {
10106 temppath2++;
10107 while ((*temppath2 != 0) && (*temppath2 != '\\'))
10108 {
10109 temppath2++;
10110 j++;
10111 }
10112 #if defined(SUPPORT_LFN)
10113 if ((i + j) > 256)
10114 {
10115 FSerrno = CE_INVALID_ARGUMENT;
10116 return -1;
10117 }
10118 #else
10119 if (j > 3)
10120 {
10121 FSerrno = CE_INVALID_ARGUMENT;
10122 return -1;
10123 }
10124 #endif
10125 }
10126
10127 if((i + j) > k)
10128 {
10129 k = (i + j);
10130 }
10131
10132 while (*temppath2 == '\\')
10133 temppath2++;
10134 if (*temppath2 == 0)
10135 break;
10136 }
10137 }
10138 }
10139 else
10140 #endif
10141 {
10142 #ifdef SUPPORT_LFN
10143 if(utfModeFileName)
10144 {
10145 utf16path = (unsigned short int *)ramptr;
10146 // Scan for too-long file names
10147 while (1)
10148 {
10149 i = 0;
10150 while((*utf16path != 0) && (*utf16path != '.')&& (*utf16path != '\\'))
10151 {
10152 utf16path++;
10153 i++;
10154 }
10155 if (i > 256)
10156 {
10157 FSerrno = CE_INVALID_ARGUMENT;
10158 return -1;
10159 }
10160
10161 j = 0;
10162 if (*utf16path == '.')
10163 {
10164 utf16path++;
10165 while ((*utf16path != 0) && (*utf16path != '\\'))
10166 {
10167 utf16path++;
10168 j++;
10169 }
10170 if ((i + j) > 256)
10171 {
10172 FSerrno = CE_INVALID_ARGUMENT;
10173 return -1;
10174 }
10175 }
10176
10177 if((i + j) > k)
10178 {
10179 k = (i + j);
10180 }
10181
10182 while (*utf16path == '\\')
10183 utf16path++;
10184 if (*utf16path == 0)
10185 break;
10186 }
10187 }
10188 else
10189 #endif
10190 {
10191 // Scan for too-long file names
10192 while (1)
10193 {
10194 i = 0;
10195 while((*temppath != 0) && (*temppath != '.')&& (*temppath != '\\'))
10196 {
10197 temppath++;
10198 i++;
10199 }
10200 #if defined(SUPPORT_LFN)
10201 if (i > 256)
10202 {
10203 FSerrno = CE_INVALID_ARGUMENT;
10204 return -1;
10205 }
10206 #else
10207 if (i > 8)
10208 {
10209 FSerrno = CE_INVALID_ARGUMENT;
10210 return -1;
10211 }
10212 #endif
10213
10214 j = 0;
10215 if (*temppath == '.')
10216 {
10217 temppath++;
10218 while ((*temppath != 0) && (*temppath != '\\'))
10219 {
10220 temppath++;
10221 j++;
10222 }
10223 #if defined(SUPPORT_LFN)
10224 if ((i + j) > 256)
10225 {
10226 FSerrno = CE_INVALID_ARGUMENT;
10227 return -1;
10228 }
10229 #else
10230 if (j > 3)
10231 {
10232 FSerrno = CE_INVALID_ARGUMENT;
10233 return -1;
10234 }
10235 #endif
10236 }
10237
10238 if((i + j) > k)
10239 {
10240 k = (i + j);
10241 }
10242
10243 while (*temppath == '\\')
10244 temppath++;
10245 if (*temppath == 0)
10246 break;
10247 }
10248 }
10249 }
10250
10251 utf16path = (unsigned short int *)ramptr;
10252 temppath = ramptr;
10253 #ifdef ALLOW_PGMFUNCTIONS
10254 utf16path2 = (rom unsigned short int *)romptr;
10255 temppath2 = romptr;
10256 #endif
10257
10258 // We're going to be moving the CWD
10259 // Back up the CWD
10260 FileObjectCopy (tempCWD, cwdptr);
10261
10262 // get to the target directory
10263 while (1)
10264 {
10265 #ifdef ALLOW_PGMFUNCTIONS
10266 if (mode == 1)
10267 {
10268 #ifdef SUPPORT_LFN
10269 if(utfModeFileName)
10270 i = *utf16path2;
10271 else
10272 #endif
10273 i = *temppath2;
10274 }
10275 else
10276 #endif
10277 {
10278 #ifdef SUPPORT_LFN
10279 if(utfModeFileName)
10280 i = *utf16path;
10281 else
10282 #endif
10283 i = *temppath;
10284 }
10285
10286 if (i == '.')
10287 {
10288 #ifdef ALLOW_PGMFUNCTIONS
10289 if (mode == 1)
10290 {
10291 #ifdef SUPPORT_LFN
10292 if(utfModeFileName)
10293 {
10294 utf16path2++;
10295 i = *utf16path2;
10296 }
10297 else
10298 #endif
10299 {
10300 temppath2++;
10301 i = *temppath2;
10302 }
10303 }
10304 else
10305 {
10306 #endif
10307 #ifdef SUPPORT_LFN
10308 if(utfModeFileName)
10309 {
10310 utf16path++;
10311 i = *utf16path;
10312 }
10313 else
10314 #endif
10315 {
10316 temppath++;
10317 i = *temppath;
10318 }
10319 #ifdef ALLOW_PGMFUNCTIONS
10320 }
10321 #endif
10322
10323 if ((i != '.') && (i != 0) && (i != '\\'))
10324 {
10325 FSerrno = CE_INVALID_ARGUMENT;
10326 return -1;
10327 }
10328
10329 if (i == '.')
10330 {
10331 if (cwdptr->dirclus == FatRootDirClusterValue)
10332 {
10333 // If we try to change to the .. from the
10334 // root, operation fails
10335 FSerrno = CE_INVALID_ARGUMENT;
10336 return -1;
10337 }
10338 #ifdef ALLOW_PGMFUNCTIONS
10339 if (mode == 1)
10340 {
10341 #ifdef SUPPORT_LFN
10342 if(utfModeFileName)
10343 {
10344 utf16path2++;
10345 i = *utf16path2;
10346 }
10347 else
10348 #endif
10349 {
10350 temppath2++;
10351 i = *temppath2;
10352 }
10353 }
10354 else
10355 #endif
10356 {
10357 #ifdef SUPPORT_LFN
10358 if(utfModeFileName)
10359 {
10360 utf16path++;
10361 i = *utf16path;
10362 }
10363 else
10364 #endif
10365 {
10366 temppath++;
10367 i = *temppath;
10368 }
10369 }
10370
10371 if ((i != '\\') && (i != 0))
10372 {
10373 FSerrno = CE_INVALID_ARGUMENT;
10374 return -1;
10375 }
10376 // dotdot entry
10377 #ifndef __18CXX
10378 #ifdef SUPPORT_LFN
10379 if(utfModeFileName)
10380 FSchdir (".\0.\0\0");
10381 #endif
10382 else
10383 FSchdir ("..");
10384 #else
10385 #ifdef SUPPORT_LFN
10386 if(utfModeFileName)
10387 FSchdir (dotdotPath1);
10388 else
10389 #endif
10390 FSchdir (dotdotPath);
10391 #endif
10392 }
10393 // Skip past any backslashes
10394 while (i == '\\')
10395 {
10396 #ifdef ALLOW_PGMFUNCTIONS
10397 if (mode == 1)
10398 {
10399 #ifdef SUPPORT_LFN
10400 if(utfModeFileName)
10401 {
10402 utf16path2++;
10403 i = *utf16path2;
10404 }
10405 else
10406 #endif
10407 {
10408 temppath2++;
10409 i = *temppath2;
10410 }
10411 }
10412 else
10413 {
10414 #endif
10415 #ifdef SUPPORT_LFN
10416 if(utfModeFileName)
10417 {
10418 utf16path++;
10419 i = *utf16path;
10420 }
10421 else
10422 #endif
10423 {
10424 temppath++;
10425 i = *temppath;
10426 }
10427 #ifdef ALLOW_PGMFUNCTIONS
10428 }
10429 #endif
10430 }
10431 if (i == 0)
10432 {
10433 // No point in creating a dot or dotdot entry directly
10434 FileObjectCopy (cwdptr, tempCWD);
10435 FSerrno = CE_INVALID_ARGUMENT;
10436 return -1;
10437 }
10438 }
10439 else
10440 {
10441 if (i == '\\')
10442 {
10443 // Start at the root
10444 cwdptr->dirclus = FatRootDirClusterValue;
10445 cwdptr->dirccls = FatRootDirClusterValue;
10446 i = 0;
10447 cwdptr->name[i++] = '\\';
10448 // if(utfModeFileName)
10449 // {
10450 // cwdptr->name[i++] = 0x00;
10451 // }
10452 for (; i < 11; i++)
10453 {
10454 cwdptr->name[i] = 0x20;
10455 }
10456
10457 #ifdef ALLOW_PGMFUNCTIONS
10458 if (mode == 1)
10459 {
10460 #ifdef SUPPORT_LFN
10461 if(utfModeFileName)
10462 {
10463 utf16path2++;
10464 i = *utf16path2;
10465 }
10466 else
10467 #endif
10468 {
10469 temppath2++;
10470 i = *temppath2;
10471 }
10472 }
10473 else
10474 {
10475 #endif
10476 #ifdef SUPPORT_LFN
10477 if(utfModeFileName)
10478 {
10479 utf16path++;
10480 i = *utf16path;
10481 }
10482 else
10483 #endif
10484 {
10485 temppath++;
10486 i = *temppath;
10487 }
10488 #ifdef ALLOW_PGMFUNCTIONS
10489 }
10490 #endif
10491 // If we just got two backslashes in a row at the
10492 // beginning of the path, the function fails
10493 if ((i == '\\') || (i == 0))
10494 {
10495 FileObjectCopy (cwdptr, tempCWD);
10496 FSerrno = CE_INVALID_ARGUMENT;
10497 return -1;
10498 }
10499 }
10500 else
10501 {
10502 break;
10503 }
10504 }
10505 }
10506
10507 while (1)
10508 {
10509 while(1)
10510 {
10511 #ifdef ALLOW_PGMFUNCTIONS
10512 if (mode == 1)
10513 {
10514 #ifdef SUPPORT_LFN
10515 if(utfModeFileName)
10516 {
10517 // Change directories as specified
10518 i = *utf16path2;
10519 j = 0;
10520
10521 k = 512;
10522
10523 // Parse the next token
10524 while ((i != 0) && (i != '\\') && (j < k))
10525 {
10526 tempArray[j++] = i;
10527 tempArray[j++] = i >> 8;
10528 utf16path2++;
10529 i = *utf16path2;
10530 }
10531 }
10532 else
10533 #endif
10534 {
10535 // Change directories as specified
10536 i = *temppath2;
10537 j = 0;
10538
10539 #if defined(SUPPORT_LFN)
10540 k = 256;
10541 #else
10542 k = 12;
10543 #endif
10544
10545 // Parse the next token
10546 while ((i != 0) && (i != '\\') && (j < k))
10547 {
10548 tempArray[j++] = i;
10549 temppath2++;
10550 i = *temppath2;
10551 }
10552 }
10553 }
10554 else
10555 {
10556 #endif
10557 #ifdef SUPPORT_LFN
10558 if(utfModeFileName)
10559 {
10560 // Change directories as specified
10561 i = *utf16path;
10562 j = 0;
10563
10564 k = 512;
10565
10566 // Parse the next token
10567 while ((i != 0) && (i != '\\') && (j < k))
10568 {
10569 tempArray[j++] = i;
10570 tempArray[j++] = i >> 8;
10571 utf16path++;
10572 i = *utf16path;
10573 }
10574 }
10575 else
10576 #endif
10577 {
10578 // Change directories as specified
10579 i = *temppath;
10580 j = 0;
10581
10582 #if defined(SUPPORT_LFN)
10583 k = 256;
10584 #else
10585 k = 12;
10586 #endif
10587
10588 // Parse the next token
10589 while ((i != 0) && (i != '\\') && (j < k))
10590 {
10591 tempArray[j++] = i;
10592 temppath++;
10593 i = *temppath;
10594 }
10595 }
10596 #ifdef ALLOW_PGMFUNCTIONS
10597 }
10598 #endif
10599 #ifdef SUPPORT_LFN
10600 if(utfModeFileName)
10601 {
10602 tempArray[j++] = 0;
10603 tempArray[j] = 0;
10604
10605 if ((tempArray[0] == '.') && (tempArray[1] == 0))
10606 {
10607 if (((tempArray[2] != 0) || (tempArray[3] != 0)) && ((tempArray[2] != '.') || (tempArray[3] != 0)))
10608 {
10609 FileObjectCopy (cwdptr, tempCWD);
10610 FSerrno = CE_INVALID_ARGUMENT;
10611 return -1;
10612 }
10613 if (((tempArray[2] == '.') && (tempArray[3] == 0)) && ((tempArray[4] != 0) || (tempArray[5] != 0)))
10614 {
10615 FileObjectCopy (cwdptr, tempCWD);
10616 FSerrno = CE_INVALID_ARGUMENT;
10617 return -1;
10618 }
10619 }
10620 }
10621 else
10622 #endif
10623 {
10624 tempArray[j] = 0;
10625
10626 if (tempArray[0] == '.')
10627 {
10628 if ((tempArray[1] != 0) && (tempArray[1] != '.'))
10629 {
10630 FileObjectCopy (cwdptr, tempCWD);
10631 FSerrno = CE_INVALID_ARGUMENT;
10632 return -1;
10633 }
10634 if ((tempArray[1] == '.') && (tempArray[2] != 0))
10635 {
10636 FileObjectCopy (cwdptr, tempCWD);
10637 FSerrno = CE_INVALID_ARGUMENT;
10638 return -1;
10639 }
10640 }
10641 }
10642
10643 // Try to change to it
10644 // If you can't we need to create it
10645 if (FSchdir (tempArray))
10646 break;
10647 else
10648 {
10649 // We changed into the directory
10650 while (i == '\\')
10651 {
10652 // Next char is a backslash
10653 // Move past it
10654 #ifdef ALLOW_PGMFUNCTIONS
10655 if (mode == 1)
10656 {
10657 #ifdef SUPPORT_LFN
10658 if(utfModeFileName)
10659 {
10660 utf16path2++;
10661 i = *utf16path2;
10662 }
10663 else
10664 #endif
10665 {
10666 temppath2++;
10667 i = *temppath2;
10668 }
10669 }
10670 else
10671 {
10672 #endif
10673 #ifdef SUPPORT_LFN
10674 if(utfModeFileName)
10675 {
10676 utf16path++;
10677 i = *utf16path;
10678 }
10679 else
10680 #endif
10681 {
10682 temppath++;
10683 i = *temppath;
10684 }
10685 #ifdef ALLOW_PGMFUNCTIONS
10686 }
10687 #endif
10688 }
10689 // If it's the last one, return success
10690 if (i == 0)
10691 {
10692 FileObjectCopy (cwdptr, tempCWD);
10693 return 0;
10694 }
10695 }
10696 }
10697
10698 #ifdef SUPPORT_LFN
10699 if(utfModeFileName)
10700 {
10701 unsigned short int *tempPtr1;
10702 unsigned short int *tempPtr2;
10703 k = 0;
10704 tempPtr1 = (unsigned short int *)&tempArray[0];
10705 tempPtr2 = (unsigned short int *)&tempDirectoryString[0];
10706
10707 for(;;)
10708 {
10709 tempPtr2[k] = tempPtr1[k];
10710 if(tempPtr2[k])
10711 k++;
10712 else
10713 break;
10714 }
10715 }
10716 else
10717 #endif
10718 {
10719 strcpy(&tempDirectoryString[0],&tempArray[0]);
10720 }
10721
10722 // Create a dir here
10723 if (!CreateDIR (tempDirectoryString))
10724 {
10725 FileObjectCopy (cwdptr, tempCWD);
10726 return -1;
10727 }
10728
10729 // Try to change to that directory
10730 if (FSchdir (tempArray))
10731 {
10732 FileObjectCopy (cwdptr, tempCWD);
10733 FSerrno = CE_BADCACHEREAD;
10734 return -1;
10735 }
10736
10737 #ifdef ALLOW_PGMFUNCTIONS
10738 if (mode == 1)
10739 {
10740 #ifdef SUPPORT_LFN
10741 if(utfModeFileName)
10742 {
10743 while (*utf16path2 == '\\')
10744 {
10745 utf16path2++;
10746 i = *utf16path2;
10747 }
10748 }
10749 else
10750 #endif
10751 {
10752 // Check for another backslash
10753 while (*temppath2 == '\\')
10754 {
10755 temppath2++;
10756 i = *temppath2;
10757 }
10758 }
10759 }
10760 else
10761 {
10762 #endif
10763 #ifdef SUPPORT_LFN
10764 if(utfModeFileName)
10765 {
10766 while (*utf16path == '\\')
10767 {
10768 utf16path++;
10769 i = *utf16path;
10770 }
10771 }
10772 else
10773 #endif
10774 {
10775 while (*temppath == '\\')
10776 {
10777 temppath++;
10778 i = *temppath;
10779 }
10780 }
10781 #ifdef ALLOW_PGMFUNCTIONS
10782 }
10783 #endif
10784
10785 // Check to see if we're at the end of the path string
10786 if (i == 0)
10787 {
10788 // We already have one
10789 FileObjectCopy (cwdptr, tempCWD);
10790 return 0;
10791 }
10792 }
10793 }
10794
10795
10796 /**************************************************************************
10797 Function:
10798 int CreateDIR (char * path)
10799 Summary:
10800 FSmkdir helper function to create a directory
10801 Conditions:
10802 This function should not be called by the user.
10803 Input:
10804 path - The name of the dir to create
10805 Return Values:
10806 TRUE - Directory was created successfully
10807 FALSE - Directory could not be created.
10808 Side Effects:
10809 Any unwritten data in the data buffer or the FAT buffer will be written
10810 to the device.
10811 Description:
10812 The CreateDIR function is a helper function for the mkdirhelper
10813 function. The CreateDIR function will create a new file entry for
10814 a directory and assign a cluster to it. It will erase the cluster
10815 and write a dot and dotdot entry to it.
10816 Remarks:
10817 None.
10818 **************************************************************************/
10819
10820 int CreateDIR (char * path)
10821 {
10822 FSFILE * dirEntryPtr = &gFileTemp;
10823 DIRENTRY dir;
10824 WORD handle = 0;
10825 DWORD dot, dotdot;
10826
10827 if (FormatDirName(path, dirEntryPtr,0) == FALSE)
10828 {
10829 FSerrno = CE_INVALID_FILENAME;
10830 return FALSE;
10831 }
10832
10833 dirEntryPtr->dirclus = cwdptr->dirclus;
10834 dirEntryPtr->dirccls = cwdptr->dirccls;
10835 dirEntryPtr->cluster = 0;
10836 dirEntryPtr->ccls = 0;
10837 dirEntryPtr->dsk = cwdptr->dsk;
10838
10839 // Create a directory entry
10840 if(CreateFileEntry(dirEntryPtr, &handle, DIRECTORY, TRUE) != CE_GOOD)
10841 {
10842 return FALSE;
10843 }
10844 else
10845 {
10846 if (gNeedFATWrite)
10847 if(WriteFAT (dirEntryPtr->dsk, 0, 0, TRUE))
10848 {
10849 FSerrno = CE_WRITE_ERROR;
10850 return FALSE;
10851 }
10852 // Zero that cluster
10853 if (dirEntryPtr->dirclus == FatRootDirClusterValue)
10854 dotdot = 0;
10855 else
10856 dotdot = dirEntryPtr->dirclus;
10857 dirEntryPtr->dirccls = dirEntryPtr->dirclus;
10858 dir = Cache_File_Entry(dirEntryPtr, &handle, TRUE);
10859 if (dir == NULL)
10860 {
10861 FSerrno = CE_BADCACHEREAD;
10862 return FALSE;
10863 }
10864
10865 // Get the cluster
10866 dot = GetFullClusterNumber(dir); // Get complete cluster number.
10867
10868 if (writeDotEntries (dirEntryPtr->dsk, dot, dotdot))
10869 return TRUE;
10870 else
10871 return FALSE;
10872
10873 }
10874 }
10875
10876
10877 /***********************************************************************************
10878 Function:
10879 BYTE writeDotEntries (DISK * disk, DWORD dotAddress, DWORD dotdotAddress)
10880 Summary:
10881 Create dot and dotdot entries in a non-root directory
10882 Conditions:
10883 This function should not be called by the user.
10884 Input:
10885 disk - The global disk structure
10886 dotAddress - The cluster the current dir is in
10887 dotdotAddress - The cluster the previous directory was in
10888 Return Values:
10889 TRUE - The dot and dotdot entries were created
10890 FALSE - The dot and dotdot entries could not be created in the new directory
10891 Side Effects:
10892 None
10893 Description:
10894 The writeDotEntries function will create and write dot and dotdot entries
10895 to a newly created directory.
10896 Remarks:
10897 None.
10898 ***********************************************************************************/
10899
10900 BYTE writeDotEntries (DISK * disk, DWORD dotAddress, DWORD dotdotAddress)
10901 {
10902 WORD i;
10903 WORD size;
10904 _DIRENTRY entry;
10905 DIRENTRY entryptr = &entry;
10906 DWORD sector;
10907
10908 gBufferOwner = NULL;
10909
10910 size = sizeof (_DIRENTRY);
10911
10912 memset(disk->buffer, 0x00, disk->sectorSize);
10913
10914 entry.DIR_Name[0] = '.';
10915
10916 for (i = 1; i < 11; i++)
10917 {
10918 entry.DIR_Name[i] = 0x20;
10919 }
10920 entry.DIR_Attr = ATTR_DIRECTORY;
10921 entry.DIR_NTRes = 0x00;
10922
10923 entry.DIR_FstClusLO = (WORD)(dotAddress & 0x0000FFFF); // Lower 16 bit address
10924
10925 #ifdef SUPPORT_FAT32 // If FAT32 supported.
10926 entry.DIR_FstClusHI = (WORD)((dotAddress & 0x0FFF0000)>> 16); // Higher 16 bit address. FAT32 uses only 28 bits. Mask even higher nibble also.
10927 #else // If FAT32 support not enabled
10928 entry.DIR_FstClusHI = 0;
10929 #endif
10930
10931 entry.DIR_FileSize = 0x00;
10932
10933 // Times need to be the same as the times in the directory entry
10934
10935 // Set dir date for uncontrolled clock source
10936 #ifdef INCREMENTTIMESTAMP
10937 entry.DIR_CrtTimeTenth = 0xB2;
10938 entry.DIR_CrtTime = 0x7278;
10939 entry.DIR_CrtDate = 0x32B0;
10940 entry.DIR_LstAccDate = 0x0000;
10941 entry.DIR_WrtTime = 0x0000;
10942 entry.DIR_WrtDate = 0x0000;
10943 #endif
10944
10945 #ifdef USEREALTIMECLOCK
10946 entry.DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp
10947 entry.DIR_CrtTime = gTimeCrtTime; // time created //
10948 entry.DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004)
10949 entry.DIR_LstAccDate = 0x0000; // Last Access date
10950 entry.DIR_WrtTime = 0x0000; // last update time
10951 entry.DIR_WrtDate = 0x0000; // last update date
10952 #endif
10953
10954 #ifdef USERDEFINEDCLOCK
10955 entry.DIR_CrtTimeTenth = gTimeCrtMS; // millisecond stamp
10956 entry.DIR_CrtTime = gTimeCrtTime; // time created //
10957 entry.DIR_CrtDate = gTimeCrtDate; // date created (1/1/2004)
10958 entry.DIR_LstAccDate = 0x0000; // Last Access date
10959 entry.DIR_WrtTime = 0x0000; // last update time
10960 entry.DIR_WrtDate = 0x0000; // last update date
10961 #endif
10962
10963 for (i = 0; i < size; i++)
10964 {
10965 *(disk->buffer + i) = *((char *)entryptr + i);
10966 }
10967 entry.DIR_Name[1] = '.';
10968
10969 entry.DIR_FstClusLO = (WORD)(dotdotAddress & 0x0000FFFF); // Lower 16 bit address
10970
10971 #ifdef SUPPORT_FAT32 // If FAT32 supported.
10972 entry.DIR_FstClusHI = (WORD)((dotdotAddress & 0x0FFF0000)>> 16); // Higher 16 bit address. FAT32 uses only 28 bits. Mask even higher nibble also.
10973 #else // If FAT32 support not enabled
10974 entry.DIR_FstClusHI = 0;
10975 #endif
10976
10977
10978 for (i = 0; i < size; i++)
10979 {
10980 *(disk->buffer + i + size) = *((char *)entryptr + i);
10981 }
10982
10983 sector = Cluster2Sector (disk, dotAddress);
10984
10985 if (MDD_SectorWrite(sector, disk->buffer, FALSE) == FALSE)
10986 {
10987 FSerrno = CE_WRITE_ERROR;
10988 return FALSE;
10989 }
10990
10991 return TRUE;
10992 }
10993
10994 // This array is used to prevent a stack frame error
10995 #ifdef __18CXX
10996 char tempArray[13] = " ";
10997 #endif
10998
10999
11000 /**************************************************************************
11001 Function:
11002 int FSrmdir (char * path)
11003 Summary:
11004 Delete a directory as per the Ascii input path
11005 Conditions:
11006 None
11007 Input:
11008 path - The path of the directory to remove
11009 rmsubdirs -
11010 - TRUE - All sub-dirs and files in the target dir will be removed
11011 - FALSE - FSrmdir will not remove non-empty directories
11012 Return Values:
11013 0 - The specified directory was deleted successfully
11014 EOF - The specified directory could not be deleted
11015 Side Effects:
11016 The FSerrno variable will be changed.
11017 Description:
11018 The FSrmdir function passes a RAM pointer to the path to the
11019 rmdirhelper function.
11020 Remarks:
11021 None.
11022 **************************************************************************/
11023
11024 int FSrmdir (char * path, unsigned char rmsubdirs)
11025 {
11026 return rmdirhelper (0, path, NULL, rmsubdirs);
11027 }
11028
11029
11030 /**************************************************************************
11031 Function:
11032 int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs)
11033 Summary:
11034 Delete a directory as per the UTF16 input path
11035 Conditions:
11036 None
11037 Input:
11038 path - The path of the directory to remove
11039 rmsubdirs -
11040 - TRUE - All sub-dirs and files in the target dir will be removed
11041 - FALSE - FSrmdir will not remove non-empty directories
11042 Return Values:
11043 0 - The specified directory was deleted successfully
11044 EOF - The specified directory could not be deleted
11045 Side Effects:
11046 The FSerrno variable will be changed.
11047 Description:
11048 The wFSrmdir function passes a RAM pointer to the path to the
11049 rmdirhelper function.
11050 Remarks:
11051 None.
11052 **************************************************************************/
11053 #ifdef SUPPORT_LFN
11054 int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs)
11055 {
11056 int result;
11057 utfModeFileName = TRUE;
11058 result = rmdirhelper (0, (char *)path, NULL, rmsubdirs);
11059 utfModeFileName = FALSE;
11060 return result;
11061 }
11062 #endif
11063
11064 /**************************************************************************
11065 Function:
11066 int FSrmdirpgm (const rom char * path)
11067 Summary:
11068 Delete a directory with a path in ROM on PIC18
11069 Conditions:
11070 None.
11071 Input:
11072 path - The path of the directory to remove (ROM)
11073 rmsubdirs -
11074 - TRUE - All sub-dirs and files in the target dir will be removed
11075 - FALSE - FSrmdir will not remove non-empty directories
11076 Return Values:
11077 0 - The specified directory was deleted successfully
11078 EOF - The specified directory could not be deleted
11079 Side Effects:
11080 The FSerrno variable will be changed.
11081 Description:
11082 The FSrmdirpgm function passes a PIC18 ROM path pointer to the
11083 rmdirhelper function.
11084 Remarks:
11085 This function is for use with PIC18 when passing arguments in ROM.
11086 **************************************************************************/
11087
11088 #ifdef ALLOW_PGMFUNCTIONS
11089 int FSrmdirpgm (const rom char * path, unsigned char rmsubdirs)
11090 {
11091 return rmdirhelper (1, NULL, path, rmsubdirs);
11092 }
11093 #endif
11094
11095 /**************************************************************************
11096 Function:
11097 int wFSrmdirpgm (const rom unsigned short int * path, unsigned char rmsubdirs)
11098 Summary:
11099 Delete a directory with a path in ROM on PIC18
11100 Conditions:
11101 None.
11102 Input:
11103 path - The path of the directory to remove (ROM)
11104 rmsubdirs -
11105 - TRUE - All sub-dirs and files in the target dir will be removed
11106 - FALSE - FSrmdir will not remove non-empty directories
11107 Return Values:
11108 0 - The specified directory was deleted successfully
11109 EOF - The specified directory could not be deleted
11110 Side Effects:
11111 The FSerrno variable will be changed.
11112 Description:
11113 The FSrmdirpgm function passes a PIC18 ROM path pointer to the
11114 rmdirhelper function.
11115 Remarks:
11116 This function is for use with PIC18 when passing arguments in ROM.
11117 **************************************************************************/
11118
11119 #ifdef ALLOW_PGMFUNCTIONS
11120
11121 #ifdef SUPPORT_LFN
11122 int wFSrmdirpgm (const rom unsigned short int * path, unsigned char rmsubdirs)
11123 {
11124 int result;
11125 utfModeFileName = TRUE;
11126 result = rmdirhelper (1, NULL, (const char *)path, rmsubdirs);
11127 utfModeFileName = FALSE;
11128 return result;
11129 }
11130 #endif
11131
11132 #endif
11133
11134 /************************************************************************************************
11135 Function:
11136 // PIC24/30/33/32
11137 int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs)
11138 // PIC18
11139 int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs)
11140 Summary:
11141 Helper function for FSrmdir
11142 Conditions:
11143 This function should not be called by the user.
11144 Input:
11145 path - The path of the dir to delete
11146 rmsubdirs -
11147 - TRUE - Remove all sub-directories and files in the directory
11148 - FALSE - Non-empty directories can not be removed
11149 Return Values:
11150 0 - The specified directory was successfully removed.
11151 EOF - The specified directory could not be removed.
11152 Side Effects:
11153 The FSerrno variable will be changed.
11154 Description:
11155 This helper function is used by the FSmkdir function. If the path
11156 argument is specified in ROM for PIC18 this function will be able
11157 to parse it correctly. This function will first change to the
11158 specified directory. If the rmsubdirs argument is FALSE the function
11159 will search through the directory to ensure that it is empty and then
11160 remove it. If the rmsubdirs argument is TRUE the function will also
11161 search through the directory for subdirectories or files. When the
11162 function finds a file, the file will be erased. When the function
11163 finds a subdirectory, it will switch to the subdirectory and begin
11164 removing all of the files in that subdirectory. Once the subdirectory
11165 is empty, the function will switch back to the original directory.
11166 return to the original position in that directory, and continue removing
11167 files. Once the specified directory is empty, the function will
11168 change to the parent directory, search through it for the directory
11169 to remove, and then erase that directory.
11170 Remarks:
11171 None.
11172 ************************************************************************************************/
11173
11174 #ifdef ALLOW_PGMFUNCTIONS
11175 int rmdirhelper (BYTE mode, char * ramptr, const rom char * romptr, unsigned char rmsubdirs)
11176 #else
11177 int rmdirhelper (BYTE mode, char * ramptr, char * romptr, unsigned char rmsubdirs)
11178 #endif
11179 {
11180 FILEOBJ tempCWD = &tempCWDobj;
11181 FILEOBJ fo = &gFileTemp;
11182 DIRENTRY entry;
11183 WORD handle = 0;
11184 WORD handle2;
11185 WORD subDirDepth;
11186 short int Index3 = 0;
11187 char Index, Index2;
11188
11189 #if defined(SUPPORT_LFN)
11190 BOOL prevUtfModeFileName = utfModeFileName;
11191 char tempArray[514];
11192 WORD prevHandle;
11193 LFN_ENTRY *lfno;
11194 FSFILE cwdTemp;
11195 UINT16_VAL tempShift;
11196 unsigned short int *tempLFN = (unsigned short int *)&tempArray[0];
11197 BOOL forFirstTime;
11198 #else
11199 char tempArray[13];
11200 #endif
11201 #ifndef __18CXX
11202
11203 #else
11204 char dotdotname[] = "..";
11205 char dotdotname1[5] = {'.','\0','.','\0','\0'};
11206 #endif
11207
11208 FSerrno = CE_GOOD;
11209
11210 // Back up the current working directory
11211 FileObjectCopy (tempCWD, cwdptr);
11212
11213 #ifdef ALLOW_PGMFUNCTIONS
11214 if (mode)
11215 {
11216 if (chdirhelper (1, NULL, romptr))
11217 {
11218 FSerrno = CE_DIR_NOT_FOUND;
11219 return -1;
11220 }
11221 }
11222 else
11223 {
11224 #endif
11225 if (FSchdir (ramptr))
11226 {
11227 FSerrno = CE_DIR_NOT_FOUND;
11228 return -1;
11229 }
11230 #ifdef ALLOW_PGMFUNCTIONS
11231 }
11232 #endif
11233
11234 // Make sure we aren't trying to remove the root dir or the CWD
11235 if ((cwdptr->dirclus == FatRootDirClusterValue) || (cwdptr->dirclus == tempCWD->dirclus))
11236 {
11237 FileObjectCopy (cwdptr, tempCWD);
11238 FSerrno = CE_INVALID_ARGUMENT;
11239 return -1;
11240 }
11241
11242 handle++;
11243 entry = Cache_File_Entry (cwdptr, &handle, TRUE);
11244
11245 if (entry == NULL)
11246 {
11247 FileObjectCopy (cwdptr, tempCWD);
11248 FSerrno = CE_BADCACHEREAD;
11249 return -1;
11250 }
11251
11252 handle++;
11253 entry = Cache_File_Entry (cwdptr, &handle, FALSE);
11254 if (entry == NULL)
11255 {
11256 FileObjectCopy (cwdptr, tempCWD);
11257 FSerrno = CE_BADCACHEREAD;
11258 return -1;
11259 }
11260 // Don't remove subdirectories and sub-files
11261 if (!rmsubdirs)
11262 {
11263 while (entry->DIR_Name[0] != 0)
11264 {
11265 if ((unsigned char)entry->DIR_Name[0] != 0xE5)
11266 {
11267 FileObjectCopy (cwdptr, tempCWD);
11268 FSerrno = CE_DIR_NOT_EMPTY;
11269 return -1;
11270 }
11271 handle++;
11272 entry = Cache_File_Entry (cwdptr, &handle, FALSE);
11273 if ((entry == NULL))
11274 {
11275 FileObjectCopy (cwdptr, tempCWD);
11276 FSerrno = CE_BADCACHEREAD;
11277 return -1;
11278 }
11279 }
11280 }
11281 else
11282 {
11283 // Do remove subdirectories and sub-files
11284 dirCleared = FALSE;
11285 subDirDepth = 0;
11286 #if defined(SUPPORT_LFN)
11287 tempCWD-> utf16LFNptr = (unsigned short int *)&tempArray[0];
11288 fo-> utf16LFNptr = (unsigned short int *)&tempArray[0];
11289 #endif
11290
11291 while (!dirCleared)
11292 {
11293 if (entry->DIR_Name[0] != 0)
11294 {
11295 if (((unsigned char)entry->DIR_Name[0] != 0xE5) && (entry->DIR_Attr == ATTR_LONG_NAME))
11296 {
11297 #if defined(SUPPORT_LFN)
11298 lfno = (LFN_ENTRY *)entry;
11299
11300 if(lfno->LFN_SequenceNo & 0x40)
11301 {
11302 Index3 = (lfno->LFN_SequenceNo - 0x41) * 13;
11303 tempLFN[Index3 + 13] = 0x0000;
11304 forFirstTime = TRUE;
11305 }
11306 else
11307 {
11308 Index3 = (lfno->LFN_SequenceNo - 1) * 13;
11309 forFirstTime = FALSE;
11310 }
11311
11312 tempShift.byte.LB = lfno->LFN_Part1[0];
11313 tempShift.byte.HB = lfno->LFN_Part1[1];
11314 tempLFN[Index3++] = tempShift.Val;
11315 tempShift.byte.LB = lfno->LFN_Part1[2];
11316 tempShift.byte.HB = lfno->LFN_Part1[3];
11317 tempLFN[Index3++] = tempShift.Val;
11318 tempShift.byte.LB = lfno->LFN_Part1[4];
11319 tempShift.byte.HB = lfno->LFN_Part1[5];
11320 tempLFN[Index3++] = tempShift.Val;
11321 tempShift.byte.LB = lfno->LFN_Part1[6];
11322 tempShift.byte.HB = lfno->LFN_Part1[7];
11323 tempLFN[Index3++] = tempShift.Val;
11324 tempShift.byte.LB = lfno->LFN_Part1[8];
11325 tempShift.byte.HB = lfno->LFN_Part1[9];
11326 tempLFN[Index3++] = tempShift.Val;
11327
11328 tempLFN[Index3++] = lfno->LFN_Part2[0];
11329 tempLFN[Index3++] = lfno->LFN_Part2[1];
11330 tempLFN[Index3++] = lfno->LFN_Part2[2];
11331 tempLFN[Index3++] = lfno->LFN_Part2[3];
11332 tempLFN[Index3++] = lfno->LFN_Part2[4];
11333 tempLFN[Index3++] = lfno->LFN_Part2[5];
11334
11335 tempLFN[Index3++] = lfno->LFN_Part3[0];
11336 tempLFN[Index3] = lfno->LFN_Part3[1];
11337
11338 if(forFirstTime)
11339 {
11340 tempCWD->utf16LFNlength = Index3;
11341
11342 for(Index = 12;Index >= 0;Index--)
11343 {
11344 if((tempLFN[Index3 - Index - 1]) == 0x0000)
11345 {
11346 tempCWD->utf16LFNlength = Index3 - Index;
11347 break;
11348 }
11349 }
11350
11351 fo->utf16LFNlength = tempCWD->utf16LFNlength;
11352 }
11353 handle++;
11354 #endif
11355 }
11356 else if (((unsigned char)entry->DIR_Name[0] != 0xE5) && (entry->DIR_Attr != ATTR_VOLUME) && (entry->DIR_Attr != ATTR_LONG_NAME))
11357 {
11358 if ((entry->DIR_Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)
11359 {
11360 // We have a directory
11361 subDirDepth++;
11362 #if defined(SUPPORT_LFN)
11363 if(tempCWD-> utf16LFNlength)
11364 {
11365 utfModeFileName = 1;
11366 Index = FSchdir(&tempArray[0]);
11367 utfModeFileName = prevUtfModeFileName;
11368 tempCWD-> utf16LFNlength = 0;
11369 fo-> utf16LFNlength = 0;
11370 }
11371 else
11372 #endif
11373 {
11374 for (Index = 0; (Index < DIR_NAMESIZE) && (entry->DIR_Name[(BYTE)Index] != 0x20); Index++)
11375 {
11376 tempArray[(BYTE)Index] = entry->DIR_Name[(BYTE)Index];
11377 }
11378 if (entry->DIR_Name[8] != 0x20)
11379 {
11380 tempArray[(BYTE)Index++] = '.';
11381 for (Index2 = 0; (Index2 < DIR_EXTENSION) && (entry->DIR_Name[Index2 + DIR_NAMESIZE] != 0x20); Index2++)
11382 {
11383 tempArray[(BYTE)Index++] = entry->DIR_Name[Index2 + DIR_NAMESIZE];
11384 }
11385 }
11386 tempArray[(BYTE)Index] = 0;
11387 #ifdef SUPPORT_LFN
11388 utfModeFileName = 0;
11389 #endif
11390 Index = FSchdir(&tempArray[0]);
11391 #ifdef SUPPORT_LFN
11392 utfModeFileName = prevUtfModeFileName;
11393 #endif
11394 }
11395
11396 // Change to the subdirectory
11397 if (Index)
11398 {
11399 FileObjectCopy (cwdptr, tempCWD);
11400 FSerrno = CE_DIR_NOT_FOUND;
11401 return -1;
11402 }
11403 else
11404 {
11405 // Make sure we're not trying to delete the CWD
11406 if (cwdptr->dirclus == tempCWD->dirclus)
11407 {
11408 FileObjectCopy (cwdptr, tempCWD);
11409 FSerrno = CE_INVALID_ARGUMENT;
11410 return -1;
11411 }
11412 }
11413 handle = 2;
11414 recache = TRUE;
11415 }
11416 else
11417 {
11418 #if defined(SUPPORT_LFN)
11419 if(!tempCWD-> utf16LFNlength)
11420 #endif
11421 {
11422 for (Index = 0; Index < 11; Index++)
11423 {
11424 fo->name[(BYTE)Index] = entry->DIR_Name[(BYTE)Index];
11425 }
11426 }
11427
11428 fo->dsk = &gDiskData;
11429
11430 fo->entry = handle;
11431 fo->dirclus = cwdptr->dirclus;
11432 fo->dirccls = cwdptr->dirccls;
11433 fo->cluster = 0;
11434 fo->ccls = 0;
11435
11436 if (FILEerase(fo, &handle, TRUE))
11437 {
11438 #if defined(SUPPORT_LFN)
11439 tempCWD-> utf16LFNlength = 0;
11440 fo-> utf16LFNlength = 0;
11441 #endif
11442 FileObjectCopy (cwdptr, tempCWD);
11443 FSerrno = CE_ERASE_FAIL;
11444 return -1;
11445 }
11446 else
11447 {
11448 handle++;
11449 }
11450 #if defined(SUPPORT_LFN)
11451 tempCWD-> utf16LFNlength = 0;
11452 fo-> utf16LFNlength = 0;
11453 #endif
11454 } // Check to see if it's a DIR entry
11455 }// Check non-dir entry to see if its a valid file
11456 else
11457 {
11458 handle++;
11459 }
11460
11461 if (recache)
11462 {
11463 recache = FALSE;
11464 cwdptr->dirccls = cwdptr->dirclus;
11465 entry = Cache_File_Entry (cwdptr, &handle, TRUE);
11466 }
11467 else
11468 {
11469 entry = Cache_File_Entry (cwdptr, &handle, FALSE);
11470 }
11471
11472 if (entry == NULL)
11473 {
11474 #if defined(SUPPORT_LFN)
11475 tempCWD-> utf16LFNlength = 0;
11476 fo-> utf16LFNlength = 0;
11477 #endif
11478 FileObjectCopy (cwdptr, tempCWD);
11479 FSerrno = CE_BADCACHEREAD;
11480 return -1;
11481 }
11482 }
11483 else
11484 {
11485 #if defined(SUPPORT_LFN)
11486 tempCWD-> utf16LFNlength = 0;
11487 fo-> utf16LFNlength = 0;
11488 #endif
11489
11490 // We have reached the end of the directory
11491 if (subDirDepth != 0)
11492 {
11493 handle2 = 0;
11494
11495 cwdptr->dirccls = cwdptr->dirclus;
11496 entry = Cache_File_Entry (cwdptr, &handle2, TRUE);
11497 if (entry == NULL)
11498 {
11499 FileObjectCopy (cwdptr, tempCWD);
11500 FSerrno = CE_BADCACHEREAD;
11501 return -1;
11502 }
11503
11504 // Get the cluster
11505 handle2 = GetFullClusterNumber(entry); // Get complete cluster number.
11506
11507 #ifndef __18CXX
11508 #ifdef SUPPORT_LFN
11509 if(utfModeFileName)
11510 Index3 = FSchdir (".\0.\0\0");
11511 else
11512 #endif
11513 Index3 = FSchdir ("..");
11514 #else
11515 #ifdef SUPPORT_LFN
11516 if(utfModeFileName)
11517 Index3 = FSchdir (dotdotname1);
11518 else
11519 #endif
11520 Index3 = FSchdir (dotdotname);
11521 #endif
11522 if(Index3)
11523 {
11524 FileObjectCopy (cwdptr, tempCWD);
11525 FSerrno = CE_DIR_NOT_FOUND;
11526 return -1;
11527 }
11528 // Return to our previous position in this directory
11529 handle = 2;
11530 cwdptr->dirccls = cwdptr->dirclus;
11531 entry = Cache_File_Entry (cwdptr, &handle, TRUE);
11532 if (entry == NULL)
11533 {
11534 FileObjectCopy (cwdptr, tempCWD);
11535 FSerrno = CE_BADCACHEREAD;
11536 return -1;
11537 }
11538
11539 // Get the cluster
11540 TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number.
11541
11542 while ((TempClusterCalc != handle2) ||
11543 ((TempClusterCalc == handle2) &&
11544 (((unsigned char)entry->DIR_Name[0] == 0xE5) || (entry->DIR_Attr == ATTR_VOLUME))))
11545 {
11546 handle++;
11547 entry = Cache_File_Entry (cwdptr, &handle, FALSE);
11548 if (entry == NULL)
11549 {
11550 FileObjectCopy (cwdptr, tempCWD);
11551 FSerrno = CE_BADCACHEREAD;
11552 return -1;
11553 }
11554 // Get the cluster
11555 TempClusterCalc = GetFullClusterNumber(entry); // Get complete cluster number in a loop.
11556 }
11557
11558 Index3 = 0;
11559 #if defined(SUPPORT_LFN)
11560 FileObjectCopy (&cwdTemp, cwdptr);
11561 prevHandle = handle - 1;
11562 lfno = (LFN_ENTRY *)Cache_File_Entry (cwdptr, &prevHandle, FALSE);
11563
11564
11565 while((lfno->LFN_Attribute == ATTR_LONG_NAME) && (lfno->LFN_SequenceNo != DIR_DEL)
11566 && (lfno->LFN_SequenceNo != DIR_EMPTY))
11567 {
11568 tempShift.byte.LB = lfno->LFN_Part1[0];
11569 tempShift.byte.HB = lfno->LFN_Part1[1];
11570 tempLFN[Index3++] = tempShift.Val;
11571 tempShift.byte.LB = lfno->LFN_Part1[2];
11572 tempShift.byte.HB = lfno->LFN_Part1[3];
11573 tempLFN[Index3++] = tempShift.Val;
11574 tempShift.byte.LB = lfno->LFN_Part1[4];
11575 tempShift.byte.HB = lfno->LFN_Part1[5];
11576 tempLFN[Index3++] = tempShift.Val;
11577 tempShift.byte.LB = lfno->LFN_Part1[6];
11578 tempShift.byte.HB = lfno->LFN_Part1[7];
11579 tempLFN[Index3++] = tempShift.Val;
11580 tempShift.byte.LB = lfno->LFN_Part1[8];
11581 tempShift.byte.HB = lfno->LFN_Part1[9];
11582 tempLFN[Index3++] = tempShift.Val;
11583
11584 tempLFN[Index3++] = lfno->LFN_Part2[0];
11585 tempLFN[Index3++] = lfno->LFN_Part2[1];
11586 tempLFN[Index3++] = lfno->LFN_Part2[2];
11587 tempLFN[Index3++] = lfno->LFN_Part2[3];
11588 tempLFN[Index3++] = lfno->LFN_Part2[4];
11589 tempLFN[Index3++] = lfno->LFN_Part2[5];
11590
11591 tempLFN[Index3++] = lfno->LFN_Part3[0];
11592 tempLFN[Index3++] = lfno->LFN_Part3[1];
11593
11594 prevHandle = prevHandle - 1;
11595 lfno = (LFN_ENTRY *)Cache_File_Entry (cwdptr, &prevHandle, FALSE);
11596 }
11597
11598 FileObjectCopy (cwdptr, &cwdTemp);
11599
11600 #endif
11601
11602 if(Index3 == 0)
11603 {
11604 memset (tempArray, 0x00, 12);
11605 for (Index = 0; Index < 11; Index++)
11606 {
11607 tempArray[(BYTE)Index] = entry->DIR_Name[(BYTE)Index];
11608 }
11609 #if defined(SUPPORT_LFN)
11610 cwdptr->utf16LFNlength = 0;
11611 #endif
11612 }
11613 #if defined(SUPPORT_LFN)
11614 else
11615 {
11616 cwdptr->utf16LFNlength = Index3;
11617
11618 for(Index = 12;Index >= 0;Index--)
11619 {
11620 if((tempLFN[Index3 - Index - 1]) == 0x0000)
11621 {
11622 cwdptr->utf16LFNlength = Index3 - Index;
11623 break;
11624 }
11625 }
11626
11627 cwdptr->utf16LFNptr = (unsigned short int *)&tempArray[0];
11628 }
11629 #endif
11630 // Erase the directory that we just cleared the subdirectories out of
11631
11632 if (eraseDir (&tempArray[0]))
11633 {
11634 FileObjectCopy (cwdptr, tempCWD);
11635 FSerrno = CE_ERASE_FAIL;
11636 return -1;
11637 }
11638 else
11639 {
11640 handle++;
11641 cwdptr->dirccls = cwdptr->dirclus;
11642 entry = Cache_File_Entry (cwdptr, &handle, TRUE);
11643 if (entry == NULL)
11644 {
11645 FileObjectCopy (cwdptr, tempCWD);
11646 FSerrno = CE_BADCACHEREAD;
11647 return -1;
11648 }
11649 }
11650
11651 // Decrease the subdirectory depth
11652 subDirDepth--;
11653 }
11654 else
11655 {
11656 dirCleared = TRUE;
11657 } // Check subdirectory depth
11658 } // Check until we get an empty entry
11659 } // Loop until the whole dir is cleared
11660 }
11661
11662 // Cache the current directory name
11663 // tempArray is used so we don't disturb the
11664 // global getcwd buffer
11665 if (FSgetcwd (&tempArray[0], 2) == NULL)
11666 {
11667 FileObjectCopy (cwdptr, tempCWD);
11668 return -1;
11669 }
11670 else
11671 {
11672 #if defined(SUPPORT_LFN)
11673 if(!cwdptr->utf16LFNlength)
11674 #endif
11675 {
11676 memset (tempArray, 0x00, 12);
11677 for (Index = 0; Index < 11; Index++)
11678 {
11679 tempArray[(BYTE)Index] = cwdptr->name[(BYTE)Index];
11680 }
11681 }
11682 }
11683
11684 // If we're here, this directory is empty
11685 #ifndef __18CXX
11686 #ifdef SUPPORT_LFN
11687 if(utfModeFileName)
11688 Index3 = FSchdir (".\0.\0\0");
11689 else
11690 #endif
11691 Index3 = FSchdir ("..");
11692 #else
11693 #ifdef SUPPORT_LFN
11694 if(utfModeFileName)
11695 Index3 = FSchdir (dotdotname1);
11696 else
11697 #endif
11698 Index3 = FSchdir (dotdotname);
11699 #endif
11700 if(Index3)
11701 {
11702 FileObjectCopy (cwdptr, tempCWD);
11703 FSerrno = CE_DIR_NOT_FOUND;
11704 return -1;
11705 }
11706
11707 #if defined(SUPPORT_LFN)
11708 if(cwdptr->utf16LFNlength)
11709 {
11710 Index3 = eraseDir((char *)cwdptr->utf16LFNptr);
11711 }
11712 else
11713 #endif
11714 {
11715 Index3 = eraseDir(tempArray);
11716 }
11717
11718 if (Index3)
11719 {
11720 FileObjectCopy (cwdptr, tempCWD);
11721 FSerrno = CE_ERASE_FAIL;
11722 return -1;
11723 }
11724 else
11725 {
11726 FileObjectCopy (cwdptr, tempCWD);
11727 return 0;
11728 }
11729 }
11730
11731
11732 /****************************************************************
11733 Function:
11734 int eraseDir (char * path)
11735 Summary:
11736 FSrmdir helper function to erase dirs
11737 Conditions:
11738 This function should not be called by the user.
11739 Input:
11740 path - The name of the directory to delete
11741 Return Values:
11742 0 - Dir was deleted successfully
11743 -1 - Dir could not be deleted.
11744 Side Effects:
11745 None
11746 Description:
11747 The eraseDir function is a helper function for the rmdirhelper
11748 function. The eraseDir function will search for the
11749 directory that matches the specified path name and then erase
11750 it with the FILEerase function.
11751 Remarks:
11752 None.
11753 *****************************************************************/
11754
11755 int eraseDir (char * path)
11756 {
11757 int result;
11758 BYTE Index;
11759 FSFILE tempCWDobj2;
11760
11761 if (MDD_WriteProtectState())
11762 {
11763 return (-1);
11764 }
11765
11766 // preserve CWD
11767 FileObjectCopy(&tempCWDobj2, cwdptr);
11768
11769 // If long file name not present, copy the 8.3 name in cwdptr
11770 #if defined(SUPPORT_LFN)
11771 if(!cwdptr->utf16LFNlength)
11772 #endif
11773 {
11774 for (Index = 0; Index <11; Index++)
11775 {
11776 cwdptr->name[Index] = *(path + Index);
11777 }
11778 }
11779
11780 // copy file object over
11781 FileObjectCopy(&gFileTemp, cwdptr);
11782
11783 // See if the file is found
11784 if(FILEfind (cwdptr, &gFileTemp, LOOK_FOR_MATCHING_ENTRY, 0) == CE_GOOD)
11785 {
11786 if(FILEerase(cwdptr, &cwdptr->entry, TRUE) == CE_GOOD)
11787 result = 0;
11788 else
11789 result = -1;
11790 }
11791 else
11792 result = -1;
11793
11794 FileObjectCopy(cwdptr, &tempCWDobj2);
11795 return(result);
11796 }
11797 #endif
11798
11799
11800 #endif
11801
11802
11803 #ifdef ALLOW_FILESEARCH
11804
11805
11806 /***********************************************************************************
11807 Function:
11808 int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec)
11809 Summary:
11810 Initial search function for the input Ascii fileName
11811 Conditions:
11812 None
11813 Input:
11814 fileName - The name to search for
11815 - Parital string search characters
11816 - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*)
11817 - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T)
11818 attr - The attributes that a found file may have
11819 - ATTR_READ_ONLY - File may be read only
11820 - ATTR_HIDDEN - File may be a hidden file
11821 - ATTR_SYSTEM - File may be a system file
11822 - ATTR_VOLUME - Entry may be a volume label
11823 - ATTR_DIRECTORY - File may be a directory
11824 - ATTR_ARCHIVE - File may have archive attribute
11825 - ATTR_MASK - All attributes
11826 rec - pointer to a structure to put the file information in
11827 Return Values:
11828 0 - File was found
11829 -1 - No file matching the specified criteria was found
11830 Side Effects:
11831 Search criteria from previous FindFirst call on passed SearchRec object
11832 will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext
11833 operations.It is the responsibility of the application to read the "utf16LFNfound"
11834 before it is lost.The FSerrno variable will be changed.
11835 Description:
11836 The FindFirst function will search for a file based on parameters passed in
11837 by the user. This function will use the FILEfind function to parse through
11838 the current working directory searching for entries that match the specified
11839 parameters. If a file is found, its parameters are copied into the SearchRec
11840 structure, as are the initial parameters passed in by the user and the position
11841 of the file entry in the current working directory.If the return value of the
11842 function is 0 then "utf16LFNfoundLength" indicates whether the file found was
11843 long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero
11844 for long file name and is zero for 8P3 format."utf16LFNfound" points to the
11845 address of long file name if found during the operation.
11846 Remarks:
11847 Call FindFirst or FindFirstpgm before calling FindNext
11848 ***********************************************************************************/
11849
11850 int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec)
11851 {
11852 FSFILE f;
11853 FILEOBJ fo = &f;
11854 WORD fHandle;
11855 BYTE j;
11856 BYTE Index;
11857 #ifdef SUPPORT_LFN
11858 short int indexLFN;
11859 #endif
11860
11861 FSerrno = CE_GOOD;
11862
11863 #ifdef SUPPORT_LFN
11864 fo->utf16LFNptr = &recordSearchName[0];
11865 rec->utf16LFNfound = &recordFoundName[0];
11866 #endif
11867
11868 // Format the file name as per 8.3 format or LFN format
11869 if( !FormatFileName(fileName, fo, 1) )
11870 {
11871 FSerrno = CE_INVALID_FILENAME;
11872 return -1;
11873 }
11874
11875 rec->initialized = FALSE;
11876
11877 #if defined(SUPPORT_LFN)
11878 rec->AsciiEncodingType = fo->AsciiEncodingType;
11879 recordSearchLength = fo->utf16LFNlength;
11880
11881 // If file name is 8.3 format copy it in 'searchname' string
11882 if(!recordSearchLength)
11883 #endif
11884 {
11885 for (Index = 0; (Index < 12) && (fileName[Index] != 0); Index++)
11886 {
11887 rec->searchname[Index] = fileName[Index];
11888 }
11889
11890 for (;Index < FILE_NAME_SIZE_8P3 + 2; Index++)
11891 {
11892 rec->searchname[Index] = 0;
11893 }
11894 }
11895
11896 rec->searchattr = attr;
11897 #ifdef ALLOW_DIRS
11898 rec->cwdclus = cwdptr->dirclus;
11899 #else
11900 rec->cwdclus = FatRootDirClusterValue;
11901 #endif
11902
11903 fo->dsk = &gDiskData;
11904 fo->cluster = 0;
11905 fo->ccls = 0;
11906 fo->entry = 0;
11907 fo->attributes = attr;
11908
11909 #ifndef ALLOW_DIRS
11910 // start at the root directory
11911 fo->dirclus = FatRootDirClusterValue;
11912 fo->dirccls = FatRootDirClusterValue;
11913 #else
11914 fo->dirclus = cwdptr->dirclus;
11915 fo->dirccls = cwdptr->dirccls;
11916 #endif
11917
11918 // copy file object over
11919 FileObjectCopy(&gFileTemp, fo);
11920
11921 // See if the file is found
11922 if (FILEfind (fo, &gFileTemp,LOOK_FOR_MATCHING_ENTRY, 1) != CE_GOOD)
11923 {
11924 FSerrno = CE_FILE_NOT_FOUND;
11925 return -1;
11926 }
11927
11928 fHandle = fo->entry;
11929
11930 if (FILEopen (fo, &fHandle, 'r') == CE_GOOD)
11931 {
11932 #if defined(SUPPORT_LFN)
11933 rec->utf16LFNfoundLength = fo->utf16LFNlength;
11934 if(fo->utf16LFNlength)
11935 {
11936 indexLFN = fo->utf16LFNlength;
11937 recordFoundName[indexLFN] = 0x0000;
11938 while(indexLFN--)
11939 recordFoundName[indexLFN] = fileFoundString[indexLFN];
11940 }
11941 #endif
11942
11943 for(j = 0; j < FILE_NAME_SIZE_8P3 + 2 ; j++)
11944 {
11945 rec->filename[j] = 0;
11946 }
11947
11948 // Copy as much name as there is
11949 if (fo->attributes != ATTR_VOLUME)
11950 {
11951 for (Index = 0, j = 0; (j < 8) && (fo->name[j] != 0x20); Index++, j++)
11952 {
11953 rec->filename[Index] = fo->name[j];
11954 }
11955
11956 if(fo->name[8] != 0x20)
11957 {
11958 rec->filename[Index++] = '.';
11959
11960 // Move to the extension, even if there are more space chars
11961 for (j = 8; (j < 11) && (fo->name[j] != 0x20); Index++, j++)
11962 {
11963 rec->filename[Index] = fo->name[j];
11964 }
11965 }
11966 }
11967 else
11968 {
11969 for (Index = 0; Index < DIR_NAMECOMP; Index++)
11970 {
11971 rec->filename[Index] = fo->name[Index];
11972 }
11973 }
11974
11975 rec->attributes = fo->attributes;
11976 rec->filesize = fo->size;
11977 rec->timestamp = (DWORD)((DWORD)fo->date << 16) + fo->time;
11978 rec->entry = fo->entry;
11979 rec->initialized = TRUE;
11980 return 0;
11981 }
11982 else
11983 {
11984 FSerrno = CE_BADCACHEREAD;
11985 return -1;
11986 }
11987 }
11988
11989
11990 /**********************************************************************
11991 Function:
11992 int FindNext (SearchRec * rec)
11993 Summary:
11994 Sequential search function
11995 Conditions:
11996 None
11997 Input:
11998 rec - The structure to store the file information in
11999 Return Values:
12000 0 - File was found
12001 -1 - No additional files matching the specified criteria were found
12002 Side Effects:
12003 Search criteria from previous FindNext call on passed SearchRec object
12004 will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext
12005 operations.It is the responsibility of the application to read the "utf16LFNfound"
12006 before it is lost.The FSerrno variable will be changed.
12007 Description:
12008 The FindNext function performs the same function as the FindFirst
12009 funciton, except it does not copy any search parameters into the
12010 SearchRec structure (only info about found files) and it begins
12011 searching at the last directory entry offset at which a file was
12012 found, rather than at the beginning of the current working
12013 directory.If the return value of the function is 0 then "utf16LFNfoundLength"
12014 indicates whether the file found was long file name or short file
12015 name(8P3 format). The "utf16LFNfoundLength" is non-zero for long file name
12016 and is zero for 8P3 format."utf16LFNfound" points to the address of long
12017 file name if found during the operation.
12018 Remarks:
12019 Call FindFirst or FindFirstpgm before calling this function
12020 **********************************************************************/
12021
12022 int FindNext (SearchRec * rec)
12023 {
12024 FSFILE f;
12025 FILEOBJ fo = &f;
12026 BYTE i, j;
12027 #ifdef SUPPORT_LFN
12028 short int indexLFN;
12029 #endif
12030
12031 FSerrno = CE_GOOD;
12032
12033 // Make sure we called FindFirst on this object
12034 if (rec->initialized == FALSE)
12035 {
12036 FSerrno = CE_NOT_INIT;
12037 return -1;
12038 }
12039
12040 // Make sure we called FindFirst in the cwd
12041 #ifdef ALLOW_DIRS
12042 if (rec->cwdclus != cwdptr->dirclus)
12043 {
12044 FSerrno = CE_INVALID_ARGUMENT;
12045 return -1;
12046 }
12047 #endif
12048
12049 #if defined(SUPPORT_LFN)
12050 fo->AsciiEncodingType = rec->AsciiEncodingType;
12051 fo->utf16LFNlength = recordSearchLength;
12052 if(fo->utf16LFNlength)
12053 {
12054 fo->utf16LFNptr = &recordSearchName[0];
12055 }
12056 else
12057 #endif
12058 {
12059 // Format the file name
12060 if( !FormatFileName(rec->searchname, fo, 1) )
12061 {
12062 FSerrno = CE_INVALID_FILENAME;
12063 return -1;
12064 }
12065 }
12066
12067 /* Brn: Copy the formatted name to "fo" which is necesary before calling "FILEfind" function */
12068 //strcpy(fo->name,rec->searchname);
12069
12070 fo->dsk = &gDiskData;
12071 fo->cluster = 0;
12072 fo->ccls = 0;
12073 fo->entry = rec->entry + 1;
12074 fo->attributes = rec->searchattr;
12075
12076 #ifndef ALLOW_DIRS
12077 // start at the root directory
12078 fo->dirclus = FatRootDirClusterValue;
12079 fo->dirccls = FatRootDirClusterValue;
12080 #else
12081 fo->dirclus = cwdptr->dirclus;
12082 fo->dirccls = cwdptr->dirccls;
12083 #endif
12084
12085 // copy file object over
12086 FileObjectCopy(&gFileTemp, fo);
12087
12088 // See if the file is found
12089 if (CE_GOOD != FILEfind (fo, &gFileTemp,LOOK_FOR_MATCHING_ENTRY, 1))
12090 {
12091 FSerrno = CE_FILE_NOT_FOUND;
12092 return -1;
12093 }
12094 else
12095 {
12096 #if defined(SUPPORT_LFN)
12097 rec->utf16LFNfoundLength = fo->utf16LFNlength;
12098 if(fo->utf16LFNlength)
12099 {
12100 indexLFN = fo->utf16LFNlength;
12101 recordFoundName[indexLFN] = 0x0000;
12102 while(indexLFN--)
12103 recordFoundName[indexLFN] = fileFoundString[indexLFN];
12104 }
12105 #endif
12106
12107 for(j = 0; j < FILE_NAME_SIZE_8P3 + 2 ; j++)
12108 {
12109 rec->filename[j] = 0;
12110 }
12111
12112 if (fo->attributes != ATTR_VOLUME)
12113 {
12114 for (i = 0, j = 0; (j < 8) && (fo->name[j] != 0x20); i++, j++)
12115 {
12116 rec->filename[i] = fo->name[j];
12117 }
12118
12119 if(fo->name[8] != 0x20)
12120 {
12121 rec->filename[i++] = '.';
12122
12123 // Move to the extension, even if there are more space chars
12124 for (j = 8; (j < 11) && (fo->name[j] != 0x20); i++, j++)
12125 {
12126 rec->filename[i] = fo->name[j];
12127 }
12128 }
12129 }
12130 else
12131 {
12132 for (i = 0; i < DIR_NAMECOMP; i++)
12133 {
12134 rec->filename[i] = fo->name[i];
12135 }
12136 }
12137
12138 rec->attributes = fo->attributes;
12139 rec->filesize = fo->size;
12140 rec->timestamp = (DWORD)((DWORD)fo->date << 16) + fo->time;
12141 rec->entry = fo->entry;
12142 return 0;
12143 }
12144 }
12145
12146 /***********************************************************************************
12147 Function:
12148 int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec)
12149 Summary:
12150 Initial search function for the input UTF16 fileName
12151 Conditions:
12152 None
12153 Input:
12154 fileName - The name to search for
12155 - Parital string search characters
12156 - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*)
12157 - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T)
12158 attr - The attributes that a found file may have
12159 - ATTR_READ_ONLY - File may be read only
12160 - ATTR_HIDDEN - File may be a hidden file
12161 - ATTR_SYSTEM - File may be a system file
12162 - ATTR_VOLUME - Entry may be a volume label
12163 - ATTR_DIRECTORY - File may be a directory
12164 - ATTR_ARCHIVE - File may have archive attribute
12165 - ATTR_MASK - All attributes
12166 rec - pointer to a structure to put the file information in
12167 Return Values:
12168 0 - File was found
12169 -1 - No file matching the specified criteria was found
12170 Side Effects:
12171 Search criteria from previous wFindFirst call on passed SearchRec object
12172 will be lost. "utf16LFNfound" is overwritten after subsequent wFindFirst/FindNext
12173 operations.It is the responsibility of the application to read the "utf16LFNfound"
12174 before it is lost.The FSerrno variable will be changed.
12175 Description:
12176 The wFindFirst function will search for a file based on parameters passed in
12177 by the user. This function will use the FILEfind function to parse through
12178 the current working directory searching for entries that match the specified
12179 parameters. If a file is found, its parameters are copied into the SearchRec
12180 structure, as are the initial parameters passed in by the user and the position
12181 of the file entry in the current working directory.If the return value of the
12182 function is 0 then "utf16LFNfoundLength" indicates whether the file found was
12183 long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero
12184 for long file name and is zero for 8P3 format."utf16LFNfound" points to the
12185 address of long file name if found during the operation.
12186 Remarks:
12187 Call FindFirst or FindFirstpgm before calling FindNext
12188 ***********************************************************************************/
12189
12190 #ifdef SUPPORT_LFN
12191 int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec)
12192 {
12193 int result;
12194 utfModeFileName = TRUE;
12195 result = FindFirst ((const char *)fileName,attr,rec);
12196 utfModeFileName = FALSE;
12197 return result;
12198 }
12199 #endif
12200
12201 #endif
12202
12203 #ifdef ALLOW_FSFPRINTF
12204
12205
12206 /**********************************************************************
12207 Function:
12208 int FSputc (char c, FSFILE * file)
12209 Summary:
12210 FSfprintf helper function to write a char
12211 Conditions:
12212 This function should not be called by the user.
12213 Input:
12214 c - The character to write to the file.
12215 file - The file to write to.
12216 Return Values:
12217 0 - The character was written successfully
12218 EOF - The character was not written to the file.
12219 Side Effects:
12220 None
12221 Description:
12222 This is a helper function for FSfprintf. It will write one
12223 character to a file.
12224 Remarks:
12225 None
12226 **********************************************************************/
12227
12228 int FSputc (char c, FSFILE * file)
12229 {
12230 if (FSfwrite ((void *)&c, 1, 1, file) != 1)
12231 return EOF;
12232 else
12233 return 0;
12234 }
12235
12236
12237 /**********************************************************************
12238 Function:
12239 int str_put_n_chars (FSFILE * handle, unsigned char n, char c)
12240 Summary:
12241 FSfprintf helper function to write a char multiple times
12242 Conditions:
12243 This function should not be called by the user.
12244 Input:
12245 handle - The file to write to.
12246 n - The number of times to write that character to a file.
12247 c - The character to write to the file.
12248 Return Values:
12249 0 - The characters were written successfully
12250 EOF - The characters were not written to the file.
12251 Side Effects:
12252 None
12253 Description:
12254 This funciton is used by the FSfprintf function to write multiple
12255 instances of a single character to a file (for example, when
12256 padding a format specifier with leading spacez or zeros).
12257 Remarks:
12258 None.
12259 **********************************************************************/
12260
12261
12262 unsigned char str_put_n_chars (FSFILE * handle, unsigned char n, char c)
12263 {
12264 while (n--)
12265 if (FSputc (c, handle) == EOF)
12266 return 1;
12267 return 0;
12268 }
12269
12270
12271 /**********************************************************************
12272 Function:
12273 // PIC24/30/33/32
12274 int FSfprintf (FSFILE * fptr, const char * fmt, ...)
12275 // PIC18
12276 int FSfpritnf (FSFILE * fptr, const rom char * fmt, ...)
12277 Summary:
12278 Function to write formatted strings to a file
12279 Conditions:
12280 For PIC18, integer promotion must be enabled in the project build
12281 options menu. File opened in a write mode.
12282 Input:
12283 fptr - A pointer to the file to write to.
12284 fmt - A string of characters and format specifiers to write to
12285 the file
12286 ... - Additional arguments inserted in the string by format
12287 specifiers
12288 Returns:
12289 The number of characters written to the file
12290 Side Effects:
12291 The FSerrno variable will be changed.
12292 Description:
12293 Writes a specially formatted string to a file.
12294 Remarks:
12295 Consult AN1045 for a full description of how to use format
12296 specifiers.
12297 **********************************************************************/
12298
12299 #ifdef __18CXX
12300 int FSfprintf (FSFILE *fptr, const rom char *fmt, ...)
12301 #else
12302 int FSfprintf (FSFILE *fptr, const char * fmt, ...)
12303 #endif
12304 {
12305 va_list ap;
12306 int n;
12307
12308 va_start (ap, fmt);
12309 n = FSvfprintf (fptr, fmt, ap);
12310 va_end (ap);
12311 return n;
12312 }
12313
12314
12315 /**********************************************************************
12316 Function:
12317 // PIC24/30/33/32
12318 int FSvfprintf (FSFILE * handle, const char * formatString, va_list ap)
12319 // PIC18
12320 int FSvfpritnf (auto FSFILE * handle, auto const rom char * formatString, auto va_list ap)
12321 Summary:
12322 Helper function for FSfprintf
12323 Conditions:
12324 This function should not be called by the user.
12325 Input:
12326 handle - A pointer to the file to write to.
12327 formatString - A string of characters and format specifiers to write to
12328 the file
12329 ap - A structure pointing to the arguments on the stack
12330 Returns:
12331 The number of characters written to the file
12332 Side Effects:
12333 The FSerrno variable will be changed.
12334 Description:
12335 This helper function will access the elements passed to FSfprintf
12336 Remarks:
12337 Consult AN1045 for a full description of how to use format
12338 specifiers.
12339 **********************************************************************/
12340
12341 #ifdef __18CXX
12342 int FSvfprintf (auto FSFILE *handle, auto const rom char * formatString, auto va_list ap)
12343 #else
12344 int FSvfprintf (FSFILE *handle, const char * formatString, va_list ap)
12345 #endif
12346 {
12347 unsigned char c;
12348 int count = 0;
12349
12350 for (c = *formatString; c; c = *++formatString)
12351 {
12352 if (c == '%')
12353 {
12354 unsigned char flags = 0;
12355 unsigned char width = 0;
12356 unsigned char precision = 0;
12357 unsigned char have_precision = 0;
12358 unsigned char size = 0;
12359 #ifndef __18CXX
12360 unsigned char size2 = 0;
12361 #endif
12362 unsigned char space_cnt;
12363 unsigned char cval;
12364 #ifdef __18CXX
12365 unsigned long larg;
12366 far rom char * romstring;
12367 #else
12368 unsigned long long larg;
12369 #endif
12370 char * ramstring;
12371 int n;
12372
12373 FSerrno = CE_GOOD;
12374
12375 c = *++formatString;
12376
12377 while ((c == '-') || (c == '+') || (c == ' ') || (c == '#') || (c == '0'))
12378 {
12379 switch (c)
12380 {
12381 case '-':
12382 flags |= _FLAG_MINUS;
12383 break;
12384 case '+':
12385 flags |= _FLAG_PLUS;
12386 break;
12387 case ' ':
12388 flags |= _FLAG_SPACE;
12389 break;
12390 case '#':
12391 flags |= _FLAG_OCTO;
12392 break;
12393 case '0':
12394 flags |= _FLAG_ZERO;
12395 break;
12396 }
12397 c = *++formatString;
12398 }
12399 /* the optional width field is next */
12400 if (c == '*')
12401 {
12402 n = va_arg (ap, int);
12403 if (n < 0)
12404 {
12405 flags |= _FLAG_MINUS;
12406 width = -n;
12407 }
12408 else
12409 width = n;
12410 c = *++formatString;
12411 }
12412 else
12413 {
12414 cval = 0;
12415 while ((unsigned char) isdigit (c))
12416 {
12417 cval = cval * 10 + c - '0';
12418 c = *++formatString;
12419 }
12420 width = cval;
12421 }
12422
12423 /* if '-' is specified, '0' is ignored */
12424 if (flags & _FLAG_MINUS)
12425 flags &= ~_FLAG_ZERO;
12426
12427 /* the optional precision field is next */
12428 if (c == '.')
12429 {
12430 c = *++formatString;
12431 if (c == '*')
12432 {
12433 n = va_arg (ap, int);
12434 if (n >= 0)
12435 {
12436 precision = n;
12437 have_precision = 1;
12438 }
12439 c = *++formatString;
12440 }
12441 else
12442 {
12443 cval = 0;
12444 while ((unsigned char) isdigit (c))
12445 {
12446 cval = cval * 10 + c - '0';
12447 c = *++formatString;
12448 }
12449 precision = cval;
12450 have_precision = 1;
12451 }
12452 }
12453
12454 /* the optional 'h' specifier. since int and short int are
12455 the same size for MPLAB C18, this is a NOP for us. */
12456 if (c == 'h')
12457 {
12458 c = *++formatString;
12459 /* if 'c' is another 'h' character, this is an 'hh'
12460 specifier and the size is 8 bits */
12461 if (c == 'h')
12462 {
12463 size = _FMT_BYTE;
12464 c = *++formatString;
12465 }
12466 }
12467 else if ((c == 't') || (c == 'z'))
12468 c = *++formatString;
12469 #ifdef __18CXX
12470 else if ((c == 'H') || (c == 'T') || (c == 'Z'))
12471 {
12472 size = _FMT_SHRTLONG;
12473 c = *++formatString;
12474 }
12475 else if ((c == 'l') || (c == 'j'))
12476 #else
12477 else if ((c == 'q') || (c == 'j'))
12478 {
12479 size = _FMT_LONGLONG;
12480 c = *++formatString;
12481 }
12482 else if (c == 'l')
12483 #endif
12484 {
12485 size = _FMT_LONG;
12486 c = *++formatString;
12487 }
12488
12489 switch (c)
12490 {
12491 case '\0':
12492 /* this is undefined behaviour. we have a trailing '%' character
12493 in the string, perhaps with some flags, width, precision
12494 stuff as well, but no format specifier. We'll, arbitrarily,
12495 back up a character so that the loop will terminate
12496 properly when it loops back and we'll output a '%'
12497 character. */
12498 --formatString;
12499 /* fallthrough */
12500 case '%':
12501 if (FSputc ('%', handle) == EOF)
12502 {
12503 FSerrno = CE_WRITE_ERROR;
12504 return EOF;
12505 }
12506 ++count;
12507 break;
12508 case 'c':
12509 space_cnt = 0;
12510 if (width > 1)
12511 {
12512 space_cnt = width - 1;
12513 count += space_cnt;
12514 }
12515 if (space_cnt && !(flags & _FLAG_MINUS))
12516 {
12517 if (str_put_n_chars (handle, space_cnt, ' '))
12518 {
12519 FSerrno = CE_WRITE_ERROR;
12520 return EOF;
12521 }
12522 space_cnt = 0;
12523 }
12524 c = va_arg (ap, int);
12525 if (FSputc (c, handle) == EOF)
12526 {
12527 FSerrno = CE_WRITE_ERROR;
12528 return EOF;
12529 }
12530 ++count;
12531 if (str_put_n_chars (handle, space_cnt, ' '))
12532 {
12533 FSerrno = CE_WRITE_ERROR;
12534 return EOF;
12535 }
12536 break;
12537 case 'S':
12538 #ifdef __18CXX
12539 if (size == _FMT_SHRTLONG)
12540 romstring = va_arg (ap, rom far char *);
12541 else
12542 romstring = (far rom char*)va_arg (ap, rom near char *);
12543 n = strlenpgm (romstring);
12544 /* Normalize the width based on the length of the actual
12545 string and the precision. */
12546 if (have_precision && precision < (unsigned char) n)
12547 n = precision;
12548 if (width < (unsigned char) n)
12549 width = n;
12550 space_cnt = width - (unsigned char) n;
12551 count += space_cnt;
12552 /* we've already calculated the space count that the width
12553 will require. now we want the width field to have the
12554 number of character to display from the string itself,
12555 limited by the length of the actual string and the
12556 specified precision. */
12557 if (have_precision && precision < width)
12558 width = precision;
12559 /* if right justified, we print the spaces before the
12560 string */
12561 if (!(flags & _FLAG_MINUS))
12562 {
12563 if (str_put_n_chars (handle, space_cnt, ' '))
12564 {
12565 FSerrno = CE_WRITE_ERROR;
12566 return EOF;
12567 }
12568 space_cnt = 0;
12569 }
12570 cval = 0;
12571 for (c = *romstring; c && cval < width; c = *++romstring)
12572 {
12573 if (FSputc (c, handle) == EOF)
12574 {
12575 FSerrno = CE_WRITE_ERROR;
12576 return EOF;
12577 }
12578 ++count;
12579 ++cval;
12580 }
12581 /* If there are spaces left, it's left justified.
12582 Either way, calling the function unconditionally
12583 is smaller code. */
12584 if (str_put_n_chars (handle, space_cnt, ' '))
12585 {
12586 FSerrno = CE_WRITE_ERROR;
12587 return EOF;
12588 }
12589 break;
12590 #endif
12591 case 's':
12592 ramstring = va_arg (ap, char *);
12593 n = strlen (ramstring);
12594 /* Normalize the width based on the length of the actual
12595 string and the precision. */
12596 if (have_precision && precision < (unsigned char) n)
12597 n = precision;
12598 if (width < (unsigned char) n)
12599 width = n;
12600 space_cnt = width - (unsigned char) n;
12601 count += space_cnt;
12602 /* we've already calculated the space count that the width
12603 will require. now we want the width field to have the
12604 number of character to display from the string itself,
12605 limited by the length of the actual string and the
12606 specified precision. */
12607 if (have_precision && precision < width)
12608 width = precision;
12609 /* if right justified, we print the spaces before the string */
12610 if (!(flags & _FLAG_MINUS))
12611 {
12612 if (str_put_n_chars (handle, space_cnt, ' '))
12613 {
12614 FSerrno = CE_WRITE_ERROR;
12615 return EOF;
12616 }
12617 space_cnt = 0;
12618 }
12619 cval = 0;
12620 for (c = *ramstring; c && cval < width; c = *++ramstring)
12621 {
12622 if (FSputc (c, handle) == EOF)
12623 {
12624 FSerrno = CE_WRITE_ERROR;
12625 return EOF;
12626 }
12627 ++count;
12628 ++cval;
12629 }
12630 /* If there are spaces left, it's left justified.
12631 Either way, calling the function unconditionally
12632 is smaller code. */
12633 if (str_put_n_chars (handle, space_cnt, ' '))
12634 {
12635 FSerrno = CE_WRITE_ERROR;
12636 return EOF;
12637 }
12638 break;
12639 case 'd':
12640 case 'i':
12641 flags |= _FLAG_SIGNED;
12642 /* fall through */
12643 case 'o':
12644 case 'u':
12645 case 'x':
12646 case 'X':
12647 case 'b':
12648 case 'B':
12649 /* This is a bit of a trick. The 'l' and 'hh' size
12650 specifiers are valid only for the integer conversions,
12651 not the 'p' or 'P' conversions, and are ignored for the
12652 latter. By jumping over the additional size specifier
12653 checks here we get the best code size since we can
12654 limit the size checks in the remaining code. */
12655 if (size == _FMT_LONG)
12656 {
12657 if (flags & _FLAG_SIGNED)
12658 larg = va_arg (ap, long int);
12659 else
12660 larg = va_arg (ap, unsigned long int);
12661 goto _do_integer_conversion;
12662 }
12663 else if (size == _FMT_BYTE)
12664 {
12665 if (flags & _FLAG_SIGNED)
12666 larg = (signed char) va_arg (ap, int);
12667 else
12668 larg = (unsigned char) va_arg (ap, unsigned int);
12669 goto _do_integer_conversion;
12670 }
12671 #ifndef __18CXX
12672 else if (size == _FMT_LONGLONG)
12673 {
12674 if (flags & _FLAG_SIGNED)
12675 larg = (signed long long)va_arg (ap, long long);
12676 else
12677 larg = (unsigned long long) va_arg (ap, unsigned long long);
12678 goto _do_integer_conversion;
12679 }
12680 #endif
12681 /* fall trough */
12682 case 'p':
12683 case 'P':
12684 #ifdef __18CXX
12685 if (size == _FMT_SHRTLONG)
12686 {
12687 if (flags & _FLAG_SIGNED)
12688 larg = va_arg (ap, short long int);
12689 else
12690 larg = va_arg (ap, unsigned short long int);
12691 }
12692 else
12693 #endif
12694 if (flags & _FLAG_SIGNED)
12695 larg = va_arg (ap, int);
12696 else
12697 larg = va_arg (ap, unsigned int);
12698 _do_integer_conversion:
12699 /* default precision is 1 */
12700 if (!have_precision)
12701 precision = 1;
12702 {
12703 unsigned char digit_cnt = 0;
12704 unsigned char prefix_cnt = 0;
12705 unsigned char sign_char;
12706 /* A 32 bit number will require at most 32 digits in the
12707 string representation (binary format). */
12708 #ifdef __18CXX
12709 char buf[33];
12710 /* Start storing digits least-significant first */
12711 char *q = &buf[31];
12712 /* null terminate the string */
12713 buf[32] = '\0';
12714 #else
12715 char buf[65];
12716 char *q = &buf[63];
12717 buf[64] = '\0';
12718 #endif
12719 space_cnt = 0;
12720 size = 10;
12721
12722 switch (c)
12723 {
12724 case 'b':
12725 case 'B':
12726 size = 2;
12727 #ifndef __18CXX
12728 size2 = 1;
12729 #endif
12730 break;
12731 case 'o':
12732 size = 8;
12733 #ifndef __18CXX
12734 size2 = 3;
12735 #endif
12736 break;
12737 case 'p':
12738 case 'P':
12739 /* from here on out, treat 'p' conversions just
12740 like 'x' conversions. */
12741 c += 'x' - 'p';
12742 /* fall through */
12743 case 'x':
12744 case 'X':
12745 size = 16;
12746 #ifndef __18CXX
12747 size2 = 4;
12748 #endif
12749 break;
12750 }// switch (c)
12751
12752 /* if it's an unsigned conversion, we should ignore the
12753 ' ' and '+' flags */
12754 if (!(flags & _FLAG_SIGNED))
12755 flags &= ~(_FLAG_PLUS | _FLAG_SPACE);
12756
12757 /* if it's a negative value, we need to negate the
12758 unsigned version before we convert to text. Using
12759 unsigned for this allows us to (ab)use the 2's
12760 complement system to avoid overflow and be able to
12761 adequately handle LONG_MIN.
12762
12763 We'll figure out what sign character to print, if
12764 any, here as well. */
12765 #ifdef __18CXX
12766 if (flags & _FLAG_SIGNED && ((long) larg < 0))
12767 {
12768 larg = -(long) larg;
12769 #else
12770 if (flags & _FLAG_SIGNED && ((long long) larg < 0))
12771 {
12772 larg = -(long long) larg;
12773 #endif
12774 sign_char = '-';
12775 ++digit_cnt;
12776 }
12777 else if (flags & _FLAG_PLUS)
12778 {
12779 sign_char = '+';
12780 ++digit_cnt;
12781 }
12782 else if (flags & _FLAG_SPACE)
12783 {
12784 sign_char = ' ';
12785 ++digit_cnt;
12786 }
12787 else
12788 sign_char = '\0';
12789 /* get the digits for the actual number. If the
12790 precision is zero and the value is zero, the result
12791 is no characters. */
12792 if (precision || larg)
12793 {
12794 do
12795 {
12796 #ifdef __18CXX
12797 cval = s_digits[larg % size];
12798 if ((c == 'X') && (cval >= 'a'))
12799 cval -= 'a' - 'A';
12800 larg /= size;
12801 #else
12802 // larg is congruent mod size2 to its lower 16 bits
12803 // for size2 = 2^n, 0 <= n <= 4
12804 if (size2 != 0)
12805 cval = s_digits[(unsigned int) larg % size];
12806 else
12807 cval = s_digits[larg % size];
12808 if ((c == 'X') && (cval >= 'a'))
12809 cval -= 'a' - 'A';
12810 if (size2 != 0)
12811 larg = larg >> size2;
12812 else
12813 larg /= size;
12814 #endif
12815 *q-- = cval;
12816 ++digit_cnt;
12817 } while (larg);
12818 /* if the '#' flag was specified and we're dealing
12819 with an 'o', 'b', 'B', 'x', or 'X' conversion,
12820 we need a bit more. */
12821 if (flags & _FLAG_OCTO)
12822 {
12823 if (c == 'o')
12824 {
12825 /* per the standard, for octal, the '#' flag
12826 makes the precision be at least one more
12827 than the number of digits in the number */
12828 if (precision <= digit_cnt)
12829 precision = digit_cnt + 1;
12830 }
12831 else if ((c == 'x') || (c == 'X') || (c == 'b') || (c == 'B'))
12832 prefix_cnt = 2;
12833 }
12834 }
12835 else
12836 digit_cnt = 0;
12837
12838 /* The leading zero count depends on whether the '0'
12839 flag was specified or not. If it was not, then the
12840 count is the difference between the specified
12841 precision and the number of digits (including the
12842 sign character, if any) to be printed; otherwise,
12843 it's as if the precision were equal to the max of
12844 the specified precision and the field width. If a
12845 precision was specified, the '0' flag is ignored,
12846 however. */
12847 if ((flags & _FLAG_ZERO) && (width > precision)
12848 && !have_precision)
12849 precision = width;
12850 /* for the rest of the processing, precision contains
12851 the leading zero count for the conversion. */
12852 if (precision > digit_cnt)
12853 precision -= digit_cnt;
12854 else
12855 precision = 0;
12856 /* the space count is the difference between the field
12857 width and the digit count plus the leading zero
12858 count. If the width is less than the digit count
12859 plus the leading zero count, the space count is
12860 zero. */
12861 if (width > precision + digit_cnt + prefix_cnt)
12862 space_cnt = width - precision - digit_cnt - prefix_cnt;
12863
12864 /* for output, we check the justification, if it's
12865 right justified and the space count is positive, we
12866 emit the space characters first. */
12867 if (!(flags & _FLAG_MINUS) && space_cnt)
12868 {
12869 if (str_put_n_chars (handle, space_cnt, ' '))
12870 {
12871 FSerrno = CE_WRITE_ERROR;
12872 return EOF;
12873 }
12874 count += space_cnt;
12875 space_cnt = 0;
12876 }
12877 /* if we have a sign character to print, that comes
12878 next */
12879 if (sign_char)
12880 if (FSputc (sign_char, handle) == EOF)
12881 {
12882 FSerrno = CE_WRITE_ERROR;
12883 return EOF;
12884 }
12885 /* if we have a prefix (0b, 0B, 0x or 0X), that's next */
12886 if (prefix_cnt)
12887 {
12888 if (FSputc ('0', handle) == EOF)
12889 {
12890 FSerrno = CE_WRITE_ERROR;
12891 return EOF;
12892 }
12893 if (FSputc (c, handle) == EOF)
12894 {
12895 FSerrno = CE_WRITE_ERROR;
12896 return EOF;
12897 }
12898 }
12899 /* if we have leading zeros, they follow. the prefix, if any
12900 is included in the number of digits when determining how
12901 many leading zeroes are needed. */
12902 // if (precision > prefix_cnt)
12903 // precision -= prefix_cnt;
12904 if (str_put_n_chars (handle, precision, '0'))
12905 {
12906 FSerrno = CE_WRITE_ERROR;
12907 return EOF;
12908 }
12909 /* print the actual number */
12910 for (cval = *++q; cval; cval = *++q)
12911 if (FSputc (cval, handle) == EOF)
12912 {
12913 FSerrno = CE_WRITE_ERROR;
12914 return EOF;
12915 }
12916 /* if there are any spaces left, they go to right-pad
12917 the field */
12918 if (str_put_n_chars (handle, space_cnt, ' '))
12919 {
12920 FSerrno = CE_WRITE_ERROR;
12921 return EOF;
12922 }
12923
12924 count += precision + digit_cnt + space_cnt + prefix_cnt;
12925 }
12926 break;
12927 case 'n':
12928 switch (size)
12929 {
12930 case _FMT_LONG:
12931 *(long *) va_arg (ap, long *) = count;
12932 break;
12933 #ifdef __18CXX
12934 case _FMT_SHRTLONG:
12935 *(short long *) va_arg (ap, short long *) = count;
12936 break;
12937 #else
12938 case _FMT_LONGLONG:
12939 *(long long *) va_arg (ap, long long *) = count;
12940 break;
12941 #endif
12942 case _FMT_BYTE:
12943 *(signed char *) va_arg (ap, signed char *) = count;
12944 break;
12945 default:
12946 *(int *) va_arg (ap, int *) = count;
12947 break;
12948 }
12949 break;
12950 default:
12951 /* undefined behaviour. we do nothing */
12952 break;
12953 }
12954 }
12955 else
12956 {
12957 if (FSputc (c, handle) == EOF)
12958 {
12959 FSerrno = CE_WRITE_ERROR;
12960 return EOF;
12961 }
12962 ++count;
12963 }
12964 }
12965 return count;
12966 }
12967
12968
12969
12970 #endif
12971
12972
12973
12974
12975
|