Ventoy/LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/fat_write.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