File: C:\M91449\Perso\RTWdsPIC\Developpements\Forum\resodad_john\myFolder\SDtroubleshooting\..\Microchip\MDD File System\FSIO.c1 /****************************************************************************** 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 |