Adding support for limited-memory embedded systems.
This patch reorganizes heap memory usage by dosfsck and mkdosfs to support limited-memory embedded systems - in particular, those based on Xilinx's Microblaze processor. It also adds a few comments. Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
This commit is contained in:
parent
89f0b727b5
commit
ff1b24e91d
11
src/boot.c
11
src/boot.c
@ -57,7 +57,8 @@ static struct {
|
||||
{ 0xff, "5.25\" 320k floppy 2s/40tr/8sec" },
|
||||
};
|
||||
|
||||
#if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ || defined __ppc64__ || defined __bfin__
|
||||
#if defined __alpha || defined __ia64__ || defined __s390x__ || defined __x86_64__ \
|
||||
|| defined __ppc64__ || defined __bfin__ || defined __MICROBLAZE__
|
||||
/* Unaligned fields must first be copied byte-wise */
|
||||
#define GET_UNALIGNED_W(f) \
|
||||
({ \
|
||||
@ -300,6 +301,14 @@ void read_boot(DOS_FS *fs)
|
||||
fs_read(0,sizeof(b),&b);
|
||||
logical_sector_size = GET_UNALIGNED_W(b.sector_size);
|
||||
if (!logical_sector_size) die("Logical sector size is zero.");
|
||||
|
||||
/* This was moved up because it's the first thing that will fail */
|
||||
/* if the platform needs special handling of unaligned multibyte accesses */
|
||||
/* but such handling isn't being provided. See GET_UNALIGNED_W() above. */
|
||||
if (logical_sector_size & (SECTOR_SIZE-1))
|
||||
die("Logical sector size (%d bytes) is not a multiple of the physical "
|
||||
"sector size.",logical_sector_size);
|
||||
|
||||
fs->cluster_size = b.cluster_size*logical_sector_size;
|
||||
if (!fs->cluster_size) die("Cluster size is zero.");
|
||||
if (b.fats != 2 && b.fats != 1)
|
||||
|
||||
92
src/check.c
92
src/check.c
@ -111,8 +111,11 @@ loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern)
|
||||
if (!prev)
|
||||
die("Root directory has no cluster allocated!");
|
||||
for (clu_num = prev+1; clu_num != prev; clu_num++) {
|
||||
FAT_ENTRY entry;
|
||||
|
||||
if (clu_num >= fs->clusters+2) clu_num = 2;
|
||||
if (!fs->fat[clu_num].value)
|
||||
get_fat(&entry, fs->fat, clu_num, fs);
|
||||
if (!entry.value)
|
||||
break;
|
||||
}
|
||||
if (clu_num == prev)
|
||||
@ -183,15 +186,27 @@ loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a full path (starting with '/') for the specified dentry,
|
||||
* relative to the partition. All components are "long" names where possible.
|
||||
*
|
||||
* @param[in] file Information about dentry (file or directory) of interest
|
||||
*
|
||||
* return Pointer to static string containing file's full path
|
||||
*/
|
||||
static char *path_name(DOS_FILE *file)
|
||||
{
|
||||
static char path[PATH_MAX*2];
|
||||
|
||||
if (!file) *path = 0;
|
||||
if (!file) *path = 0; /* Reached the root directory */
|
||||
else {
|
||||
if (strlen(path_name(file->parent)) > PATH_MAX)
|
||||
die("Path name too long.");
|
||||
if (strcmp(path,"/") != 0) strcat(path,"/");
|
||||
|
||||
/* Append the long name to the path,
|
||||
* or the short name if there isn't a long one
|
||||
*/
|
||||
strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name));
|
||||
}
|
||||
return path;
|
||||
@ -461,9 +476,12 @@ static int check_file(DOS_FS *fs,DOS_FILE *file)
|
||||
clusters = prev = 0;
|
||||
for (curr = FSTART(file,fs) ? FSTART(file,fs) :
|
||||
-1; curr != -1; curr = next_cluster(fs,curr)) {
|
||||
if (!fs->fat[curr].value || bad_cluster(fs,curr)) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, curr, fs);
|
||||
|
||||
if (!curEntry.value || bad_cluster(fs,curr)) {
|
||||
printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n",
|
||||
path_name(file),fs->fat[curr].value ? "bad" : "free",curr);
|
||||
path_name(file), curEntry.value ? "bad" : "free",curr);
|
||||
if (prev) set_fat(fs,prev,-1);
|
||||
else if (!file->offset)
|
||||
die( "FAT32 root dir starts with a bad cluster!" );
|
||||
@ -690,6 +708,15 @@ static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check a dentry's cluster chain for bad clusters.
|
||||
* If requested, we verify readability and mark unreadable clusters as bad.
|
||||
*
|
||||
* @param[inout] fs Information about the filesystem
|
||||
* @param[in] file dentry to check
|
||||
* @param[in] read_test Nonzero == verify that dentry's clusters can
|
||||
* be read
|
||||
*/
|
||||
static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
|
||||
{
|
||||
DOS_FILE *owner;
|
||||
@ -699,6 +726,11 @@ static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
|
||||
for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
|
||||
walk = next_clu) {
|
||||
next_clu = next_cluster(fs,walk);
|
||||
|
||||
/* In this stage we are checking only for a loop within our own
|
||||
* cluster chain.
|
||||
* Cross-linking of clusters is handled in check_file()
|
||||
*/
|
||||
if ((owner = get_owner(fs,walk))) {
|
||||
if (owner == file) {
|
||||
printf("%s\n Circular cluster chain. Truncating to %lu "
|
||||
@ -727,6 +759,7 @@ static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
|
||||
}
|
||||
set_owner(fs,walk,file);
|
||||
}
|
||||
/* Revert ownership (for now) */
|
||||
for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
|
||||
walk = next_cluster(fs,walk))
|
||||
if (bad_cluster(fs,walk)) break;
|
||||
@ -742,11 +775,21 @@ static void undelete(DOS_FS *fs,DOS_FILE *file)
|
||||
clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/
|
||||
fs->cluster_size;
|
||||
prev = 0;
|
||||
for (walk = FSTART(file,fs); left && walk >= 2 && walk <
|
||||
fs->clusters+2 && !fs->fat[walk].value; walk++) {
|
||||
|
||||
walk = FSTART(file,fs);
|
||||
|
||||
while (left && (walk >= 2) && (walk < fs->clusters+2)) {
|
||||
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, walk, fs);
|
||||
|
||||
if (!curEntry.value)
|
||||
break;
|
||||
|
||||
left--;
|
||||
if (prev) set_fat(fs,prev,walk);
|
||||
prev = walk;
|
||||
walk++;
|
||||
}
|
||||
if (prev) set_fat(fs,prev,-1);
|
||||
else MODIFY_START(file,0,fs);
|
||||
@ -763,6 +806,19 @@ static void new_dir( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a description for a referenced dentry and insert it in our dentry
|
||||
* tree. Then, go check the dentry's cluster chain for bad clusters and
|
||||
* cluster loops.
|
||||
*
|
||||
* @param[inout] fs Information about the filesystem
|
||||
* @param[out] chain
|
||||
* @param[in] parent Information about parent directory of this file
|
||||
* NULL == no parent ('file' is root directory)
|
||||
* @param[in] offset Partition-relative byte offset of directory entry of interest
|
||||
* 0 == Root directory
|
||||
* @param cp
|
||||
*/
|
||||
static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
|
||||
loff_t offset,FDSC **cp)
|
||||
{
|
||||
@ -773,6 +829,7 @@ static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
|
||||
if (offset)
|
||||
fs_read(offset,sizeof(DIR_ENT),&de);
|
||||
else {
|
||||
/* Construct a DIR_ENT for the root directory */
|
||||
memcpy(de.name," ",MSDOS_NAME);
|
||||
de.attr = ATTR_DIR;
|
||||
de.size = de.time = de.date = 0;
|
||||
@ -805,14 +862,15 @@ static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
|
||||
if (list) {
|
||||
printf("Checking file %s",path_name(new));
|
||||
if (new->lfn)
|
||||
printf(" (%s)", file_name(new->dir_ent.name) );
|
||||
printf(" (%s)", file_name(new->dir_ent.name) ); /* (8.3) */
|
||||
printf("\n");
|
||||
}
|
||||
/* Don't include root directory, '.', or '..' in the total file count */
|
||||
if (offset &&
|
||||
strncmp(de.name,MSDOS_DOT,MSDOS_NAME) != 0 &&
|
||||
strncmp(de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0)
|
||||
++n_files;
|
||||
test_file(fs,new,test);
|
||||
test_file(fs,new,test); /* Bad cluster check */
|
||||
}
|
||||
|
||||
|
||||
@ -844,6 +902,16 @@ static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively scan subdirectories of the specified parent directory.
|
||||
*
|
||||
* @param[inout] fs Information about the filesystem
|
||||
* @param[in] parent Identifies the directory to scan
|
||||
* @param[in] cp
|
||||
*
|
||||
* @return 0 Success
|
||||
* @return 1 Error
|
||||
*/
|
||||
static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)
|
||||
{
|
||||
DOS_FILE *walk;
|
||||
@ -857,6 +925,14 @@ static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan all directory and file information for errors.
|
||||
*
|
||||
* @param[inout] fs Information about the filesystem
|
||||
*
|
||||
* @return 0 Success
|
||||
* @return 1 Error
|
||||
*/
|
||||
int scan_root(DOS_FS *fs)
|
||||
{
|
||||
DOS_FILE **chain;
|
||||
|
||||
@ -106,6 +106,7 @@ int main(int argc,char **argv)
|
||||
unsigned n_files_check=0, n_files_verify=0;
|
||||
unsigned long free_clusters;
|
||||
|
||||
memset(&fs, 0, sizeof(fs));
|
||||
rw = salvage_files = verify = 0;
|
||||
interactive = 1;
|
||||
check_atari();
|
||||
|
||||
@ -163,8 +163,6 @@ typedef struct _dos_file {
|
||||
typedef struct {
|
||||
unsigned long value;
|
||||
unsigned long reserved;
|
||||
DOS_FILE *owner;
|
||||
int prev; /* number of previous clusters */
|
||||
} FAT_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
@ -182,7 +180,8 @@ typedef struct {
|
||||
loff_t fsinfo_start; /* 0 if not present */
|
||||
long free_clusters;
|
||||
loff_t backupboot_start; /* 0 if not present */
|
||||
FAT_ENTRY *fat;
|
||||
unsigned char *fat;
|
||||
DOS_FILE **cluster_owner;
|
||||
char *label;
|
||||
} DOS_FS;
|
||||
|
||||
|
||||
216
src/fat.c
216
src/fat.c
@ -36,7 +36,15 @@
|
||||
#include "fat.h"
|
||||
|
||||
|
||||
static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)
|
||||
/**
|
||||
* Fetch the FAT entry for a specified cluster.
|
||||
*
|
||||
* @param[out] entry Cluster to which cluster of interest is linked
|
||||
* @param[in] fat FAT table for the partition
|
||||
* @param[in] cluster Cluster of interest
|
||||
* @param[in] fs Information from the FAT boot sectors (bits per FAT entry)
|
||||
*/
|
||||
void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
|
||||
@ -61,18 +69,33 @@ static void get_fat(FAT_ENTRY *entry,void *fat,unsigned long cluster,DOS_FS *fs)
|
||||
default:
|
||||
die("Bad FAT entry size: %d bits.",fs->fat_bits);
|
||||
}
|
||||
entry->owner = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a bookkeeping structure from the partition's FAT table.
|
||||
* If the partition has multiple FATs and they don't agree, try to pick a winner,
|
||||
* and queue a command to overwrite the loser.
|
||||
* One error that is fixed here is a cluster that links to something out of range.
|
||||
*
|
||||
* @param[inout] fs Information about the filesystem
|
||||
*/
|
||||
void read_fat(DOS_FS *fs)
|
||||
{
|
||||
int eff_size;
|
||||
unsigned long i;
|
||||
void *first,*second = NULL;
|
||||
int first_ok,second_ok;
|
||||
unsigned long total_num_clusters;
|
||||
|
||||
eff_size = ((fs->clusters+2ULL)*fs->fat_bits+7)/8ULL;
|
||||
/* Clean up from previous pass */
|
||||
free(fs->fat);
|
||||
free(fs->cluster_owner);
|
||||
fs->fat = NULL;
|
||||
fs->cluster_owner = NULL;
|
||||
|
||||
total_num_clusters = fs->clusters + 2UL;
|
||||
eff_size = (total_num_clusters*fs->fat_bits+7)/8ULL;
|
||||
first = alloc(eff_size);
|
||||
fs_read(fs->fat_start,eff_size,first);
|
||||
if (fs->nfats > 1) {
|
||||
@ -119,22 +142,37 @@ void read_fat(DOS_FS *fs)
|
||||
if (second) {
|
||||
free(second);
|
||||
}
|
||||
fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2ULL));
|
||||
for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],first,i,fs);
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (fs->fat[i].value >= fs->clusters+2 &&
|
||||
(fs->fat[i].value < FAT_MIN_BAD(fs))) {
|
||||
fs->fat = (unsigned char*) first;
|
||||
|
||||
fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *));
|
||||
memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *)));
|
||||
|
||||
/* Truncate any cluster chains that link to something out of range */
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
if (curEntry.value >= fs->clusters+2 &&
|
||||
(curEntry.value < FAT_MIN_BAD(fs))) {
|
||||
printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
|
||||
i-2,fs->fat[i].value,fs->clusters+2-1);
|
||||
i-2, curEntry.value, fs->clusters+2-1);
|
||||
set_fat(fs,i,-1);
|
||||
}
|
||||
free(first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the FAT entry for a specified cluster
|
||||
* (i.e., change the cluster it links to).
|
||||
* Queue a command to write out this change.
|
||||
*
|
||||
* @param[in,out] fs Information about the filesystem
|
||||
* @param[in] cluster Cluster to change
|
||||
* @param[in] new Cluster to link to
|
||||
*/
|
||||
void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new)
|
||||
{
|
||||
unsigned char data[4];
|
||||
unsigned char *data = NULL;
|
||||
int size;
|
||||
loff_t offs;
|
||||
|
||||
@ -144,53 +182,80 @@ void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new)
|
||||
new = FAT_BAD(fs);
|
||||
switch( fs->fat_bits ) {
|
||||
case 12:
|
||||
data = fs->fat + cluster*3/2;
|
||||
offs = fs->fat_start+cluster*3/2;
|
||||
if (cluster & 1) {
|
||||
data[0] = ((new & 0xf) << 4) | (fs->fat[cluster-1].value >> 8);
|
||||
FAT_ENTRY prevEntry;
|
||||
get_fat(&prevEntry, fs->fat, cluster-1, fs);
|
||||
data[0] = ((new & 0xf) << 4) | (prevEntry.value >> 8);
|
||||
data[1] = new >> 4;
|
||||
}
|
||||
else {
|
||||
FAT_ENTRY subseqEntry;
|
||||
get_fat(&subseqEntry, fs->fat, cluster+1, fs);
|
||||
data[0] = new & 0xff;
|
||||
data[1] = (new >> 8) | (cluster == fs->clusters-1 ? 0 :
|
||||
(0xff & fs->fat[cluster+1].value) << 4);
|
||||
(0xff & subseqEntry.value) << 4);
|
||||
}
|
||||
size = 2;
|
||||
break;
|
||||
case 16:
|
||||
data = fs->fat + cluster*2;
|
||||
offs = fs->fat_start+cluster*2;
|
||||
*(unsigned short *) data = CT_LE_W(new);
|
||||
size = 2;
|
||||
break;
|
||||
case 32:
|
||||
offs = fs->fat_start+cluster*4;
|
||||
/* According to M$, the high 4 bits of a FAT32 entry are reserved and
|
||||
* are not part of the cluster number. So we never touch them. */
|
||||
*(unsigned long *) data = CT_LE_L( (new & 0xfffffff) |
|
||||
(fs->fat[cluster].reserved << 28) );
|
||||
size = 4;
|
||||
{
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, cluster, fs);
|
||||
|
||||
data = fs->fat + cluster*4;
|
||||
offs = fs->fat_start+cluster*4;
|
||||
/* According to M$, the high 4 bits of a FAT32 entry are reserved and
|
||||
* are not part of the cluster number. So we never touch them. */
|
||||
*(unsigned long *) data = CT_LE_L( (new & 0xfffffff) |
|
||||
(curEntry.reserved << 28) );
|
||||
size = 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
die("Bad FAT entry size: %d bits.",fs->fat_bits);
|
||||
}
|
||||
fs->fat[cluster].value = new;
|
||||
fs_write(offs,size,&data);
|
||||
fs_write(offs,size,data);
|
||||
if (fs->nfats > 1) {
|
||||
fs_write(offs+fs->fat_size,size,&data);
|
||||
fs_write(offs+fs->fat_size,size,data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int bad_cluster(DOS_FS *fs,unsigned long cluster)
|
||||
{
|
||||
return FAT_IS_BAD(fs,fs->fat[cluster].value);
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, cluster, fs);
|
||||
|
||||
return FAT_IS_BAD(fs, curEntry.value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the cluster to which the specified cluster is linked.
|
||||
* If the linked cluster is marked bad, abort.
|
||||
*
|
||||
* @param[in] fs Information about the filesystem
|
||||
* @param[in] cluster Cluster to follow
|
||||
*
|
||||
* @return -1 'cluster' is at the end of the chain
|
||||
* @return Other values Next cluster in this chain
|
||||
*/
|
||||
unsigned long next_cluster(DOS_FS *fs,unsigned long cluster)
|
||||
{
|
||||
unsigned long value;
|
||||
FAT_ENTRY curEntry;
|
||||
|
||||
value = fs->fat[cluster].value;
|
||||
get_fat(&curEntry, fs->fat, cluster, fs);
|
||||
|
||||
value = curEntry.value;
|
||||
if (FAT_IS_BAD(fs,value))
|
||||
die("Internal error: next_cluster on bad cluster");
|
||||
return FAT_IS_EOF(fs,value) ? -1 : value;
|
||||
@ -203,17 +268,32 @@ loff_t cluster_start(DOS_FS *fs,unsigned long cluster)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update internal bookkeeping to show that the specified cluster belongs
|
||||
* to the specified dentry.
|
||||
*
|
||||
* @param[in,out] fs Information about the filesystem
|
||||
* @param[in] cluster Cluster being assigned
|
||||
* @param[in] owner Information on dentry that owns this cluster
|
||||
* (may be NULL)
|
||||
*/
|
||||
void set_owner(DOS_FS *fs,unsigned long cluster,DOS_FILE *owner)
|
||||
{
|
||||
if (owner && fs->fat[cluster].owner)
|
||||
if (fs->cluster_owner == NULL)
|
||||
die("Internal error: attempt to set owner in non-existent table");
|
||||
|
||||
if (owner && fs->cluster_owner[cluster] && (fs->cluster_owner[cluster] != owner))
|
||||
die("Internal error: attempt to change file owner");
|
||||
fs->fat[cluster].owner = owner;
|
||||
fs->cluster_owner[cluster] = owner;
|
||||
}
|
||||
|
||||
|
||||
DOS_FILE *get_owner(DOS_FS *fs,unsigned long cluster)
|
||||
{
|
||||
return fs->fat[cluster].owner;
|
||||
if (fs->cluster_owner == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return fs->cluster_owner[cluster];
|
||||
}
|
||||
|
||||
|
||||
@ -223,12 +303,16 @@ void fix_bad(DOS_FS *fs)
|
||||
|
||||
if (verbose)
|
||||
printf("Checking for bad clusters.\n");
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
if (!get_owner(fs,i) && !FAT_IS_BAD(fs, curEntry.value))
|
||||
if (!fs_test(cluster_start(fs,i),fs->cluster_size)) {
|
||||
printf("Cluster %lu is unreadable.\n",i);
|
||||
set_fat(fs,i,-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -240,27 +324,35 @@ void reclaim_free(DOS_FS *fs)
|
||||
if (verbose)
|
||||
printf("Checking for unused clusters.\n");
|
||||
reclaimed = 0;
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (!get_owner(fs,i) && fs->fat[i].value &&
|
||||
!FAT_IS_BAD(fs,fs->fat[i].value)) {
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
if (!get_owner(fs,i) && curEntry.value &&
|
||||
!FAT_IS_BAD(fs, curEntry.value)) {
|
||||
set_fat(fs,i,0);
|
||||
reclaimed++;
|
||||
}
|
||||
}
|
||||
if (reclaimed)
|
||||
printf("Reclaimed %d unused cluster%s (%llu bytes).\n",reclaimed,
|
||||
reclaimed == 1 ? "" : "s",(unsigned long long)reclaimed*fs->cluster_size);
|
||||
}
|
||||
|
||||
|
||||
static void tag_free(DOS_FS *fs,DOS_FILE *ptr)
|
||||
static void tag_free(DOS_FS *fs,DOS_FILE *ptr,
|
||||
const unsigned long *prev_cluster)
|
||||
{
|
||||
DOS_FILE *owner;
|
||||
int prev;
|
||||
unsigned long i,walk;
|
||||
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
|
||||
!get_owner(fs,i) && !fs->fat[i].prev) {
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
|
||||
!get_owner(fs,i) && !prev_cluster[i]) {
|
||||
prev = 0;
|
||||
for (walk = i; walk > 0 && walk != -1;
|
||||
walk = next_cluster(fs,walk)) {
|
||||
@ -274,6 +366,7 @@ static void tag_free(DOS_FS *fs,DOS_FILE *ptr)
|
||||
prev = walk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -282,36 +375,53 @@ void reclaim_file(DOS_FS *fs)
|
||||
DOS_FILE dummy;
|
||||
int reclaimed,files,changed;
|
||||
unsigned long i,next,walk;
|
||||
unsigned long *prev_cluster = NULL;
|
||||
unsigned long total_num_clusters;
|
||||
|
||||
if (verbose)
|
||||
printf("Reclaiming unconnected clusters.\n");
|
||||
for (i = 2; i < fs->clusters+2; i++) fs->fat[i].prev = 0;
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
next = fs->fat[i].value;
|
||||
|
||||
total_num_clusters = fs->clusters + 2UL;
|
||||
prev_cluster = alloc(total_num_clusters * sizeof(unsigned long));
|
||||
memset(prev_cluster, 0, (total_num_clusters * sizeof(unsigned long)));
|
||||
|
||||
for (i = 2; i < total_num_clusters; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
next = curEntry.value;
|
||||
if (!get_owner(fs,i) && next && next < fs->clusters+2) {
|
||||
if (get_owner(fs,next) || !fs->fat[next].value ||
|
||||
FAT_IS_BAD(fs,fs->fat[next].value)) set_fat(fs,i,-1);
|
||||
else fs->fat[next].prev++;
|
||||
FAT_ENTRY nextEntry;
|
||||
get_fat(&nextEntry, fs->fat, next, fs);
|
||||
|
||||
if (get_owner(fs,next) || !nextEntry.value ||
|
||||
FAT_IS_BAD(fs, nextEntry.value)) set_fat(fs,i,-1);
|
||||
else
|
||||
prev_cluster[next]++;
|
||||
}
|
||||
}
|
||||
do {
|
||||
tag_free(fs,&dummy);
|
||||
tag_free(fs,&dummy, prev_cluster);
|
||||
changed = 0;
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (fs->fat[i].value && !FAT_IS_BAD(fs,fs->fat[i].value) &&
|
||||
for (i = 2; i < total_num_clusters; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) &&
|
||||
!get_owner(fs, i)) {
|
||||
if (!fs->fat[fs->fat[i].value].prev--)
|
||||
if (!prev_cluster[curEntry.value]--)
|
||||
die("Internal error: prev going below zero");
|
||||
set_fat(fs,i,-1);
|
||||
changed = 1;
|
||||
printf("Broke cycle at cluster %lu in free chain.\n",i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (changed);
|
||||
files = reclaimed = 0;
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (get_owner(fs,i) == &dummy && !fs->fat[i].prev) {
|
||||
for (i = 2; i < total_num_clusters; i++)
|
||||
if (get_owner(fs,i) == &dummy && !prev_cluster[i]) {
|
||||
DIR_ENT de;
|
||||
loff_t offset;
|
||||
files++;
|
||||
@ -330,6 +440,8 @@ void reclaim_file(DOS_FS *fs)
|
||||
printf("Reclaimed %d unused cluster%s (%llu bytes) in %d chain%s.\n",
|
||||
reclaimed,reclaimed == 1 ? "" : "s",(unsigned long long)reclaimed*fs->cluster_size,files,
|
||||
files == 1 ? "" : "s");
|
||||
|
||||
free(prev_cluster);
|
||||
}
|
||||
|
||||
|
||||
@ -339,9 +451,13 @@ unsigned long update_free(DOS_FS *fs)
|
||||
unsigned long free = 0;
|
||||
int do_set = 0;
|
||||
|
||||
for (i = 2; i < fs->clusters+2; i++)
|
||||
if (!get_owner(fs,i) && !FAT_IS_BAD(fs,fs->fat[i].value))
|
||||
for (i = 2; i < fs->clusters+2; i++) {
|
||||
FAT_ENTRY curEntry;
|
||||
get_fat(&curEntry, fs->fat, i, fs);
|
||||
|
||||
if (!get_owner(fs,i) && !FAT_IS_BAD(fs, curEntry.value))
|
||||
++free;
|
||||
}
|
||||
|
||||
if (!fs->fsinfo_start)
|
||||
return free;
|
||||
|
||||
@ -28,6 +28,10 @@ void read_fat(DOS_FS *fs);
|
||||
/* Loads the FAT of the file system described by FS. Initializes the FAT,
|
||||
replaces broken FATs and rejects invalid cluster entries. */
|
||||
|
||||
void get_fat(FAT_ENTRY *entry, void *fat, unsigned long cluster, DOS_FS *fs);
|
||||
|
||||
/* Retrieve the FAT entry (next chained cluster) for CLUSTER. */
|
||||
|
||||
void set_fat(DOS_FS *fs,unsigned long cluster,unsigned long new);
|
||||
|
||||
/* Changes the value of the CLUSTERth cluster of the FAT of FS to NEW. Special
|
||||
|
||||
10
src/file.c
10
src/file.c
@ -57,6 +57,14 @@ static void put_char(char **p,unsigned char c)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct the "pretty-printed" representation of the name in a short directory entry.
|
||||
*
|
||||
* @param[in] fixed Pointer to name[0] of a DIR_ENT
|
||||
*
|
||||
* @return Pointer to static string containing pretty "8.3" equivalent of the
|
||||
* name in the directory entry.
|
||||
*/
|
||||
char *file_name(unsigned char *fixed)
|
||||
{
|
||||
static char path[MSDOS_NAME*4+2];
|
||||
@ -204,6 +212,8 @@ static FDSC **file_find(FDSC **dir,char *fixed)
|
||||
}
|
||||
|
||||
|
||||
/* Returns the attribute of the file FIXED in directory CURR or FDT_NONE if no
|
||||
such file exists or if CURR is NULL. */
|
||||
FD_TYPE file_type(FDSC **curr,char *fixed)
|
||||
{
|
||||
FDSC **this;
|
||||
|
||||
9
src/io.c
9
src/io.c
@ -103,6 +103,15 @@ void fs_open(char *path,int rw)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read data from the partition, accounting for any pending updates that are
|
||||
* queued for writing.
|
||||
*
|
||||
* @param[in] pos Byte offset, relative to the beginning of the partition,
|
||||
* at which to read
|
||||
* @param[in] size Number of bytes to read
|
||||
* @param[out] data Where to put the data read
|
||||
*/
|
||||
void fs_read(loff_t pos,int size,void *data)
|
||||
{
|
||||
CHANGE *walk;
|
||||
|
||||
@ -302,6 +302,7 @@ static struct msdos_boot_sector bs; /* Boot sector data */
|
||||
static int start_data_sector; /* Sector number for the start of the data area */
|
||||
static int start_data_block; /* Block number for the start of the data area */
|
||||
static unsigned char *fat; /* File allocation table */
|
||||
static unsigned alloced_fat_length; /* # of FAT sectors we can keep in memory */
|
||||
static unsigned char *info_sector; /* FAT32 info sector */
|
||||
static struct msdos_dir_entry *root_dir; /* Root directory */
|
||||
static int size_root_dir; /* Size of the root directory in bytes */
|
||||
@ -309,7 +310,7 @@ static int sectors_per_cluster = 0; /* Number of sectors per disk cluster */
|
||||
static int root_dir_entries = 0; /* Number of root directory entries */
|
||||
static char *blank_sector; /* Blank sector - all zeros */
|
||||
static int hidden_sectors = 0; /* Number of hidden sectors */
|
||||
|
||||
static int malloc_entire_fat = FALSE; /* Whether we should malloc() the entire FAT or not */
|
||||
|
||||
/* Function prototype definitions */
|
||||
|
||||
@ -1219,10 +1220,15 @@ setup_tables (void)
|
||||
|
||||
/* Make the file allocation tables! */
|
||||
|
||||
if ((fat = (unsigned char *) malloc (fat_length * sector_size)) == NULL)
|
||||
if (malloc_entire_fat)
|
||||
alloced_fat_length = fat_length;
|
||||
else
|
||||
alloced_fat_length = 1;
|
||||
|
||||
if ((fat = (unsigned char *) malloc (alloced_fat_length * sector_size)) == NULL)
|
||||
die ("unable to allocate space for FAT image in memory");
|
||||
|
||||
memset( fat, 0, fat_length * sector_size );
|
||||
memset( fat, 0, alloced_fat_length * sector_size );
|
||||
|
||||
mark_FAT_cluster (0, 0xffffffff); /* Initial fat entries */
|
||||
mark_FAT_cluster (1, 0xffffffff);
|
||||
@ -1352,8 +1358,13 @@ write_tables (void)
|
||||
}
|
||||
/* seek to start of FATS and write them all */
|
||||
seekto( reserved_sectors*sector_size, "first FAT" );
|
||||
for (x = 1; x <= nr_fats; x++)
|
||||
writebuf( fat, fat_length * sector_size, "FAT" );
|
||||
for (x = 1; x <= nr_fats; x++) {
|
||||
int y;
|
||||
int blank_fat_length = fat_length - alloced_fat_length;
|
||||
writebuf( fat, alloced_fat_length * sector_size, "FAT" );
|
||||
for (y=0; y<blank_fat_length; y++)
|
||||
writebuf( blank_sector, sector_size, "FAT" );
|
||||
}
|
||||
/* Write the root directory directly after the last FAT. This is the root
|
||||
* dir area on FAT12/16, and the first cluster on FAT32. */
|
||||
writebuf( (char *) root_dir, size_root_dir, "root directory" );
|
||||
@ -1456,6 +1467,7 @@ main (int argc, char **argv)
|
||||
|
||||
case 'c': /* c : Check FS as we build it */
|
||||
check = TRUE;
|
||||
malloc_entire_fat = TRUE; /* Need to be able to mark clusters bad */
|
||||
break;
|
||||
|
||||
case 'C': /* C : Create a new file */
|
||||
@ -1505,6 +1517,7 @@ main (int argc, char **argv)
|
||||
|
||||
case 'l': /* l : Bad block filename */
|
||||
listfile = optarg;
|
||||
malloc_entire_fat = TRUE; /* Need to be able to mark clusters bad */
|
||||
break;
|
||||
|
||||
case 'm': /* m : Set boot message */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user