File System Assignment

Copyright Tristan Aubrey-Jones and Dale Caffull December 2006.

myfs.c

home Home   up Up   ( Download )


/* COMP2009 File System Assignment * Tristan Aubrey-Jones (taj105) and Dale Caffull (dc1005) * ---------------------------------------------------------- * This code implements the methods myfs_read_file, myfs_write_file and * myfs_delete_file and requires myfs_write_sector and myfs_read_sector. * It provides a single directoried file system for a 1.44MB floppy disk * with 2880 sectors of 512B each. Max file size: 1458176B (1.39MB) * * Features: * * - The file system uses a block size of 4 sectors * which limits disk fragmentation but means that the disk has a maximum capacity of 712 files. * * - The file system contains two FAT-16 tables with a adler-32 checksums so that if one becomes corrupted * it is restored on the next file read or write. * * - The FAT is cached between subsequent file read, write and delete calls. On a call the first * sector of the FAT is read and it's checksum is compared to the cached FAT's version. * If the cache's checksum matches the disk's the cache is used, otherwise the rest of the FAT * is read, and its checksum is computed and checked to ensure that the FAT is valid. * * - The directory information is stored in a 26 sector hashtable so that on average only 1 sector must be * read to find a file's information. * * - Files are allocated optimally by finding all free space in the FAT, sorting by descending "gap" size and * selecting the smallest gap that will fit the file. If the file is too big for one gap, the * largest gap is used and the smallest gap is found that will fit the rest and so on. * Before writing the file these block ranges are sorted by ascending LBA (using quick sort), * so that reads and writes are sequential. */ #include "myfs.h" #define MYFS_BLANK_DISK (-6) #define MYFS_FAT_CORRUPT (-7) #define SECTOR_SIZE 512 #define BLOCK_SIZE 4 #define HOUSEKEEPING_SIZE 8 #define DISK_SIZE 720 #define FAT_SIZE 1440 #define FILENAME_LENGTH 11 #define FILES_PER_SECTOR 30 #define MAX_FILES (DISK_SIZE - HOUSEKEEPING_SIZE) #define FREE_SPACE 00 #define EOF 01 #define FALSE 0 #define TRUE !0 typedef char BYTE; typedef unsigned short int LBA; typedef unsigned char BOOL; /* stores the information for a single transfer * of a block either writing to disk from data, or * reading from disk into data. */ struct BLOCK_TRANSFER { LBA lba; /* starting lba of transfer */ BYTE *data; /* pointer to array of at least length B */ int length; /* length of data to read and write in B */ }; /* global variables */ static struct BLOCK_TRANSFER block_list[DISK_SIZE]; /* stores a list of blocks in memory */ /* caches last read FAT */ static BOOL formatted = FALSE; static BOOL fat_needsrestore = FALSE; /* fat needs to be restored from FAT-2 */ static BYTE fat_buffer[3 * SECTOR_SIZE]; /* stores a fat in memory */ /* caches last read sector from filetable */ static BYTE filetable_buffer[SECTOR_SIZE]; static LBA filetable_buffer_sector; /* copies count bytes from src to dest */ static void *memcpy(void* dest, const void* src, unsigned int length) { /* local variables */ unsigned int c; char *dst8, *src8; double *dst64, *src64; /* copy 1B at a time */ dst8 = (char *)dest; src8 = (char *)src; c = length % sizeof(double); while (c--) { *dst8++ = *src8++; } /* copy 8B at a time */ dst64 = (double *)dst8; src64 = (double *)src8; c = length - (length % sizeof(double)); while (c) { *dst64++ = *src64++; c -= sizeof(double); } return dest; } /* checks if two arrays are equal */ static int equals(const void *a, const void *b, int length) { /* local variables */ int c; char *a8, *b8; int *a32, *b32; /* check byte by byte */ c = length % sizeof(int); a8 = (char *)a; b8 = (char *)b; while (c--) { if (*a8++ != *b8++) return 0; } /* check 4B at a time */ c = length - (length % sizeof(int)); a32 = (int *)a8; b32 = (int *)b8; while (c) { if (*a32++ != *b32++) return 0; c -= sizeof(int); } /* arrays are equal */ return 1; } /* computes an adler-32 checksum of a byte array */ static int checksum(BYTE *arr, unsigned int length) { int r; unsigned int a = 1, b = 0; int c = length; while (c--) { a = (a + *arr) % 65521; b = (b + a) % 65521; arr++; } r = b; r = r << 16; return r|a; } /* generates a hashcode for any array of bytes */ static int hash(const BYTE *arr, int length) { int h = 0; while (length--) { h = h + (*arr * (31 ^ length)); arr++; } return h; } /* write length bytes from data to disk starting at the sector sector 'sector'. */ static int write_data(LBA sector, const BYTE *data, int length) { /* variables */ int i; const BYTE *data_ptr = data; BYTE buffer[SECTOR_SIZE]; /* validate range */ if ((sector * SECTOR_SIZE) + length > DISK_SIZE * BLOCK_SIZE * SECTOR_SIZE) return MYFS_FAT_CORRUPT; /* write data */ while (length > 0) { /* if less than a sector of data left in buffer */ if (length < SECTOR_SIZE) { /* copy remaining data into buffer and zero rest */ memcpy(buffer, data_ptr, length); for (i = length; i < SECTOR_SIZE; i++) { buffer[i] = 0; } /* write last sector from this buffer */ if (myfs_write_sector(buffer, sector) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; length = 0; } else { /* write straight from main buffer */ if (myfs_write_sector(data_ptr, sector) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; data_ptr += SECTOR_SIZE; length -= SECTOR_SIZE; sector++; } } return MYFS_SUCCESS; } /* reads length bytes starting at the sector into data */ static int read_data(LBA sector, BYTE *data, int length) { /* variables */ BYTE buffer[SECTOR_SIZE]; /* validate range */ if ((sector * SECTOR_SIZE) + length > DISK_SIZE * BLOCK_SIZE * SECTOR_SIZE) return MYFS_FAT_CORRUPT; /* write data */ while (length > 0) { /* if less than a sector of data left to read */ if (length < SECTOR_SIZE) { /* read remaining sector into buffer */ if (myfs_read_sector(buffer, sector) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; /* and copy length to buffer */ memcpy(data, buffer, length); length = 0; } else { /* read straight to main buffer */ if (myfs_read_sector(data, sector) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; data += SECTOR_SIZE; length -= SECTOR_SIZE; sector++; } } return MYFS_SUCCESS; } /* swaps the value at arr[a] with that at arr[b] */ static void sort_swap(struct BLOCK_TRANSFER arr[], int a, int b) { /* swap values */ struct BLOCK_TRANSFER v = arr[a]; arr[a] = arr[b]; arr[b] = v; } /* partitions array between arr[left] and arr[right], moving * values lt the pivot to the left, and gt the pivot to the right. */ static int sort_partition(struct BLOCK_TRANSFER arr[], int left, int right, int pivotIndex, int (*comp)(const struct BLOCK_TRANSFER, const struct BLOCK_TRANSFER)) { /* locals */ int i; int storeIndex; /* get pivot value */ struct BLOCK_TRANSFER pivotValue = arr[pivotIndex]; /* move pivot to end */ sort_swap(arr, pivotIndex, right); /* swap values on either side of pivot */ storeIndex = left; for(i = left; i < right; i++) { if (comp(arr[i], pivotValue)) { /* swap */ sort_swap(arr, storeIndex, i); storeIndex++; } } /* move pivot to final place */ sort_swap(arr, right, storeIndex); return storeIndex; } /* sorts the array between arr[left] and arr[right] into ascending order by lba */ static void sort_recursive(struct BLOCK_TRANSFER arr[], int left, int right, int (*comp)(const struct BLOCK_TRANSFER, const struct BLOCK_TRANSFER)) { /* perform quicksort on the two halves of the array */ if (right > left) { int pivotIndex = left + ((right - left) / 2); int pivotNewIndex = sort_partition(arr, left, right, pivotIndex, comp); sort_recursive(arr, left, pivotNewIndex - 1, comp); sort_recursive(arr, pivotNewIndex+1, right, comp); } } /* compares the LBA's of two BLOCK_TRANSFERs for sorting them in ascending order. */ static int compare_bylba_asc(const struct BLOCK_TRANSFER arrVal, const struct BLOCK_TRANSFER pivotVal) { return arrVal.lba <= pivotVal.lba; } /* compares the lengths of two BLOCK_TRANSFERs for sorting them in descending order */ static int compare_bylength_desc(const struct BLOCK_TRANSFER arrVal, const struct BLOCK_TRANSFER pivotVal) { return arrVal.length > pivotVal.length; } /* sorts an array of pending block transfers into ascending order by lba * to ensure optimal reading and writing. */ static void sort_bylba(struct BLOCK_TRANSFER arr[], int length) { sort_recursive(arr, 0, length-1, compare_bylba_asc); } /* sorts an array of block transfers into descending order by length * for use when finding optimal free blocks. */ static void sort_bylength(struct BLOCK_TRANSFER arr[], int length) { sort_recursive(arr, 0, length-1, compare_bylength_desc); } /* inits all flags to defaults */ static void init() { fat_needsrestore = FALSE; formatted = FALSE; filetable_buffer_sector = 0; } /* reads the fat at sector if not already cached. */ static int fat_read(LBA sector) { int *hashpointer; BYTE buffer[SECTOR_SIZE * 3]; /* read the first sector of the house-keeping */ if (read_data(sector, buffer, SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; /* check if is blank */ if (buffer[0] == 0) return MYFS_BLANK_DISK; /* check if checksum maches */ if (equals(buffer + 2, fat_buffer + 2, 4)) return MYFS_SUCCESS; /* read in the rest of the fat */ if (read_data(sector + 1, buffer + SECTOR_SIZE, SECTOR_SIZE * 2) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; /* check the checksum */ hashpointer = (int *)(buffer + 2); if (*hashpointer == checksum(buffer + 6, FAT_SIZE)) { /* if checksums match, return true */ memcpy(fat_buffer,buffer,SECTOR_SIZE * 3); return MYFS_SUCCESS; } else return MYFS_FAT_CORRUPT; } /* loads the fat table from disk (or uses cache if can) */ static int fat_load() { int r = fat_read(0); if (r == MYFS_FAT_CORRUPT) { fat_needsrestore = TRUE; r = fat_read(3); if (r == MYFS_FAT_CORRUPT) { /* both fat tables are corrupt */ return MYFS_FAT_CORRUPT; } } return r; } /* saves the current fat table to disk (in sectors 0, and 3) */ static int fat_save() { if (write_data(0, fat_buffer, 3 * SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; if (write_data(3, fat_buffer, 3 * SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; return MYFS_SUCCESS; } /* computes the checksum for the hashtable and writes that back to the * fat buffer */ static void fat_computechecksum() { int cs = checksum(fat_buffer + sizeof(int) + 2, FAT_SIZE); memcpy(fat_buffer + sizeof(LBA), &cs, sizeof(int)); } /* traverses linked list of blocks starting at sector and * puts them into global array (block_list), and returns length * or MYFS_FAT_CORRUPT if a sector points into the housekeeping section. */ static int fat_read_blocks(LBA sector, int file_size) { int i = 0; while (sector != EOF) { /* check points into data area, and not housekeeping */ if (sector < HOUSEKEEPING_SIZE) return MYFS_FAT_CORRUPT; block_list[i].lba = sector; sector = *((LBA *)(fat_buffer + 6 + (sector * 2))); if (sector == EOF) block_list[i].length = file_size; else { block_list[i].length = SECTOR_SIZE * BLOCK_SIZE; file_size -= SECTOR_SIZE * BLOCK_SIZE; } i++; } return i; } /* marks the linked list of blocks starting at sector as free */ static int fat_delete_blocks(LBA sector) { int i = 0; LBA sector2; while (sector != EOF) { /* check points into data area, and not housekeeping */ if (sector < HOUSEKEEPING_SIZE) return MYFS_FAT_CORRUPT; sector2 = *((LBA *)(fat_buffer + 6 + (sector * 2))); *(fat_buffer + 6 + (sector * 2)) = 0; sector = sector2; i++; } /* recompute checksum */ fat_computechecksum(); return MYFS_SUCCESS; } /* finds all the free blocks on the disk and adds them to the block_list array * returns the length of block_list */ static int fat_findallfreeblocks() { int i, j = 0, start = 0; LBA lba; for (i = HOUSEKEEPING_SIZE; i < DISK_SIZE; i++) { lba = *(fat_buffer + 6 + (i * 2)); if (start == 0) { if (lba == 0) { start = i; } } else { if (lba != 0) { /* add to list: start --> i - 1*/ block_list[j].lba = start; block_list[j].length = (i - start) * BLOCK_SIZE * SECTOR_SIZE; j++; start = 0; } } } if (start != 0) { block_list[j].lba = start; block_list[j].length = (i - start) * BLOCK_SIZE * SECTOR_SIZE; j++; } return j; } /* look in block_list for the smallest block range * that will fit a file of length bytes (searching from * start into block_list). returns the index in block_list for the * block that fits, or -1 if no free block is big enough */ static int fat_minthatfits(int length, int start, int list_length) { int current = start; while(start < list_length && block_list[start].length > length) { current = start; start++; } if (block_list[current].length >= length) return current; else return -1; } /* finds a list of free block ranges that will fit length bytes * puts it in block_list and returns the length of block_list * or MYFS_DISK_FULL if there wernt enough blocks available. */ static int fat_findblocks(int length) { /* variables */ int list_length, i = 0, j = 0; struct BLOCK_TRANSFER result[DISK_SIZE]; /* find all free block ranges on disk, and sort by length */ list_length = fat_findallfreeblocks(); if (list_length < 1) return MYFS_DISK_FULL; sort_bylength(block_list, list_length); /* loop while still need more blocks */ while (i < list_length) { /* trys to find 1 block range to fit whole file */ int c = fat_minthatfits(length, i, list_length); if (c != -1) { /* add block range as final block */ result[j] = block_list[c]; /* assign correct length to range */ result[j].length = length; j++; /* sort by ascending lba */ sort_bylba(result, j); /* copy into block_list */ for (i = 0; i < j; i++) { block_list[i] = result[i]; } return j; } else { /* if current not enough, add to list and look for more */ result[j] = block_list[i]; length = length - block_list[i].length; i++; j++; } } return MYFS_DISK_FULL; } /* writes the file block chain for a file to the FAT */ static void fat_writeblocks(int length) { LBA lba; int i, count; /* for each block range */ for (i = 0; i < length; i++) { /* for each block in block range */ lba = block_list[i].lba; count = block_list[i].length; while (count > BLOCK_SIZE * SECTOR_SIZE) { /* link to next block */ *((LBA *)(fat_buffer + 6 + (lba * 2))) = lba + 1; count -= BLOCK_SIZE * SECTOR_SIZE; lba++; } /* link to next block range in list */ if (i == length - 1) *((LBA *)(fat_buffer + 6 + (lba * 2))) = EOF; else *((LBA *)(fat_buffer + 6 + (lba * 2))) = block_list[i+1].lba; } fat_computechecksum(); } /* get the file details of the file at i in the directory table */ static int filetable_getentry(int i, LBA *start, int *length, char name[FILENAME_LENGTH]) { /* variables */ int j; LBA sector = (i / FILES_PER_SECTOR) + 6; /* check LBAs */ if (i < 0 || i > MAX_FILES) return MYFS_FAT_CORRUPT; /* read if sector is not in buffer already */ if (filetable_buffer_sector != sector) { /* read from disk */ if (read_data(sector, filetable_buffer, SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; filetable_buffer_sector = sector; } /* extract file information from sector and return it */ j = (i % FILES_PER_SECTOR) * 17; memcpy(start, filetable_buffer + j, sizeof(LBA)); memcpy(length, filetable_buffer + j + sizeof(LBA), sizeof(int)); memcpy(name, filetable_buffer + j + sizeof(LBA) + sizeof(int), FILENAME_LENGTH); return MYFS_SUCCESS; } /* set the file details of the file at i in the directory table */ static int filetable_setentry(int i, LBA start, int length, const char name[FILENAME_LENGTH]) { /* variables */ int j; LBA sector = (i / FILES_PER_SECTOR) + 6; /* check LBAs */ if (i < 0 || i > MAX_FILES) return MYFS_FAT_CORRUPT; /* read if sector is not in buffer already */ if (filetable_buffer_sector != sector) { /* read from disk */ if (read_data(sector, filetable_buffer, SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; filetable_buffer_sector = sector; } /* change entry */ j = (i % FILES_PER_SECTOR) * 17; memcpy(filetable_buffer + j, &start, sizeof(LBA)); memcpy(filetable_buffer + j + sizeof(LBA), &length, sizeof(int)); memcpy(filetable_buffer + j + sizeof(LBA) + sizeof(int), name, FILENAME_LENGTH); /* write back to disk */ if (write_data(sector, filetable_buffer, SECTOR_SIZE) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; return MYFS_SUCCESS; } /* find the filetable entry with the name searchname, and return its * filetable index, putting its start lba and length into the params */ static int filetable_findentry(const char searchname[FILENAME_LENGTH], LBA *start, int *length) { /* our initial index */ int r, i; char name[FILENAME_LENGTH]; int begin = hash(searchname, FILENAME_LENGTH) % MAX_FILES; r = filetable_getentry(begin, start, length, name); if (r != MYFS_SUCCESS) return r; /* loop while wrong file */ i = begin; while(*start != 0 && !equals(searchname, name, FILENAME_LENGTH)) { i++; if (i >= MAX_FILES) i = 0; if (i == begin) return MYFS_DISK_FULL; r = filetable_getentry(i, start, length, name); if (r != MYFS_SUCCESS) return r; } /* why loop terminate? */ if (*start == 0) return MYFS_FILE_NOT_FOUND; else return i; } /* gets the file details for the file with the given name */ static int filetable_get_file(const char name[FILENAME_LENGTH], LBA *start, int *length) { int r; r = filetable_findentry(name, start, length); if (r >= 0) return MYFS_SUCCESS; else if (r == MYFS_DISK_FULL) return MYFS_FILE_NOT_FOUND; else return r; } /* deletes the filetable entry for the file with the given name */ static int filetable_delete_file(const char name[FILENAME_LENGTH]) { /* search for entry */ LBA start; int length; char zeros[] = {0,0,0,0,0,0,0,0,0,0,0}; int r = filetable_findentry(name, &start, &length); if (r >= MYFS_SUCCESS) { /* overwrite file entry */ return filetable_setentry(r, 1, 0, zeros); } else return r; } /* adds the file entry for the given details to the filetable */ static int filetable_add_file(const char name[FILENAME_LENGTH], LBA start, int length) { /* find a spot for the entry */ LBA start_buffer; char name_buffer[FILENAME_LENGTH]; int length_buffer, i, r, begin = hash(name, FILENAME_LENGTH) % MAX_FILES; r = filetable_getentry(begin, &start_buffer, &length_buffer, name_buffer); if (r != MYFS_SUCCESS) return r; /* loop until found blank entry */ i = begin; while (start_buffer > 1) { /* check if file already exists */ if (equals(name_buffer, name, FILENAME_LENGTH)) return MYFS_FILE_EXISTS; /* progress linearly to next file entry */ i++; if (i >= MAX_FILES) i = 0; if (i == begin) return MYFS_DISK_FULL; r = filetable_getentry(i, &start_buffer, &length_buffer, name_buffer); if (r != MYFS_SUCCESS) return r; } /* add the entry */ return filetable_setentry(i, start, length, name); } /* formats a blank disk */ static int format_disk() { /* vars */ int i, r; BYTE buffer[SECTOR_SIZE]; /* make and save blank fat */ for (i = 0; i < 3 * SECTOR_SIZE; i++) { fat_buffer[i] = 0; } fat_buffer[0] = 1; fat_computechecksum(); /* (fat saved at end of a read or write) */ /*r = fat_save(); if (r != MYFS_SUCCESS) return r;*/ /* blank directory tables */ for (i = 0; i < SECTOR_SIZE; i++) { buffer[i] = 0; } for (i = 6; i < HOUSEKEEPING_SIZE * BLOCK_SIZE; i++) { r = write_data(i, buffer, SECTOR_SIZE); if (r != MYFS_SUCCESS) return r; } formatted = TRUE; return MYFS_SUCCESS; } /* writes the array of blocks as defined in block_list */ static int write_blocklist(int length, const BYTE *data) { int i, r, written = 0; for (i = 0; i < length; i++) { r = write_data(block_list[i].lba * BLOCK_SIZE, data + written, block_list[i].length); if (r != MYFS_SUCCESS) return r; written += block_list[i].length; } return MYFS_SUCCESS; } /* reads the array of blocks as defined in block_list */ static int read_blocklist(int length) { int i, r; for (i = 0; i < length; i++) { r = read_data(block_list[i].lba * BLOCK_SIZE, block_list[i].data, block_list[i].length); if (r != MYFS_SUCCESS) return r; } return MYFS_SUCCESS; } int myfs_read_file(const char filename[11], char buffer[], int buffer_size, int *file_size) { /* vars */ LBA lba; int i, r, l, length, size; /* initialization */ init(); r = fat_load(); if (r == MYFS_BLANK_DISK) return MYFS_FILE_NOT_FOUND; else if (r == MYFS_FAT_CORRUPT) return MYFS_DISK_FAILURE; /* get file from dir table */ r = filetable_get_file(filename, &lba, &size); if (r == MYFS_FAT_CORRUPT) return MYFS_DISK_FAILURE; else if (r != MYFS_SUCCESS) return r; /* if file exists, return its actual size */ *file_size = size; /* check for 0 length */ if (size > 0) { /* check buffer length */ if (buffer_size < size) return MYFS_BUFFER_TOO_SMALL; /* read block list */ l = fat_read_blocks(lba, size); if (l < 0) return MYFS_DISK_FAILURE; /* prepare transaction list */ length = 0; for (i = 0; i < l; i++) { block_list[i].data = buffer + length; length += block_list[i].length; } /* read block data */ if (read_blocklist(l) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; } /* file read */ return MYFS_SUCCESS; } int myfs_write_file(const char filename[11], const char buffer[], int file_size) { /* local variables */ LBA lba_buffer; int r, l, length_buffer; /* initialization */ init(); /* check file size bounds */ if (file_size > MAX_FILES * BLOCK_SIZE * SECTOR_SIZE) return MYFS_DISK_FULL; if (file_size < 0) return MYFS_DISK_FAILURE; /* load fat table */ r = fat_load(); if (r == MYFS_BLANK_DISK) { if (format_disk() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; formatted = TRUE; } else if (r == MYFS_FAT_CORRUPT) { format_disk(); fat_save(); return MYFS_DISK_FAILURE; } else if (r != MYFS_SUCCESS) { return MYFS_DISK_FAILURE; } /* check if file already exists */ r = filetable_get_file(filename, &lba_buffer, &length_buffer); if (r == MYFS_SUCCESS) return MYFS_FILE_EXISTS; else if (r == MYFS_FAT_CORRUPT) { format_disk(); fat_save(); return MYFS_DISK_FAILURE; } else if (r != MYFS_FILE_NOT_FOUND) return r; /* check for 0 length file */ if (file_size > 0) { /* find free space */ l = fat_findblocks(file_size); if (l == MYFS_DISK_FULL) return l; /* write blocks */ if (write_blocklist(l, buffer) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; lba_buffer = block_list[0].lba; /* update fat table cache */ fat_writeblocks(l); } else lba_buffer = 8; /* save fat table to disk if need to */ if (file_size > 0 || formatted) { if (fat_save() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; } /* add entry to file table */ r = filetable_add_file(filename, lba_buffer, file_size); if (r == MYFS_DISK_FULL) return r; else if (r != MYFS_SUCCESS) return MYFS_DISK_FAILURE; /* file written! */ return MYFS_SUCCESS; } int myfs_delete_file(const char filename[11]) { /* local variables */ LBA lba_buffer; int r, length_buffer; /* initialization */ init(); r = fat_load(); if (r == MYFS_BLANK_DISK) { if (format_disk() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; if (fat_save() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; return MYFS_FILE_NOT_FOUND; } else if (r == MYFS_FAT_CORRUPT) { format_disk(); fat_save(); return MYFS_DISK_FAILURE; } else if (r != MYFS_SUCCESS) { return MYFS_DISK_FAILURE; } /* check if file already exists */ r = filetable_get_file(filename, &lba_buffer, &length_buffer); if (r == MYFS_FAT_CORRUPT) { if (format_disk() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; } else if (r != MYFS_SUCCESS) return r; /* check if is 0 length */ if (length_buffer > 0) { /* delete from fat */ if (fat_delete_blocks(lba_buffer) != MYFS_SUCCESS) { format_disk(); return MYFS_DISK_FAILURE; } /* save fat */ if (fat_save() != MYFS_SUCCESS) return MYFS_DISK_FAILURE; } /* remove filetable entry */ if (filetable_delete_file(filename) != MYFS_SUCCESS) return MYFS_DISK_FAILURE; /* return if succeeded */ return MYFS_SUCCESS; }