/** * @public * @brief Moves a file or directory from source to destination. * * @param pIoman The FF_IOMAN object pointer. * @param szSourceFile String of the source file to be moved or renamed. * @param szDestinationFile String of the destination file to where the source should be moved or renamed. * * @return FF_ERR_NONE on success. * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists. * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!). * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found. * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. * **/ FF_ERROR FF_Move(FF_IOMAN *pIoman, const FF_T_INT8 *szSourceFile, const FF_T_INT8 *szDestinationFile) { FF_ERROR Error; FF_FILE *pSrcFile, *pDestFile; FF_DIRENT MyFile; FF_T_UINT8 EntryBuffer[32]; FF_T_UINT16 i; FF_T_UINT32 DirCluster; if(!pIoman) { return FF_ERR_NULL_POINTER; } // Check destination file doesn't exist! pDestFile = FF_Open(pIoman, szDestinationFile, FF_MODE_READ, &Error); if(pDestFile || (Error == FF_ERR_FILE_OBJECT_IS_A_DIR)) { FF_Close(pDestFile); return FF_ERR_FILE_DESTINATION_EXISTS; // YES -- FAIL } pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_READ, &Error); if(Error == FF_ERR_FILE_OBJECT_IS_A_DIR) { // Open a directory for moving! pSrcFile = FF_Open(pIoman, szSourceFile, FF_MODE_DIR, &Error); } if(pSrcFile) { // Create the new dirent. FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); MyFile.Attrib = FF_getChar(EntryBuffer, (FF_T_UINT16)(FF_FAT_DIRENT_ATTRIB)); MyFile.Filesize = pSrcFile->Filesize; MyFile.ObjectCluster = pSrcFile->ObjectCluster; MyFile.CurrentItem = 0; i = (FF_T_UINT16) strlen(szDestinationFile); while(i != 0) { if(szDestinationFile[i] == '\\' || szDestinationFile[i] == '/') { break; } i--; } strncpy(MyFile.FileName, (szDestinationFile + i + 1), FF_MAX_FILENAME); if(i == 0) { i = 1; } DirCluster = FF_FindDir(pIoman, szDestinationFile, i); if(DirCluster) { // Destination Dir was found, we can now create the new entry. if(FF_CreateDirent(pIoman, DirCluster, &MyFile)) { FF_Close(pSrcFile); return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT; // FAILED } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { FF_RmLFNs(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry); FF_FetchEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pSrcFile->DirCluster, pSrcFile->DirEntry, EntryBuffer); } FF_unlockDIR(pIoman); FF_Close(pSrcFile); FF_FlushCache(pIoman); return FF_ERR_NONE; } return FF_ERR_FILE_DIR_NOT_FOUND; } return FF_ERR_FILE_SOURCE_NOT_FOUND; // Source not found! }
FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { FF_FILE *pFile; FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; FF_T_SINT8 RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif if(!pIoman) { return FF_ERR_NULL_POINTER; } pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error); if(!pFile) { return Error; // File in use or File not found! } pFile->FileDeleted = FF_TRUE; FF_lockDIR(pIoman); { if(FF_isDirEmpty(pIoman, path)) { FF_lockFAT(pIoman); { FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); // Edit the Directory Entry! (So it appears as deleted); FF_RmLFNs(pIoman, pFile->DirCluster, pFile->DirEntry); FF_FetchEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); EntryBuffer[0] = 0xE5; FF_PushEntry(pIoman, pFile->DirCluster, pFile->DirEntry, EntryBuffer); #ifdef FF_PATH_CACHE FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].DirCluster = 0; FF_ReleaseSemaphore(pIoman->pSemaphore); } } } FF_ReleaseSemaphore(pIoman->pSemaphore); #endif FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); FF_FlushCache(pIoman); } else { RetVal = FF_ERR_DIR_NOT_EMPTY; } } FF_unlockDIR(pIoman); FF_Close(pFile); // Free the file pointer resources // File is now lost! return RetVal; }
FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { #else FF_ERROR FF_RmFile(FF_IOMAN *pIoman, const FF_T_INT8 *path) { #endif FF_FILE *pFile; FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; FF_FETCH_CONTEXT FetchContext; pFile = FF_Open(pIoman, path, FF_MODE_READ, &Error); if(!pFile) { return Error; // File in use or File not found! } pFile->FileDeleted = FF_TRUE; if(pFile->ObjectCluster) { // Ensure there is actually a cluster chain to delete! FF_lockFAT(pIoman); // Lock the FAT so its thread-safe. { Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); if(Error) { FF_Close(pFile); return Error; } } // Edit the Directory Entry! (So it appears as deleted); FF_lockDIR(pIoman); { Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); if(Error) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } EntryBuffer[0] = 0xE5; Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } FF_CleanupEntryFetch(pIoman, &FetchContext); } FF_unlockDIR(pIoman); Error = FF_FlushCache(pIoman); if(Error) { FF_Close(pFile); return Error; } Error = FF_Close(pFile); // Free the file pointer resources return Error; }
FF_ERROR FF_FormatPartition(FF_IOMAN *pIoman, FF_T_UINT32 ulPartitionNumber, FF_T_UINT32 ulClusterSize) { FF_BUFFER *pBuffer; FF_T_SINT8 scPartitionCount; FF_T_UINT32 maxClusters, f16MaxClusters, f32MaxClusters; FF_T_UINT32 fatSize = 32; // Default to a fat32 format. FF_PARTITION_ENTRY partitionGeom; FF_T_UINT32 ulBPRLba; ///< The LBA of the boot partition record. FF_T_UINT32 fat32Size, fat16Size, newFat32Size, newFat16Size, finalFatSize; FF_T_UINT32 sectorsPerCluster = ulClusterSize / pIoman->BlkSize; FF_T_UINT32 ulReservedSectors, ulTotalSectors; FF_T_UINT32 ul32DataSectors, ul16DataSectors; FF_T_UINT32 i; FF_T_UINT32 ulClusterBeginLBA; FF_ERROR Error = FF_ERR_NONE; // Get Partition Metrics, and pass on to FF_Format() function pBuffer = FF_GetBuffer(pIoman, 0, FF_MODE_READ); { if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED | FF_FORMATPARTITION; } scPartitionCount = FF_PartitionCount(pBuffer->pBuffer); if(!scPartitionCount) { // Get Partition Geom from volume boot record. ulBPRLba = 0; partitionGeom.ulStartLBA = FF_getShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS); // Get offset to start of where we can actually put the FAT table. ulReservedSectors = partitionGeom.ulStartLBA; partitionGeom.ulLength = (FF_T_UINT32) FF_getShort(pBuffer->pBuffer, FF_FAT_16_TOTAL_SECTORS); if(partitionGeom.ulLength == 0) { // 32-bit entry was used. partitionGeom.ulLength = FF_getLong(pBuffer->pBuffer, FF_FAT_32_TOTAL_SECTORS); } ulTotalSectors = partitionGeom.ulLength; partitionGeom.ulLength -= partitionGeom.ulStartLBA; // Remove the reserved sectors from the count. } else { // Get partition Geom from the partition table entry. } // Calculate the max possiblenumber of clusters based on clustersize. maxClusters = partitionGeom.ulLength / sectorsPerCluster; // Determine the size of a FAT table required to support this. fat32Size = (maxClusters * 4) / pIoman->BlkSize; // Potential size in sectors of a fat32 table. if((maxClusters * 4) % pIoman->BlkSize) { fat32Size++; } fat32Size *= 2; // Officially there are 2 copies of the FAT. fat16Size = (maxClusters * 2) / pIoman->BlkSize; // Potential size in bytes of a fat16 table. if((maxClusters * 2) % pIoman->BlkSize) { fat16Size++; } fat16Size *= 2; // A real number of sectors to be available is therefore ~~ ul16DataSectors = partitionGeom.ulLength - fat16Size; ul32DataSectors = partitionGeom.ulLength - fat32Size; f16MaxClusters = ul16DataSectors / sectorsPerCluster; f32MaxClusters = ul32DataSectors / sectorsPerCluster; newFat16Size = (f16MaxClusters * 2) / pIoman->BlkSize; if((f16MaxClusters * 2) % pIoman->BlkSize) { newFat16Size++; } newFat32Size = (f32MaxClusters * 4) / pIoman->BlkSize; if((f32MaxClusters * 4) % pIoman->BlkSize) { newFat32Size++; } // Now determine if this should be fat16/32 format? if(f16MaxClusters < 65525) { fatSize = 16; finalFatSize = newFat16Size; } else { fatSize = 32; finalFatSize = newFat32Size; } FF_ReleaseBuffer(pIoman, pBuffer); for(i = 0; i < finalFatSize*2; i++) { // Ensure the FAT table is clear. if(i == 0) { pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA, FF_MODE_WR_ONLY); if(!pBuffer) { return FF_ERR_DEVICE_DRIVER_FAILED; } memset(pBuffer->pBuffer, 0, pIoman->BlkSize); } else { FF_BlockWrite(pIoman, partitionGeom.ulStartLBA+i, 1, pBuffer->pBuffer, FF_FALSE); } } switch(fatSize) { case 16: { FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); // First FAT entry. FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); // RESERVED alloc. break; } case 32: { FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); // FAT32 FAT sig. FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); // RESERVED alloc. FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. break; } default: break; } FF_ReleaseBuffer(pIoman, pBuffer); // Clear and initialise the root dir. ulClusterBeginLBA = partitionGeom.ulStartLBA + (finalFatSize*2); for(i = 0; i < sectorsPerCluster; i++) { if(i == 0) { pBuffer = FF_GetBuffer(pIoman, ulClusterBeginLBA, FF_MODE_WR_ONLY); memset(pBuffer->pBuffer, 0, pIoman->BlkSize); } else { FF_BlockWrite(pIoman, ulClusterBeginLBA+i, 1, pBuffer->pBuffer, FF_FALSE); } } FF_ReleaseBuffer(pIoman, pBuffer); // Correctly modify the second FAT item again. pBuffer = FF_GetBuffer(pIoman, partitionGeom.ulStartLBA + finalFatSize, FF_MODE_WRITE); { switch(fatSize) { case 16: { FF_putShort(pBuffer->pBuffer, 0, 0xFFF8); FF_putShort(pBuffer->pBuffer, 2, 0xFFFF); break; } case 32: FF_putLong(pBuffer->pBuffer, 0, 0x0FFFFFF8); FF_putLong(pBuffer->pBuffer, 4, 0xFFFFFFFF); FF_putLong(pBuffer->pBuffer, 8, 0x0FFFFFFF); // Root dir allocation. } } FF_ReleaseBuffer(pIoman, pBuffer); // Modify the fields in the VBR/PBR for correct mounting. pBuffer = FF_GetBuffer(pIoman, ulBPRLba, FF_MODE_WRITE); // Modify the FAT descriptions. { // -- First section Common vars to Fat12/16 and 32. memset(pBuffer->pBuffer, 0, pIoman->BlkSize); // Clear the boot record. FF_putChar(pBuffer->pBuffer, 0, 0xEB); // Place the Jump to bootstrap x86 instruction. FF_putChar(pBuffer->pBuffer, 1, 0x3C); // Even though we won't populate the bootstrap code. FF_putChar(pBuffer->pBuffer, 2, 0x90); // Some devices look for this as a signature. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+3), "FULLFAT2", 8); // Place the FullFAT OEM code. FF_putShort(pBuffer->pBuffer, 11, pIoman->BlkSize); FF_putChar(pBuffer->pBuffer, 13, (FF_T_UINT8) sectorsPerCluster); FF_putShort(pBuffer->pBuffer, FF_FAT_RESERVED_SECTORS, (FF_T_UINT16)partitionGeom.ulStartLBA); // Number of reserved sectors. (1 for fat12/16, 32 for f32). FF_putShort(pBuffer->pBuffer, FF_FAT_NUMBER_OF_FATS, 2); // Always 2 copies. //FF_putShort(pBuffer->pBuffer, 19, 0); // Number of sectors in partition if size < 32mb. FF_putChar(pBuffer->pBuffer, 21, 0xF8); // Media type -- HDD. FF_putShort(pBuffer->pBuffer, 510, 0xAA55); // MBR sig. FF_putLong(pBuffer->pBuffer, 32, partitionGeom.ulLength+partitionGeom.ulStartLBA); // Total sectors of this partition. if(fatSize == 32) { FF_putShort(pBuffer->pBuffer, 36, (FF_T_UINT16)finalFatSize); // Number of sectors per fat. FF_putShort(pBuffer->pBuffer, 44, 2); // Root dir cluster (2). FF_putShort(pBuffer->pBuffer, 48, 1); // FSINFO sector at LBA1. FF_putShort(pBuffer->pBuffer, 50, 6); // 0 for no backup boot sector. FF_putChar(pBuffer->pBuffer, 66, 0x29); // Indicate extended signature is present. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+71), "FullFAT2-V", 10); // Volume name. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+81), "FAT32 ", 8); // Put backup boot sector. FF_BlockWrite(pIoman, 6, 1, pBuffer->pBuffer, FF_FALSE); } else { FF_putChar(pBuffer->pBuffer, 38, 0x28); // Signal this contains an extended signature. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+43), "FullFAT2-V", 10); // Volume name. memcpy(((FF_T_UINT8 *)pBuffer->pBuffer+54), "FAT16 ", 8); FF_putShort(pBuffer->pBuffer, FF_FAT_16_SECTORS_PER_FAT, (FF_T_UINT16) finalFatSize); FF_putShort(pBuffer->pBuffer, 17, 512); // Number of Dir entries. (FAT32 0). //FF_putShort(pBuffer->pBuffer, FF_FAT_ROOT_ENTRY_COUNT, } } } FF_ReleaseBuffer(pIoman, pBuffer); if(fatSize == 32) { // Finally if FAT32, create an FSINFO sector. pBuffer = FF_GetBuffer(pIoman, 1, FF_MODE_WRITE); { memset(pBuffer->pBuffer, 0, pIoman->BlkSize); FF_putLong(pBuffer->pBuffer, 0, 0x41615252); // FSINFO sect magic number. FF_putLong(pBuffer->pBuffer, 484, 0x61417272); // FSINFO second sig. // Calculate total sectors, -1 for the root dir allocation. (Free sectors count). FF_putLong(pBuffer->pBuffer, 488, ((ulTotalSectors - (ulReservedSectors + (2*finalFatSize))) / sectorsPerCluster)-1); FF_putLong(pBuffer->pBuffer, 492, 2); // Hint for next free cluster. FF_putShort(pBuffer->pBuffer, 510, 0xAA55); } FF_ReleaseBuffer(pIoman, pBuffer); } FF_FlushCache(pIoman); return Error; }
FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_WCHAR *path, FF_T_UINT8 Mode, FF_ERROR *pError) { #else FF_FILE *FF_Open(FF_IOMAN *pIoman, const FF_T_INT8 *path, FF_T_UINT8 Mode, FF_ERROR *pError) { #endif FF_FILE *pFile; FF_FILE *pFileChain; FF_DIRENT Object; FF_T_UINT32 DirCluster, FileCluster; FF_T_UINT32 nBytesPerCluster; #ifdef FF_UNICODE_SUPPORT FF_T_WCHAR filename[FF_MAX_FILENAME]; #else FF_T_INT8 filename[FF_MAX_FILENAME]; #endif FF_ERROR Error; FF_T_UINT16 i; if(pError) { *pError = 0; } if(!pIoman) { if(pError) { *pError = FF_ERR_NULL_POINTER; } return (FF_FILE *)NULL; } pFile = FF_MALLOC(sizeof(FF_FILE)); if(!pFile) { if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY; } return (FF_FILE *)NULL; } // Get the Mode Bits. pFile->Mode = Mode; #ifdef FF_UNICODE_SUPPORT i = (FF_T_UINT16) wcslen(path); #else i = (FF_T_UINT16) strlen(path); #endif while(i != 0) { if(path[i] == '\\' || path[i] == '/') { break; } i--; } #ifdef FF_UNICODE_SUPPORT wcsncpy(filename, (path + i + 1), FF_MAX_FILENAME); #else strncpy(filename, (path + i + 1), FF_MAX_FILENAME); #endif if(i == 0) { i = 1; } DirCluster = FF_FindDir(pIoman, path, i, &Error); if(Error) { if(pError) { *pError = Error; } FF_FREE(pFile); return (FF_FILE *) NULL; } if(DirCluster) { FileCluster = FF_FindEntryInDir(pIoman, DirCluster, filename, 0x00, &Object, &Error); if(Error) { if(pError) { *pError = Error; } FF_FREE(pFile); return (FF_FILE *) NULL; } if(!FileCluster) { // If 0 was returned, it might be because the file has no allocated cluster #ifdef FF_UNICODE_SUPPORT if(wcslen(filename) == wcslen(Object.FileName)) { if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) wcslen(filename)) == FF_TRUE) { #else if(strlen(filename) == strlen(Object.FileName)) { if(Object.Filesize == 0 && FF_strmatch(filename, Object.FileName, (FF_T_UINT16) strlen(filename)) == FF_TRUE) { #endif // The file really was found! FileCluster = 1; } } } if(!FileCluster) { if((pFile->Mode & FF_MODE_CREATE)) { FileCluster = FF_CreateFile(pIoman, DirCluster, filename, &Object, &Error); if(Error) { if(pError) { *pError = Error; } FF_FREE(pFile); return (FF_FILE *) NULL; } Object.CurrentItem += 1; } } if(FileCluster) { if(Object.Attrib == FF_FAT_ATTR_DIR) { if(!(pFile->Mode & FF_MODE_DIR)) { // Not the object, File Not Found! FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_OBJECT_IS_A_DIR; } return (FF_FILE *) NULL; } } //---------- Ensure Read-Only files don't get opened for Writing. if((pFile->Mode & FF_MODE_WRITE) || (pFile->Mode & FF_MODE_APPEND)) { if((Object.Attrib & FF_FAT_ATTR_READONLY)) { FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_IS_READ_ONLY; } return (FF_FILE *) NULL; } } pFile->pIoman = pIoman; pFile->FilePointer = 0; pFile->ObjectCluster = Object.ObjectCluster; pFile->Filesize = Object.Filesize; pFile->CurrentCluster = 0; pFile->AddrCurrentCluster = pFile->ObjectCluster; //pFile->Mode = Mode; pFile->Next = NULL; pFile->DirCluster = DirCluster; pFile->DirEntry = Object.CurrentItem - 1; nBytesPerCluster = pFile->pIoman->pPartition->SectorsPerCluster / pIoman->BlkSize; pFile->iChainLength = 0; pFile->iEndOfChain = 0; pFile->FileDeleted = FF_FALSE; // File Permission Processing // Only "w" and "w+" mode strings can erase a file's contents. // Any other combinations will not cause an erase. if((pFile->Mode & FF_MODE_TRUNCATE)) { pFile->Filesize = 0; pFile->FilePointer = 0; } /* Add pFile onto the end of our linked list of FF_FILE objects. */ FF_PendSemaphore(pIoman->pSemaphore); { if(!pIoman->FirstFile) { pIoman->FirstFile = pFile; } else { pFileChain = (FF_FILE *) pIoman->FirstFile; do { if(pFileChain->ObjectCluster == pFile->ObjectCluster) { // File is already open! DON'T ALLOW IT! FF_ReleaseSemaphore(pIoman->pSemaphore); FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_ALREADY_OPEN; } return (FF_FILE *) NULL; } if(!pFileChain->Next) { pFileChain->Next = pFile; break; } pFileChain = (FF_FILE *) pFileChain->Next; }while(pFileChain != NULL); } } FF_ReleaseSemaphore(pIoman->pSemaphore); return pFile; }else { FF_FREE(pFile); if(pError) { *pError = FF_ERR_FILE_NOT_FOUND; } return (FF_FILE *) NULL; } } if(pError) { *pError = FF_ERR_FILE_INVALID_PATH; } FF_FREE(pFile); return (FF_FILE *)NULL; } /** * @public * @brief Tests if a Directory contains any other files or folders. * * @param pIoman FF_IOMAN object returned from the FF_CreateIOMAN() function. * **/ #ifdef FF_UNICODE_SUPPORT FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_WCHAR *Path) { #else FF_T_BOOL FF_isDirEmpty(FF_IOMAN *pIoman, const FF_T_INT8 *Path) { #endif FF_DIRENT MyDir; FF_ERROR RetVal = FF_ERR_NONE; FF_T_UINT8 i = 0; if(!pIoman) { return FF_FALSE; } RetVal = FF_FindFirst(pIoman, &MyDir, Path); while(RetVal == 0) { i++; RetVal = FF_FindNext(pIoman, &MyDir); if(i > 2) { return FF_FALSE; } } return FF_TRUE; } #ifdef FF_UNICODE_SUPPORT FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_WCHAR *path) { #else FF_ERROR FF_RmDir(FF_IOMAN *pIoman, const FF_T_INT8 *path) { #endif FF_FILE *pFile; FF_ERROR Error = FF_ERR_NONE; FF_T_UINT8 EntryBuffer[32]; FF_FETCH_CONTEXT FetchContext; FF_T_SINT8 RetVal = FF_ERR_NONE; #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif if(!pIoman) { return FF_ERR_NULL_POINTER; } pFile = FF_Open(pIoman, path, FF_MODE_DIR, &Error); if(!pFile) { return Error; // File in use or File not found! } pFile->FileDeleted = FF_TRUE; FF_lockDIR(pIoman); { if(FF_isDirEmpty(pIoman, path)) { FF_lockFAT(pIoman); { Error = FF_UnlinkClusterChain(pIoman, pFile->ObjectCluster, 0); // 0 to delete the entire chain! } FF_unlockFAT(pIoman); if(Error) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } // Initialise the dirent Fetch Context object for faster removal of dirents. Error = FF_InitEntryFetch(pIoman, pFile->DirCluster, &FetchContext); if(Error) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } // Edit the Directory Entry! (So it appears as deleted); Error = FF_RmLFNs(pIoman, pFile->DirEntry, &FetchContext); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } Error = FF_FetchEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } EntryBuffer[0] = 0xE5; Error = FF_PushEntryWithContext(pIoman, pFile->DirEntry, &FetchContext, EntryBuffer); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } #ifdef FF_PATH_CACHE FF_PendSemaphore(pIoman->pSemaphore); // Thread safety on shared object! { for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { #ifdef FF_UNICODE_SUPPORT if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)wcslen(path))) { #else if(FF_strmatch(pIoman->pPartition->PathCache[i].Path, path, (FF_T_UINT16)strlen(path))) { #endif pIoman->pPartition->PathCache[i].Path[0] = '\0'; pIoman->pPartition->PathCache[i].DirCluster = 0; FF_ReleaseSemaphore(pIoman->pSemaphore); } } } FF_ReleaseSemaphore(pIoman->pSemaphore); #endif Error = FF_IncreaseFreeClusters(pIoman, pFile->iChainLength); if(Error) { FF_CleanupEntryFetch(pIoman, &FetchContext); FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } FF_CleanupEntryFetch(pIoman, &FetchContext); Error = FF_FlushCache(pIoman); if(Error) { FF_unlockDIR(pIoman); FF_Close(pFile); return Error; } } else { RetVal = FF_ERR_DIR_NOT_EMPTY; } } FF_unlockDIR(pIoman); Error = FF_Close(pFile); // Free the file pointer resources if(Error) { return Error; } // File is now lost! return RetVal; }