diff --git a/src/boot.c b/src/boot.c index 474443e..ace6f88 100644 --- a/src/boot.c +++ b/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) diff --git a/src/check.c b/src/check.c index 870fcd9..2cbf7b0 100644 --- a/src/check.c +++ b/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; diff --git a/src/dosfsck.c b/src/dosfsck.c index 0a57030..c14fbcc 100644 --- a/src/dosfsck.c +++ b/src/dosfsck.c @@ -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(); diff --git a/src/dosfsck.h b/src/dosfsck.h index f62dfbd..689cc03 100644 --- a/src/dosfsck.h +++ b/src/dosfsck.h @@ -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; diff --git a/src/fat.c b/src/fat.c index 441138d..7b92301 100644 --- a/src/fat.c +++ b/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; diff --git a/src/fat.h b/src/fat.h index c5f7849..40bb6d0 100644 --- a/src/fat.h +++ b/src/fat.h @@ -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 diff --git a/src/file.c b/src/file.c index c389c60..c8f9ef5 100644 --- a/src/file.c +++ b/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; diff --git a/src/io.c b/src/io.c index 0ab0bbf..49d0196 100644 --- a/src/io.c +++ b/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; diff --git a/src/mkdosfs.c b/src/mkdosfs.c index 1264efd..89c5600 100644 --- a/src/mkdosfs.c +++ b/src/mkdosfs.c @@ -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