//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // FAT16/32 File IO Library // V2.6 // Ultra-Embedded.com // Copyright 2003 - 2012 // // Email: admin@ultra-embedded.com // // License: GPL // If you would like a version with a more permissive license for use in // closed source commercial applications please contact me for details. //----------------------------------------------------------------------------- // // This file is part of FAT File IO Library. // // FAT File IO Library is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // FAT File IO Library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with FAT File IO Library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #include "../imports.h" #include "fat_defs.h" #include "fat_access.h" #include "fat_table.h" #include "fat_write.h" #include "fat_string.h" #include "fat_misc.h" #if FATFS_INC_WRITE_SUPPORT //----------------------------------------------------------------------------- // fatfs_add_free_space: Allocate another cluster of free space to the end // of a files cluster chain. //----------------------------------------------------------------------------- int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters) { uint32 i; uint32 nextcluster; uint32 start = *startCluster; // Set the next free cluster hint to unknown if (fs->next_free_cluster != FAT32_LAST_CLUSTER) fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER); for (i=0;irootdir_first_cluster, &nextcluster)) { // Point last to this fatfs_fat_set_cluster(fs, start, nextcluster); // Point this to end of file fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER); // Adjust argument reference start = nextcluster; if (i == 0) *startCluster = nextcluster; } else return 0; } return 1; } //----------------------------------------------------------------------------- // fatfs_allocate_free_space: Add an ammount of free space to a file either from // 'startCluster' if newFile = false, or allocating a new start to the chain if // newFile = true. //----------------------------------------------------------------------------- int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size) { uint32 clusterSize; uint32 clusterCount; uint32 nextcluster; if (size==0) return 0; // Set the next free cluster hint to unknown if (fs->next_free_cluster != FAT32_LAST_CLUSTER) fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER); // Work out size and clusters clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE; clusterCount = (size / clusterSize); // If any left over if (size-(clusterSize*clusterCount)) clusterCount++; // Allocated first link in the chain if a new file if (newFile) { if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster)) return 0; // If this is all that is needed then all done if (clusterCount==1) { fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER); *startCluster = nextcluster; return 1; } } // Allocate from end of current chain (startCluster is end of chain) else nextcluster = *startCluster; if (!fatfs_add_free_space(fs, &nextcluster, clusterCount)) return 0; return 1; } //----------------------------------------------------------------------------- // fatfs_find_free_dir_offset: Find a free space in the directory for a new entry // which takes up 'entryCount' blocks (or allocate some more) //----------------------------------------------------------------------------- static int fatfs_find_free_dir_offset(struct fatfs *fs, uint32 dirCluster, int entryCount, uint32 *pSector, uint8 *pOffset) { struct fat_dir_entry *directoryEntry; uint8 item=0; uint16 recordoffset = 0; uint8 i=0; int x=0; int possible_spaces = 0; int start_recorded = 0; // No entries required? if (entryCount == 0) return 0; // Main cluster following loop while (1) { // Read sector if (fatfs_sector_reader(fs, dirCluster, x++, 0)) { // Analyse Sector for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) { // Create the multiplier for sector access recordoffset = FAT_DIR_ENTRY_SIZE * item; // Overlay directory entry over buffer directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset); // LFN Entry if (fatfs_entry_lfn_text(directoryEntry)) { // First entry? if (possible_spaces == 0) { // Store start *pSector = x-1; *pOffset = item; start_recorded = 1; } // Increment the count in-case the file turns // out to be deleted... possible_spaces++; } // SFN Entry else { // Has file been deleted? if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED) { // First entry? if (possible_spaces == 0) { // Store start *pSector = x-1; *pOffset = item; start_recorded = 1; } possible_spaces++; // We have found enough space? if (possible_spaces >= entryCount) return 1; // Else continue counting until we find a valid entry! } // Is the file entry empty? else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK) { // First entry? if (possible_spaces == 0) { // Store start *pSector = x-1; *pOffset = item; start_recorded = 1; } // Increment the blank entries count possible_spaces++; // We have found enough space? if (possible_spaces >= entryCount) return 1; } // File entry is valid else { // Reset all flags possible_spaces = 0; start_recorded = 0; } } } // End of for } // End of if // Run out of free space in the directory, allocate some more else { uint32 newCluster; // Get a new cluster for directory if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &newCluster)) return 0; // Add cluster to end of directory tree if (!fatfs_fat_add_cluster_to_chain(fs, dirCluster, newCluster)) return 0; // Erase new directory cluster memset(fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE); for (i=0;isectors_per_cluster;i++) { if (!fatfs_write_sector(fs, newCluster, i, 0)) return 0; } // If non of the name fitted on previous sectors if (!start_recorded) { // Store start *pSector = (x-1); *pOffset = 0; start_recorded = 1; } return 1; } } // End of while loop return 0; } //----------------------------------------------------------------------------- // fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset //----------------------------------------------------------------------------- int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir) { uint8 item=0; uint16 recordoffset = 0; uint8 i=0; uint32 x=0; int entryCount; struct fat_dir_entry shortEntry; int dirtySector = 0; uint32 dirSector = 0; uint8 dirOffset = 0; int foundEnd = 0; uint8 checksum; uint8 *pSname; // No write access? if (!fs->disk_io.write_media) return 0; #if FATFS_INC_LFN_SUPPORT // How many LFN entries are required? // NOTE: We always request one LFN even if it would fit in a SFN! entryCount = fatfs_lfn_entries_required(filename); if (!entryCount) return 0; #else entryCount = 0; #endif // Find space in the directory for this filename (or allocate some more) // NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported). if (!fatfs_find_free_dir_offset(fs, dirCluster, entryCount + 1, &dirSector, &dirOffset)) return 0; // Generate checksum of short filename pSname = (uint8*)shortfilename; checksum = 0; for (i=11; i!=0; i--) checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++; // Start from current sector where space was found! x = dirSector; // Main cluster following loop while (1) { // Read sector if (fatfs_sector_reader(fs, dirCluster, x++, 0)) { // Analyse Sector for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++) { // Create the multiplier for sector access recordoffset = FAT_DIR_ENTRY_SIZE * item; // If the start position for the entry has been found if (foundEnd==0) if ( (dirSector==(x-1)) && (dirOffset==item) ) foundEnd = 1; // Start adding filename if (foundEnd) { if (entryCount==0) { // Short filename fatfs_sfn_create_entry(shortfilename, size, startCluster, &shortEntry, dir); #if FATFS_INC_TIME_DATE_SUPPORT // Update create, access & modify time & date fatfs_update_timestamps(&shortEntry, 1, 1, 1); #endif memcpy(&fs->currentsector.sector[recordoffset], &shortEntry, sizeof(shortEntry)); // Writeback return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1); } #if FATFS_INC_LFN_SUPPORT else { entryCount--; // Copy entry to directory buffer fatfs_filename_to_lfn(filename, &fs->currentsector.sector[recordoffset], entryCount, checksum); dirtySector = 1; } #endif } } // End of if // Write back to disk before loading another sector if (dirtySector) { if (!fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1)) return 0; dirtySector = 0; } } else return 0; } // End of while loop return 0; } #endif