//************************************************************************************* // Function: CETYPE FS_CreateFile ( const char * FileName, // FILE_MODE mode, // FSFILE* filePtr ) // Summary: Creates/Opens a file with ascii name provided in FileName // Input: // FileName - The name of the file to open // mode - File open mode (FILE_MODE enum) // - FS_CREATE_NEW - Create a new file or replace an existing file. // - FS_OPEN_EXISTING - Open existing file for read/write access or // creates a new file; file is positioned at the // beginning. // - FS_APPEND - Open existing file for read/write access or // creates a new file; file is positioned just // past the last byte. // - FS_READ_ONLY - Open existing file in read-only mode; file // positioned at the beginning. // filePtr - pointer to FSFILE data structure that will be confi- // gured ro provide access to the file if function // succeeds. // Return Values: // CETYPE - Expected CE_GOOD, but may have other codes depending on // various error conditions. // Description: // This function will create and/or open specified file. // The specified file name will be formatted to ensure that it's in 8.3 // format. Next, the search for the specified file name will be // performed. If the name is found, the action will be taken based // upon the requested File Mode. //************************************************************************************* CETYPE FS_CreateFile ( const char* FileName, FILE_MODE mode, FSFILE* filePtr ) { //---------------------------------------------------------------- // Validate conditions and parameters //---------------------------------------------------------------- if (!SDFS_InitStatus) return CE_NOT_INIT; // FS is not initialized! if (NULL == FileName) return CE_INVALID_ARGUMENT; if (NULL == filePtr) return CE_INVALID_ARGUMENT; //----------------------------------------------------------------- CETYPE RC = CE_GOOD; char fmtName[NAME_SIZE_8r3]; //----------------------------------------------------------------- // Validate new name and convert it to 8.3 FAT format //----------------------------------------------------------------- if ( !SDFS_Format8dot3Name(FileName, fmtName, FALSE) ) return CE_INVALID_FILENAME; //================================================================ // Make sure that the name provided is unique... //---------------------------------------------------------------- FS_SeekStart(&SDFS_CWD); // Rewind Current Working Directory RC = SDFS_DirFindNext(&SDFS_CWD, filePtr, ATTR_NONE, ATTR_NONE, fmtName); //---------------------------------------------------------------- if (CE_EOF == RC) // There is no object with the same name goto NotFound; //---------------------------------------------------------------- if (CE_GOOD != RC) // Some other error (except for CE_EOF) had happened... return RC; //---------------------------------------------------------------- if ( FS_IsDirectory(filePtr) ) // The object found is a Directory... { SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return CE_FILENAME_EXISTS; } //---------------------------------------------------------------- //================================================================ // The file with the specified name present on the disk... //---------------------------------------------------------------- switch(mode) { case FS_CREATE_NEW: // File exists, we want to create a new one, so remove it first if ( CE_GOOD != (RC = FS_Delete(filePtr)) ) // Delete failed... { SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return RC; } //----------------------------------------- // Nope, does not exist any more :) goto NotFound; case FS_APPEND: // File exists, we want to position it at the end if ( CE_GOOD != (RC = FS_SeekEnd(filePtr)) ) // Seek failed... { SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return RC; } //----------------------------------------- // Everything is fine! return CE_GOOD; case FS_READ_ONLY: // Set READONLY attribute on the FO data structure to prevent WRITEs filePtr->dirFileEntry.DIR_Attr |= ATTR_READONLY; // Fall-through to OPEN_EXISTING case FS_OPEN_EXISTING: FS_SeekStart(filePtr); return CE_GOOD; default: SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return CE_INVALID_ARGUMENT; } //================================================================ // The file with the specified name does not exist on disk... //---------------------------------------------------------------- NotFound: switch(mode) { case FS_CREATE_NEW: case FS_APPEND: case FS_OPEN_EXISTING: // For all of the cases above proceed to creating new file break; case FS_READ_ONLY: // Bad luck... SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return CE_NOT_FOUND; default: SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return CE_INVALID_ARGUMENT; } //================================================================ // Now it is time to create a new file //---------------------------------------------------------------- // First, try to create Directory Entry //---------------------------------------------------------------- if ( (RC = SDFS_DirFindEmpty(&SDFS_CWD, filePtr)) != CE_GOOD) return RC; // Could not create directory entry... //---------------------------------------------------------------- // Second, allocate a cluster to the file //---------------------------------------------------------------- if ( CE_GOOD != (RC = SDFS_ClusterAllocateNew(filePtr)) ) { SDFS_InitFSFILE(filePtr, NULL, ATTR_NONE); // Reset output FSFILE structure return RC; } //---------------------------------------------------------------- // Third, set the name and Attributes of the new entry //---------------------------------------------------------------- memcpy(filePtr->dirFileEntry.DIR_Name, fmtName, NAME_SIZE_8r3); filePtr->dirFileEntry.DIR_Attr = ATTR_ARCHIVE; //---------------------------------------------------------------- // That's basically it - just need to save changes to disk //---------------------------------------------------------------- return FS_Flush(filePtr); }
//********************************************************************************* // Function: CETYPE FS_Write(FSFILE* filePtr, const void* origin, WORD length) // Summary: Write data to a file // Conditions: File opened in FS_CREATE_NEW, FS_APPEND, or FS_OPEN_EXISTING mode // Input: // filePtr - Pointer to file structure // origin - Pointer to source buffer // length - Length of the source buffer (data to write) // Return: // CETYPE - Error code (expected: CE_GOOD) // Description: // The FS_Write function will write data to a file. First, the sector // that corresponds to the current position in the file will be loaded // (if it hasn't already been cached in the global data buffer). Data // will then be written to the device from the specified buffer until // the specified amount has been written. // If the end of a cluster is reached, the next cluster will be // loaded, unless the end-of-file flag for the specified file has been // set. If it has, a new cluster will be allocated to the file. Finally, // the new position and filesize will be stored in the FSFILE object. //********************************************************************************* CETYPE FS_Write(FSFILE* filePtr, const void* origin, WORD length ) { //---------------------------------------------------------------- // Validate conditions and parameters //---------------------------------------------------------------- if (!SDFS_InitStatus) return CE_NOT_INIT; // FS is not initialized! if (NULL == filePtr) return CE_INVALID_ARGUMENT; //---------------------------------------------------------------- // Check if the file attributes allow write if( (filePtr->dirFileEntry.DIR_Attr & ATTR_READONLY) == ATTR_READONLY ) return CE_READONLY; // Check if pointer is valid if (origin == NULL) return CE_INVALID_ARGUMENT; // Check if length is valid if (length == 0) return CE_INVALID_ARGUMENT; //----------------------------------------------------------------- DWORD LBA; BYTE* ptrFrom = (BYTE*)origin; WORD ChunkSize; CETYPE RC; // Write data to the file //{ //------------------------------------------------------------ // Loop while writing bytes, exit loop if: // * All bytes are written // * Error encountered //------------------------------------------------------------ while (length > 0) { //---------------------------------------------------- // Make sure we have defined a place to write to //---------------------------------------------------- //{ if (filePtr->fileCrntSecPos == SDFS_VolumeInfo.sectorSize) { //---------------------------------------------------- // Current sector is filled in... //---------------------------------------------------- // NOTE: fileCrntSec is a 0-based counter (index) //---------------------------------------------------- if (filePtr->fileCrntSec == SDFS_VolumeInfo.SecPerClus - 1) { //---------------------------------------------------- // Current cluster is exhausted - move to the next one //---------------------------------------------------- RC = SDFS_ClusterGetNext(filePtr); if ( CE_EOF == RC ) // Oops! Reached end-of-file - try to add another cluster RC = SDFS_ClusterAllocateNew(filePtr); //---------------------------------------------------- if ( CE_GOOD != RC ) // Bad luck - no cluster to advance to! return RC; } else { // It is safe to move to the next sector in the current cluster filePtr->fileCrntSec++; // move to the next sector filePtr->fileCrntSecPos = 0; // reset position } //---------------------------------------------------- } //} //----------------------------------------------------------------- LBA = SDFS_FATClusterToLBA( filePtr->fileCrntCls) + filePtr->fileCrntSec; // add the sector number to it ChunkSize = length <= SDFS_VolumeInfo.sectorSize - filePtr->fileCrntSecPos ? length : SDFS_VolumeInfo.sectorSize - filePtr->fileCrntSecPos; //----------------------------------------------------------------- if (CE_GOOD != (RC = SDFS_DataCacheWrite (LBA, ptrFrom, filePtr->fileCrntSecPos, ChunkSize ))) return RC; //----------------------------------------------------------------- length -= ChunkSize; ptrFrom += ChunkSize; //---------------------- filePtr->fileCrntSecPos += ChunkSize; filePtr->fileSeek += ChunkSize; if (filePtr->dirFileEntry.DIR_FileSize < filePtr->fileSeek) filePtr->dirFileEntry.DIR_FileSize = filePtr->fileSeek; } //----------------------------------- return CE_GOOD; } // write
//********************************************************************************* // Function: CETYPE FS_WriteSector(FSFILE* filePtr, const void* origin) // Summary: Write data to a file one sector at a time bypassing CACHE // Conditions: File opened in FS_CREATE_NEW, FS_APPEND, or FS_OPEN_EXISTING mode // Input: // filePtr - Pointer to file structure // origin - Pointer to source buffer // Return: // CETYPE - Error code (expected: CE_GOOD) // Description: // The FS_WriteSector function will write data to a file one sector // at a time bypassing CACHE. The length of the data buffer pointed // to by "orogin" expected to be equal to the size of the sector. // If the end of a cluster is reached, the next cluster will be // loaded, unless the end-of-file flag for the specified file has been // set. If it has, a new cluster will be allocated to the file. Finally, // the new position and filesize will be stored in the FSFILE object. //********************************************************************************* CETYPE FS_WriteSector(FSFILE* filePtr, const void* origin) { //---------------------------------------------------------------- // Validate conditions and parameters //---------------------------------------------------------------- if (!SDFS_InitStatus) return CE_NOT_INIT; // FS is not initialized! if (NULL == filePtr) return CE_INVALID_ARGUMENT; //---------------------------------------------------------------- // Check if the file attributes allow write if( (filePtr->dirFileEntry.DIR_Attr & ATTR_READONLY) == ATTR_READONLY ) return CE_READONLY; // Check if pointer is valid if (origin == NULL) return CE_INVALID_ARGUMENT; //----------------------------------------------------------------- DWORD LBA; BYTE* ptrFrom = (BYTE*)origin; WORD ChunkSize; CETYPE RC; //---------------------------------------------------- // Make sure we have defined a place to write to //---------------------------------------------------- if (0 != filePtr->fileCrntSecPos) // For Sector writes we always start at the EMPTY // sector, so the rest of the current sector will // be skipped... { // NOTE: fileCrntSec is a 0-based counter (index) //---------------------------------------------------- if (filePtr->fileCrntSec == SDFS_VolumeInfo.SecPerClus - 1) { //---------------------------------------------------- // Current cluster is exhausted - move to the next one //---------------------------------------------------- RC = SDFS_ClusterGetNext(filePtr); if ( CE_EOF == RC ) // Oops! Reached end-of-file - try to add another cluster RC = SDFS_ClusterAllocateNew(filePtr); //---------------------------------------------------- if ( CE_GOOD != RC ) // Bad luck - no cluster to advance to! return RC; } else { // It is safe to move to the next sector in the current cluster filePtr->fileCrntSec++; // move to the next sector filePtr->fileCrntSecPos = 0; // reset position } } //----------------------------------------------------------------- LBA = SDFS_FATClusterToLBA( filePtr->fileCrntCls) + filePtr->fileCrntSec; // add the sector number to it ChunkSize = SDFS_VolumeInfo.sectorSize; //----------------------------------------------------------------- if ( !SD_SPI_SectorWrite(LBA, ptrFrom, FALSE) ) return CE_WRITE_ERROR; //----------------------------------------------------------------- filePtr->fileCrntSecPos += ChunkSize; filePtr->fileSeek += ChunkSize; if (filePtr->dirFileEntry.DIR_FileSize < filePtr->fileSeek) filePtr->dirFileEntry.DIR_FileSize = filePtr->fileSeek; //----------------------------------- return CE_GOOD; } // write
//************************************************************************************* // Function: CETYPE FS_mkDir (char * Name, ATTR_TYPE Attr, FSFILE* newDir) //------------------------------------------------------------------------------------- // Summary: Creates directory with the specified name in the current working // directory. // Input: // Name - Name of the new directory // Attr - Additional attributes of the new directory // newDir - pointer to the File Object structure that on SUCCESS // will be set to the newly created directory. // Return Values: // CETYPE enum member (expected CE_GOOD) // Other codes depending on encountered error conditions //************************************************************************************* CETYPE FS_mkDir (char * Name, ATTR_TYPE Attr, FSFILE* newDir) { //---------------------------------------------------------------- // Validate conditions and parameters //---------------------------------------------------------------- if (!SDFS_InitStatus) return CE_NOT_INIT; // FS is not initialized! if (NULL == Name) return CE_INVALID_FILENAME; if (NULL == newDir) return CE_INVALID_ARGUMENT; //---------------------------------------------------------------- char fmtName[NAME_SIZE_8r3]; CETYPE RC; //---------------------------------------------------------------- // Verify/Format provided Directory name (for direct match) //---------------------------------------------------------------- if ( !SDFS_Format8dot3Name (Name, fmtName, FALSE) ) return CE_INVALID_FILENAME; // Invalid/missing name //---------------------------------------------------------------- // Make sure that the name provided is unique... //---------------------------------------------------------------- FS_SeekStart(&SDFS_CWD); // Rewind Current Working Directory RC = SDFS_DirFindNext(&SDFS_CWD, newDir, ATTR_NONE, ATTR_NONE, fmtName); //---------------------------------------------------------------- if (CE_GOOD == RC) { if ( FS_IsDirectory(newDir) ) // Directory with the same name is found... return CE_GOOD; else // There exists file with the same name... { SDFS_InitFSFILE(newDir, NULL, ATTR_NONE); // Reset output FSFILE structure return CE_FILENAME_EXISTS; } } if (CE_EOF != RC) return RC; // Some other error happend on the way... //---------------------------------------------------------------- // The name provided is unique; Try to create Directory Entry //---------------------------------------------------------------- if ( (RC = SDFS_DirFindEmpty(&SDFS_CWD, newDir)) != CE_GOOD) return RC; // Could not create directory entry... //---------------------------------------------------------------- // Success; Set the name and Attributes of the new entry //---------------------------------------------------------------- memcpy(newDir->dirFileEntry.DIR_Name, fmtName, NAME_SIZE_8r3); newDir->dirFileEntry.DIR_Attr = ATTR_DIRECTORY | ATTR_ARCHIVE; //---------------------------------------------------------------- // Allocate a cluster for the new Directory and create mandatory // "." and ".." entries //---------------------------------------------------------------- if ( (RC = SDFS_ClusterAllocateNew(newDir)) != CE_GOOD) // Failure allocating cluster... { SDFS_InitFSFILE(newDir, NULL, ATTR_NONE); // Reset output FSFILE structure return RC; } //---------------------------------------------------------------- DIRENTRY spcDir; DWORD dirCluster; // Set template Directory record for "." and ".." entries SDFS_DirResetEntry( &spcDir, NULL, ATTR_DIRECTORY); //---------------------------------------------------------------- // Create and store "." entry //---------------------------------------------------------------- spcDir.DIR_Name[0] = '.'; dirCluster = SDFS_DirGetFirstCluster(&newDir->dirFileEntry); SDFS_DirSetFirstCluster (&spcDir, dirCluster); FS_Write(newDir, &spcDir, sizeof(DIRENTRY)); //---------------------------------------------------------------- // Create and store ".." entry //---------------------------------------------------------------- spcDir.DIR_Name[1] = '.'; dirCluster = SDFS_DirGetFirstCluster(&SDFS_CWD.dirFileEntry); if (dirCluster == SDFS_VolumeInfo.rootClsN) // Parent is the Root directory of the volume dirCluster = 0; // FAT32 rule for pointers to Root SDFS_DirSetFirstCluster (&spcDir, dirCluster); FS_Write(newDir, &spcDir, sizeof(DIRENTRY)); //---------------------------------------------------------------- return FS_Flush(newDir); }