mirror of https://github.com/ventoy/Ventoy.git
374 lines
13 KiB
C
374 lines
13 KiB
C
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
// 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 <string.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;i<clusters;i++)
|
|
{
|
|
// Start looking for free clusters from the beginning
|
|
if (fatfs_find_blank_cluster(fs, fs->rootdir_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;i<fs->sectors_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
|