mass WIP commit
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
c018281728
commit
383403eba4
7
Makefile
7
Makefile
@ -1,6 +1,6 @@
|
|||||||
CFLAGS ?= -Iinclude -ggdb2
|
CFLAGS ?= -Iinclude -ggdb2
|
||||||
|
|
||||||
all: build build/test-get-set-cluster build/test-mkfs-simple build/test-fragment-file
|
all: build build/test-get-set-cluster build/test-mkfs-simple build/test-fragment-file build/pangtool
|
||||||
|
|
||||||
build:
|
build:
|
||||||
mkdir build
|
mkdir build
|
||||||
@ -12,4 +12,7 @@ build/test-mkfs-simple: tests/mkfs-simple.c src/fat12.c include/fat12.h src/mkfa
|
|||||||
$(CC) $(CFLAGS) tests/mkfs-simple.c src/mkfat.c src/fat12.c src/io.c -o $@
|
$(CC) $(CFLAGS) tests/mkfs-simple.c src/mkfat.c src/fat12.c src/io.c -o $@
|
||||||
|
|
||||||
build/test-fragment-file: tests/fragment-file.c src/fat12.c include/fat12.h src/mkfat.c src/io.c include/io.h
|
build/test-fragment-file: tests/fragment-file.c src/fat12.c include/fat12.h src/mkfat.c src/io.c include/io.h
|
||||||
$(CC) $(CFLAGS) tests/fragment-file.c src/mkfat.c src/fat12.c src/io.c -o $@
|
$(CC) $(CFLAGS) tests/fragment-file.c src/mkfat.c src/fat12.c src/io.c -o $@
|
||||||
|
|
||||||
|
build/pangtool: tests/pangtool.c src/fat12.c include/fat12.h src/mkfat.c src/file.c src/io.c include/io.h
|
||||||
|
$(CC) $(CFLAGS) tests/pangtool.c src/mkfat.c src/fat12.c src/io.c src/file.c -o $@
|
@ -17,4 +17,37 @@ struct fat_directory_entry {
|
|||||||
uint8_t file_size[4];
|
uint8_t file_size[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct fat12_partition
|
||||||
|
{
|
||||||
|
struct pang_io *io;
|
||||||
|
|
||||||
|
// Number of bytes in a sector (512)
|
||||||
|
uint32_t sector_size;
|
||||||
|
uint8_t sector_buffer[512];
|
||||||
|
|
||||||
|
// These units are "sectors"
|
||||||
|
uint32_t fat_offset;
|
||||||
|
uint32_t fat_size;
|
||||||
|
uint32_t root_offset;
|
||||||
|
uint32_t first_offset;
|
||||||
|
uint32_t cluster_size;
|
||||||
|
|
||||||
|
// These are in single-unit quantities
|
||||||
|
uint32_t root_entries;
|
||||||
|
uint32_t cluster_count;
|
||||||
|
uint32_t cluster_bytes;
|
||||||
|
uint32_t sector_count;
|
||||||
|
|
||||||
|
void *fat;
|
||||||
|
uint16_t *taf;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fat_attributes {
|
||||||
|
FAT_ATTR_DIR = 0x10,
|
||||||
|
FAT_ATTR_FILE = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t fat12_find_free_cluster(struct fat12_partition *part, uint32_t start);
|
||||||
|
|
||||||
#endif /* FAT12_INTERNALS_H__ */
|
#endif /* FAT12_INTERNALS_H__ */
|
@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
struct pang_io;
|
struct pang_io;
|
||||||
struct fat12_partition;
|
struct fat12_partition;
|
||||||
|
struct fat12_file;
|
||||||
struct fat12_dirent
|
struct fat12_dirent
|
||||||
{
|
{
|
||||||
char filename[256];
|
char filename[256];
|
||||||
uint32_t first_cluster;
|
uint32_t first_cluster;
|
||||||
|
uint32_t parent_cluster;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t file_attributes;
|
uint32_t file_attributes;
|
||||||
uint32_t ctime;
|
uint32_t ctime;
|
||||||
@ -33,8 +35,14 @@ uint32_t fat12_get_cluster(void *fat, uint32_t cluster);
|
|||||||
|
|
||||||
int fat12_ls_foreach(struct fat12_partition *part, uint32_t dir_cluster,
|
int fat12_ls_foreach(struct fat12_partition *part, uint32_t dir_cluster,
|
||||||
void *data, int (*callback)(void *data, const struct fat12_dirent *dirent));
|
void *data, int (*callback)(void *data, const struct fat12_dirent *dirent));
|
||||||
int fat12_write_file(struct fat12_partition *part, const char *filename, const void *bfr, uint32_t size);
|
int fat12_write_file(struct fat12_partition *part, const char *filename[], const void *bfr, uint32_t size);
|
||||||
int fat12_delete_file(struct fat12_partition *part, const char *filename);
|
int fat12_delete_file(struct fat12_partition *part, const char *filename[]);
|
||||||
|
int fat12_defragment_file(struct fat12_partition *part, const char *path[]);
|
||||||
|
|
||||||
|
struct fat12_file *fat12_fopen(struct fat12_partition *part, const char *filename);
|
||||||
|
int fat12_fwrite(struct fat12_file *file, const void *buf, uint32_t size);
|
||||||
|
int fat12_fread(struct fat12_file *file, void *buf, uint32_t size);
|
||||||
|
int fat12_fclose(struct fat12_file **file);
|
||||||
|
|
||||||
int fat12_defrag(struct pang_io *io);
|
int fat12_defrag(struct pang_io *io);
|
||||||
int fat12_mkfs(struct pang_io *io, uint32_t bytes);
|
int fat12_mkfs(struct pang_io *io, uint32_t bytes);
|
||||||
|
456
src/fat12.c
456
src/fat12.c
@ -2,34 +2,16 @@
|
|||||||
#include "fat12-internals.h"
|
#include "fat12-internals.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
struct fat12_partition
|
struct fat_dirent_ptr
|
||||||
{
|
{
|
||||||
struct pang_io *io;
|
struct fat_directory_entry entry;
|
||||||
|
uint32_t sector;
|
||||||
// Number of bytes in a sector (512)
|
uint32_t offset;
|
||||||
uint32_t sector_size;
|
|
||||||
uint8_t sector_buffer[512];
|
|
||||||
|
|
||||||
// These units are "sectors"
|
|
||||||
uint32_t fat_offset;
|
|
||||||
uint32_t fat_size;
|
|
||||||
uint32_t root_offset;
|
|
||||||
uint32_t first_offset;
|
|
||||||
uint32_t cluster_size;
|
|
||||||
|
|
||||||
// These are in single-unit quantities
|
|
||||||
uint32_t root_entries;
|
|
||||||
uint32_t cluster_count;
|
|
||||||
uint32_t cluster_bytes;
|
|
||||||
uint32_t sector_count;
|
|
||||||
|
|
||||||
// Used for traversing directories
|
|
||||||
uint32_t current_cluster;
|
|
||||||
|
|
||||||
void *fat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void fat12_write_u8(void *ptr, uint8_t val)
|
void fat12_write_u8(void *ptr, uint8_t val)
|
||||||
@ -114,6 +96,37 @@ uint32_t fat12_get_cluster(void *fat, uint32_t cluster)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fat_dirent_set_name(struct fat_directory_entry *dirent, const char *filename)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ext_split = -1;
|
||||||
|
int name_off = 0;
|
||||||
|
int dirent_off = 0;
|
||||||
|
|
||||||
|
for (name_off = 0; filename[name_off] != '\0'; name_off++)
|
||||||
|
{
|
||||||
|
if (filename[name_off] == '.')
|
||||||
|
ext_split = name_off + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dirent_off = 0; dirent_off < 8; dirent_off++)
|
||||||
|
{
|
||||||
|
if (dirent_off < (ext_split - 1))
|
||||||
|
dirent->file_name[dirent_off] = toupper(filename[dirent_off]);
|
||||||
|
else
|
||||||
|
dirent->file_name[dirent_off] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
name_off = ext_split + 1;
|
||||||
|
for (dirent_off = 0; dirent_off < 3; dirent_off++)
|
||||||
|
{
|
||||||
|
if ((ext_split >= 0) && (filename[ext_split]))
|
||||||
|
dirent->extension[dirent_off] = toupper(filename[ext_split++]);
|
||||||
|
else
|
||||||
|
dirent->extension[dirent_off] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct fat12_partition *fat12_alloc(void)
|
struct fat12_partition *fat12_alloc(void)
|
||||||
{
|
{
|
||||||
struct fat12_partition *part = malloc(sizeof(struct fat12_partition));
|
struct fat12_partition *part = malloc(sizeof(struct fat12_partition));
|
||||||
@ -121,73 +134,12 @@ struct fat12_partition *fat12_alloc(void)
|
|||||||
return part;
|
return part;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fat12_open(struct fat12_partition *part, const char *filename)
|
static uint32_t cluster_for_sector(struct fat12_partition *part, uint32_t sector) {
|
||||||
{
|
return ((sector - part->first_offset) / part->cluster_size) + 2;
|
||||||
|
|
||||||
if (!part)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (part->io)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
part->io = pang_open(filename);
|
|
||||||
if (!part->io)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (pang_read(part->io, 0, part->sector_buffer, sizeof(part->sector_buffer)) != sizeof(part->sector_buffer))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
part->sector_size = fat12_read_u16(part->sector_buffer + 0x0b);
|
|
||||||
|
|
||||||
// These are in single-unit quantities
|
|
||||||
part->root_entries = fat12_read_u16(part->sector_buffer + 0x11);
|
|
||||||
part->sector_count = fat12_read_u16(part->sector_buffer + 0x13);
|
|
||||||
|
|
||||||
// These units are "sectors"
|
|
||||||
part->fat_offset = fat12_read_u16(part->sector_buffer + 0x0e);
|
|
||||||
part->fat_size = fat12_read_u16(part->sector_buffer + 0x16);
|
|
||||||
part->root_offset = part->fat_offset + part->fat_size;
|
|
||||||
part->first_offset = part->root_offset + (part->root_entries * sizeof(struct fat_directory_entry)) / part->sector_size;
|
|
||||||
part->cluster_size = fat12_read_u8(part->sector_buffer + 0x0d);
|
|
||||||
|
|
||||||
uint32_t bytes = (part->sector_count - part->first_offset) * part->sector_size;
|
|
||||||
part->cluster_count = bytes / part->sector_size / part->cluster_size;
|
|
||||||
part->cluster_bytes = (part->cluster_count * 3) / 2;
|
|
||||||
|
|
||||||
// Move to the root directory
|
|
||||||
part->current_cluster = part->first_offset;
|
|
||||||
|
|
||||||
///
|
|
||||||
fprintf(stderr, "part->sector_size: %d\n", part->sector_size);
|
|
||||||
|
|
||||||
// These are in single-unit quantities
|
|
||||||
fprintf(stderr, "part->root_entries: %d\n", part->root_entries);
|
|
||||||
fprintf(stderr, "part->sector_count: %d\n", part->sector_count);
|
|
||||||
|
|
||||||
// These units are "sectors"
|
|
||||||
fprintf(stderr, "part->fat_offset: %d\n", part->fat_offset);
|
|
||||||
fprintf(stderr, "part->fat_size: %d\n", part->fat_size);
|
|
||||||
fprintf(stderr, "part->root_offset: %d\n", part->root_offset);
|
|
||||||
fprintf(stderr, "part->first_offset: %d\n", part->first_offset);
|
|
||||||
fprintf(stderr, "part->cluster_size: %d\n", part->cluster_size);
|
|
||||||
|
|
||||||
fprintf(stderr, "part->cluster_count: %d\n", part->cluster_count);
|
|
||||||
fprintf(stderr, "part->cluster_bytes: %d\n", part->cluster_bytes);
|
|
||||||
fprintf(stderr, "data_bytes: %d\n", bytes);
|
|
||||||
///
|
|
||||||
|
|
||||||
if (1)
|
|
||||||
{
|
|
||||||
part->fat = malloc(part->fat_size * part->sector_size);
|
|
||||||
pang_read(part->io, part->fat_offset * part->sector_size, part->fat, part->fat_size * part->sector_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fat12_reload(struct fat12_partition *part)
|
static uint32_t sector_for_cluster(struct fat12_partition *part, uint32_t cluster) {
|
||||||
{
|
return ((cluster - 2) * part->cluster_size) + part->first_offset;
|
||||||
pang_read(part->io, part->fat_offset * part->sector_size, part->fat, part->fat_size * part->sector_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fat12_ls_foreach_sector(struct fat12_partition *part, uint32_t sector, uint32_t count,
|
static int fat12_ls_foreach_sector(struct fat12_partition *part, uint32_t sector, uint32_t count,
|
||||||
@ -206,6 +158,8 @@ static int fat12_ls_foreach_sector(struct fat12_partition *part, uint32_t sector
|
|||||||
memcpy(dirent.filename + 8, entry->extension, 3);
|
memcpy(dirent.filename + 8, entry->extension, 3);
|
||||||
dirent.first_cluster = fat12_read_u16(&entry->first_cluster);
|
dirent.first_cluster = fat12_read_u16(&entry->first_cluster);
|
||||||
dirent.size = fat12_read_u32(&entry->file_size);
|
dirent.size = fat12_read_u32(&entry->file_size);
|
||||||
|
dirent.file_attributes = entry->file_attributes;
|
||||||
|
dirent.parent_cluster = sector_for_cluster(part, sector);
|
||||||
|
|
||||||
if ((entry->file_name[0] != 0xe5) && (entry->file_name[0] != 0x00))
|
if ((entry->file_name[0] != 0xe5) && (entry->file_name[0] != 0x00))
|
||||||
callback(data, &dirent);
|
callback(data, &dirent);
|
||||||
@ -243,6 +197,99 @@ int fat12_ls_foreach(struct fat12_partition *part, uint32_t dir_cluster, void *d
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int update_taf(void *_part, const struct fat12_dirent *dir) {
|
||||||
|
struct fat12_partition *part = _part;
|
||||||
|
((uint16_t *)part->taf)[dir->first_cluster] = 0x8000 | dir->parent_cluster;
|
||||||
|
uint32_t last_cluster = dir->first_cluster;
|
||||||
|
while (1) {
|
||||||
|
uint32_t cluster = fat12_get_cluster(part->fat, last_cluster);
|
||||||
|
|
||||||
|
if ((cluster == 0) || (cluster >= 0xff8)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
((uint16_t *)part->taf)[cluster] = last_cluster;
|
||||||
|
last_cluster = cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir->file_attributes & FAT_ATTR_DIR)
|
||||||
|
fat12_ls_foreach(part, sector_for_cluster(part, dir->first_cluster), part, update_taf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fat12_reload(struct fat12_partition *part)
|
||||||
|
{
|
||||||
|
pang_read(part->io, part->fat_offset * part->sector_size, part->fat, part->fat_size * part->sector_size);
|
||||||
|
memset(part->taf, 0, sizeof(part->taf));
|
||||||
|
fat12_ls_foreach(part, 0, part, update_taf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fat12_open(struct fat12_partition *part, const char *filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!part)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (part->io)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
part->io = pang_open(filename);
|
||||||
|
if (!part->io)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (pang_read(part->io, 0, part->sector_buffer, sizeof(part->sector_buffer)) != sizeof(part->sector_buffer))
|
||||||
|
{
|
||||||
|
if (!errno)
|
||||||
|
errno = -ENOSPC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
part->sector_size = fat12_read_u16(part->sector_buffer + 0x0b);
|
||||||
|
|
||||||
|
// These are in single-unit quantities
|
||||||
|
part->root_entries = fat12_read_u16(part->sector_buffer + 0x11);
|
||||||
|
part->sector_count = fat12_read_u16(part->sector_buffer + 0x13);
|
||||||
|
|
||||||
|
// These units are "sectors"
|
||||||
|
part->fat_offset = fat12_read_u16(part->sector_buffer + 0x0e);
|
||||||
|
part->fat_size = fat12_read_u16(part->sector_buffer + 0x16);
|
||||||
|
part->root_offset = part->fat_offset + part->fat_size;
|
||||||
|
part->first_offset = part->root_offset + (part->root_entries * sizeof(struct fat_directory_entry)) / part->sector_size;
|
||||||
|
part->cluster_size = fat12_read_u8(part->sector_buffer + 0x0d);
|
||||||
|
|
||||||
|
uint32_t bytes = (part->sector_count - part->first_offset) * part->sector_size;
|
||||||
|
part->cluster_count = bytes / part->sector_size / part->cluster_size;
|
||||||
|
part->cluster_bytes = (part->cluster_count * 3) / 2;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
///
|
||||||
|
fprintf(stderr, "part->sector_size: %d\n", part->sector_size);
|
||||||
|
|
||||||
|
// These are in single-unit quantities
|
||||||
|
fprintf(stderr, "part->root_entries: %d\n", part->root_entries);
|
||||||
|
fprintf(stderr, "part->sector_count: %d\n", part->sector_count);
|
||||||
|
|
||||||
|
// These units are "sectors"
|
||||||
|
fprintf(stderr, "part->fat_offset: %d\n", part->fat_offset);
|
||||||
|
fprintf(stderr, "part->fat_size: %d\n", part->fat_size);
|
||||||
|
fprintf(stderr, "part->root_offset: %d\n", part->root_offset);
|
||||||
|
fprintf(stderr, "part->first_offset: %d\n", part->first_offset);
|
||||||
|
fprintf(stderr, "part->cluster_size: %d\n", part->cluster_size);
|
||||||
|
|
||||||
|
fprintf(stderr, "part->cluster_count: %d\n", part->cluster_count);
|
||||||
|
fprintf(stderr, "part->cluster_bytes: %d\n", part->cluster_bytes);
|
||||||
|
fprintf(stderr, "data_bytes: %d\n", bytes);
|
||||||
|
///
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
if (1)
|
||||||
|
{
|
||||||
|
part->fat = malloc(part->fat_size * part->sector_size);
|
||||||
|
part->taf = malloc(part->cluster_count * sizeof(uint16_t));
|
||||||
|
fat12_reload(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void fat12_flush(struct fat12_partition *part)
|
void fat12_flush(struct fat12_partition *part)
|
||||||
{
|
{
|
||||||
pang_write(part->io, part->fat_offset * part->sector_size, part->fat, part->fat_size * part->sector_size);
|
pang_write(part->io, part->fat_offset * part->sector_size, part->fat, part->fat_size * part->sector_size);
|
||||||
@ -282,7 +329,7 @@ void fat12_free(struct fat12_partition **part)
|
|||||||
*part = NULL;
|
*part = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fat12_find_free_cluster(struct fat12_partition *part, uint32_t start)
|
uint32_t fat12_find_free_cluster(struct fat12_partition *part, uint32_t start)
|
||||||
{
|
{
|
||||||
uint32_t cluster_value;
|
uint32_t cluster_value;
|
||||||
if (start < 1)
|
if (start < 1)
|
||||||
@ -290,12 +337,92 @@ static uint32_t fat12_find_free_cluster(struct fat12_partition *part, uint32_t s
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
cluster_value = fat12_get_cluster(part->fat, ++start);
|
cluster_value = fat12_get_cluster(part->fat, ++start);
|
||||||
fprintf(stderr, "Cluster %d value: %03x\n", start, cluster_value);
|
// fprintf(stderr, "Cluster %d value: %03x\n", start, cluster_value);
|
||||||
} while (cluster_value != 0);
|
} while (cluster_value != 0);
|
||||||
fprintf(stderr, "Found free cluster %d\n", start);
|
// fprintf(stderr, "Found free cluster %d\n", start);
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_next_directory_sector(struct fat12_partition *part, int depth, int sector)
|
||||||
|
{
|
||||||
|
uint32_t entries_per_sector = part->sector_size / sizeof(struct fat_directory_entry);
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
if ((part->root_offset - sector) * entries_per_sector >= part->root_entries)
|
||||||
|
return -1;
|
||||||
|
return sector + 1;
|
||||||
|
}
|
||||||
|
uint32_t cluster = cluster_for_sector(part, sector) + 2;
|
||||||
|
if (((sector + 1) & ((part->cluster_size * part->sector_size) - 1)) == (sector + 1))
|
||||||
|
{
|
||||||
|
uint32_t next_cluster = fat12_get_cluster(part->fat, cluster);
|
||||||
|
if (next_cluster >= 0xff8 || next_cluster == 0)
|
||||||
|
return -1;
|
||||||
|
return sector_for_cluster(part, next_cluster);
|
||||||
|
}
|
||||||
|
return sector + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_object(struct fat12_partition *part, const char *filename[], uint32_t prune, struct fat_dirent_ptr *ptr)
|
||||||
|
{
|
||||||
|
uint32_t file_cluster = 0;
|
||||||
|
uint32_t depth = 0;
|
||||||
|
|
||||||
|
// Find the dirent of the file
|
||||||
|
uint32_t dirent_cluster = 0;
|
||||||
|
|
||||||
|
// Filename we're searching for
|
||||||
|
struct fat_directory_entry dirent;
|
||||||
|
uint32_t entries_per_sector = part->sector_size / sizeof(struct fat_directory_entry);
|
||||||
|
struct fat_directory_entry entries[entries_per_sector];
|
||||||
|
|
||||||
|
// If the root directory matches, take that.
|
||||||
|
int sector = part->root_offset;
|
||||||
|
if (!filename[prune]) {
|
||||||
|
memset(&ptr->entry, 0, sizeof(ptr->entry));
|
||||||
|
ptr->sector = sector;
|
||||||
|
ptr->offset = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_entry:
|
||||||
|
fat_dirent_set_name(&dirent, filename[depth]);
|
||||||
|
int i = 0;
|
||||||
|
int check_entry_i;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pang_read(part->io, sector * part->sector_size, entries, sizeof(entries));
|
||||||
|
for (check_entry_i = 0; (check_entry_i < entries_per_sector) && (i < part->root_entries); check_entry_i++, i++)
|
||||||
|
{
|
||||||
|
if (!memcmp(&entries[check_entry_i], &dirent, 11))
|
||||||
|
{
|
||||||
|
if (filename[depth + 1 + prune])
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
sector = fat12_read_u16(entries[check_entry_i].first_cluster) * part->cluster_size + part->first_offset;
|
||||||
|
goto next_entry;
|
||||||
|
}
|
||||||
|
ptr->entry = entries[check_entry_i];
|
||||||
|
ptr->offset = check_entry_i;
|
||||||
|
ptr->sector = sector;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((sector = get_next_directory_sector(part, depth, sector)) != -1);
|
||||||
|
// ENOTFOUND
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_file(struct fat12_partition *part, const char *filename[], struct fat_dirent_ptr *ptr)
|
||||||
|
{
|
||||||
|
return find_object(part, filename, 0, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_parent(struct fat12_partition *part, const char *filename[], struct fat_dirent_ptr *ptr)
|
||||||
|
{
|
||||||
|
return find_object(part, filename, 1, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static int fat12_add_dirent_sector(struct fat12_partition *part, uint32_t sector, uint32_t count, const struct fat_directory_entry *new_dirent)
|
static int fat12_add_dirent_sector(struct fat12_partition *part, uint32_t sector, uint32_t count, const struct fat_directory_entry *new_dirent)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -323,7 +450,7 @@ static int fat12_add_dirent_sector(struct fat12_partition *part, uint32_t sector
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fat12_dir_update_or_add_dirent(struct fat12_partition *part, uint32_t dir_cluster, const struct fat_directory_entry *dirent)
|
static int fat12_dir_update_or_add_dirent(struct fat12_partition *part, uint32_t sector, const struct fat_directory_entry *dirent)
|
||||||
{
|
{
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
@ -345,53 +472,33 @@ static int fat12_dir_update_or_add_dirent(struct fat12_partition *part, uint32_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fat_dirent_set_name(struct fat_directory_entry *dirent, const char *filename)
|
int fat12_write_file(struct fat12_partition *part, const char *path[], const void *bfr, uint32_t size)
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int ext_split = -1;
|
|
||||||
int name_off = 0;
|
|
||||||
int dirent_off = 0;
|
|
||||||
|
|
||||||
for (name_off = 0; filename[name_off] != '\0'; name_off++)
|
|
||||||
{
|
|
||||||
if (filename[name_off] == '.')
|
|
||||||
ext_split = name_off + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dirent_off = 0; dirent_off < 8; dirent_off++)
|
|
||||||
{
|
|
||||||
if (dirent_off < (ext_split - 1))
|
|
||||||
dirent->file_name[dirent_off] = toupper(filename[dirent_off]);
|
|
||||||
else
|
|
||||||
dirent->file_name[dirent_off] = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
name_off = ext_split + 1;
|
|
||||||
for (dirent_off = 0; dirent_off < 3; dirent_off++)
|
|
||||||
{
|
|
||||||
if ((ext_split >= 0) && (filename[ext_split]))
|
|
||||||
dirent->extension[dirent_off] = toupper(filename[ext_split++]);
|
|
||||||
else
|
|
||||||
dirent->extension[dirent_off] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fat12_write_file(struct fat12_partition *part, const char *filename, const void *bfr, uint32_t size)
|
|
||||||
{
|
{
|
||||||
// TODO: directory support
|
// TODO: directory support
|
||||||
uint32_t first_cluster;
|
uint32_t first_cluster;
|
||||||
uint32_t cluster;
|
uint32_t cluster;
|
||||||
|
const char *filename;
|
||||||
|
int i;
|
||||||
|
for (i = 0; path[i+1]; i++)
|
||||||
|
;
|
||||||
|
filename = path[i];
|
||||||
|
|
||||||
|
struct fat_dirent_ptr parent;
|
||||||
|
if (-1 == find_parent(part, path, &parent)) {
|
||||||
|
// ENOTFOUND
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
cluster = first_cluster = fat12_find_free_cluster(part, 1);
|
cluster = first_cluster = fat12_find_free_cluster(part, 1);
|
||||||
|
|
||||||
struct fat_directory_entry dirent;
|
struct fat_directory_entry dirent;
|
||||||
memset(&dirent, 0, sizeof(dirent));
|
memset(&dirent, 0, sizeof(dirent));
|
||||||
fat_dirent_set_name(&dirent, filename);
|
fat_dirent_set_name(&dirent, filename);
|
||||||
dirent.file_attributes = 0x20;
|
dirent.file_attributes = FAT_ATTR_FILE;
|
||||||
dirent.reserved1 = 0x18;
|
dirent.reserved1 = 0x18;
|
||||||
fat12_write_u16(dirent.first_cluster, first_cluster);
|
fat12_write_u16(dirent.first_cluster, first_cluster);
|
||||||
fat12_write_u32(dirent.file_size, size);
|
fat12_write_u32(dirent.file_size, size);
|
||||||
fat12_dir_update_or_add_dirent(part, 0, &dirent);
|
fat12_dir_update_or_add_dirent(part, parent.sector, &dirent);
|
||||||
|
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
{
|
{
|
||||||
@ -404,7 +511,7 @@ int fat12_write_file(struct fat12_partition *part, const char *filename, const v
|
|||||||
bfr,
|
bfr,
|
||||||
bytes_to_write);
|
bytes_to_write);
|
||||||
size -= bytes_to_write;
|
size -= bytes_to_write;
|
||||||
fprintf(stderr, "%s: %d bytes left\n", filename, size);
|
// fprintf(stderr, "%s: %d bytes left\n", filename, size);
|
||||||
if (!size)
|
if (!size)
|
||||||
fat12_set_cluster(part->fat, cluster, 0xff8);
|
fat12_set_cluster(part->fat, cluster, 0xff8);
|
||||||
else
|
else
|
||||||
@ -416,49 +523,13 @@ int fat12_write_file(struct fat12_partition *part, const char *filename, const v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t find_root_cluster_for_file(struct fat12_partition *part, const char *filename)
|
int fat12_delete_file(struct fat12_partition *part, const char *filename[])
|
||||||
{
|
|
||||||
uint32_t file_cluster = 0;
|
|
||||||
|
|
||||||
// Find the dirent of the file
|
|
||||||
uint32_t dirent_cluster = 0;
|
|
||||||
|
|
||||||
// TODO: Support directories other than the root directory
|
|
||||||
if (1)
|
|
||||||
{
|
|
||||||
struct fat_directory_entry dirent;
|
|
||||||
uint32_t entries_per_sector = part->sector_size / sizeof(struct fat_directory_entry);
|
|
||||||
fat_dirent_set_name(&dirent, filename);
|
|
||||||
int i = 0;
|
|
||||||
int check_entry_i;
|
|
||||||
int sector = part->root_offset - 1; // -1 because we use it to update the entry below.
|
|
||||||
while (i < part->root_entries)
|
|
||||||
{
|
|
||||||
struct fat_directory_entry entries[entries_per_sector];
|
|
||||||
pang_read(part->io, ++sector * part->sector_size, entries, sizeof(entries));
|
|
||||||
for (check_entry_i = 0; (check_entry_i < entries_per_sector) && (i < part->root_entries); check_entry_i++, i++)
|
|
||||||
{
|
|
||||||
if (!memcmp(&entries[check_entry_i], &dirent, 11))
|
|
||||||
{
|
|
||||||
entries[check_entry_i].file_name[0] = 0xe5;
|
|
||||||
pang_write(part->io, sector * part->sector_size, entries, sizeof(entries));
|
|
||||||
return fat12_read_u16(entries[check_entry_i].first_cluster);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fat12_delete_file(struct fat12_partition *part, const char *filename)
|
|
||||||
{
|
{
|
||||||
// Find the root cluster of the file
|
// Find the root cluster of the file
|
||||||
uint32_t root_cluster = find_root_cluster_for_file(part, filename);
|
struct fat_dirent_ptr ptr;
|
||||||
|
if (-1 == find_file(part, filename, &ptr))
|
||||||
// A return value of 0 (or 1) is not a valid cluster, so there's
|
|
||||||
// nothing to do.
|
|
||||||
if (root_cluster < 2)
|
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "Couldn't find filename %s\n", filename[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,7 +537,7 @@ int fat12_delete_file(struct fat12_partition *part, const char *filename)
|
|||||||
// it's been deleted.
|
// it's been deleted.
|
||||||
|
|
||||||
// Set all clusters in the FAT to 0x000, indicating they're free.
|
// Set all clusters in the FAT to 0x000, indicating they're free.
|
||||||
uint32_t this_cluster = root_cluster;
|
uint32_t this_cluster = fat12_read_u16(ptr.entry.first_cluster);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uint32_t next_cluster = fat12_get_cluster(part->fat, this_cluster);
|
uint32_t next_cluster = fat12_get_cluster(part->fat, this_cluster);
|
||||||
@ -474,5 +545,52 @@ int fat12_delete_file(struct fat12_partition *part, const char *filename)
|
|||||||
fat12_set_cluster(part->fat, this_cluster, 0);
|
fat12_set_cluster(part->fat, this_cluster, 0);
|
||||||
this_cluster = next_cluster;
|
this_cluster = next_cluster;
|
||||||
} while ((this_cluster < 0xff8) && (this_cluster > 1));
|
} while ((this_cluster < 0xff8) && (this_cluster > 1));
|
||||||
|
|
||||||
|
// Free the file by setting the first letter of the filename to 0xe5.
|
||||||
|
ptr.entry.file_name[0] = 0xe5;
|
||||||
|
struct fat_directory_entry full_dir[part->sector_size / sizeof(struct fat_directory_entry)];
|
||||||
|
pang_read(part->io, ptr.sector * part->sector_size, full_dir, part->sector_size);
|
||||||
|
full_dir[ptr.offset] = ptr.entry;
|
||||||
|
pang_write(part->io, ptr.sector * part->sector_size, full_dir, part->sector_size);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fat12_defragment_file(struct fat12_partition *part, const char *path[])
|
||||||
|
{
|
||||||
|
struct fat_dirent_ptr ptr;
|
||||||
|
uint32_t cluster;
|
||||||
|
if (-1 == find_file(part, path, &ptr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cluster = cluster_for_sector(part, ptr.sector);
|
||||||
|
while (1) {
|
||||||
|
uint32_t next_cluster = fat12_get_cluster(part->fat, cluster);
|
||||||
|
if ((next_cluster == 0) || (cluster >= 0xff8)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (next_cluster != cluster + 1) {
|
||||||
|
// File is fragmented!
|
||||||
|
// We need to figure out if it's part of a chain, or if it's the root node.
|
||||||
|
if (fat12_get_cluster(part->fat, cluster + 1) == 0) {
|
||||||
|
// Yay, the cluster is free! Swap our data into here
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Cluster is used by: %04x\n", part->taf[cluster + 1]);
|
||||||
|
/*
|
||||||
|
// The cluster is used. Figure out if it's in the FAT, or if it's a dirent.
|
||||||
|
uint32_t fat_scan_offset;
|
||||||
|
for (fat_scan_offset = 2; fat_scan_offset < part->cluster_count; fat_scan_offset++) {
|
||||||
|
if (fat12_get_cluster(part->fat, fat_scan_offset) == (cluster + 1)) {
|
||||||
|
// Found a match, update the FAT entry and swap our data with the one at this offset.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Didn't find a match, so it must be a directory entry.
|
||||||
|
*/
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
cluster = next_cluster + 1;
|
||||||
|
}
|
||||||
}
|
}
|
@ -6,7 +6,9 @@
|
|||||||
#include "fat12-internals.h"
|
#include "fat12-internals.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Create a FAT12 filesystem using the given file descriptor,
|
// Create a FAT12 filesystem using the given file descriptor,
|
||||||
// with length _bytes_.
|
// with length _bytes_.
|
||||||
@ -33,6 +35,7 @@ int fat12_mkfs(struct pang_io *io, uint32_t bytes) {
|
|||||||
root_directory_sector_count = cluster_size;
|
root_directory_sector_count = cluster_size;
|
||||||
uint32_t root_directory_entry_count = (sector_size / sizeof(struct fat_directory_entry)) * root_directory_sector_count;
|
uint32_t root_directory_entry_count = (sector_size / sizeof(struct fat_directory_entry)) * root_directory_sector_count;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "bytes: %d\n", bytes);
|
fprintf(stderr, "bytes: %d\n", bytes);
|
||||||
fprintf(stderr, "sector_size: %d\n", sector_size);
|
fprintf(stderr, "sector_size: %d\n", sector_size);
|
||||||
fprintf(stderr, "cluster_size: %d\n", cluster_size);
|
fprintf(stderr, "cluster_size: %d\n", cluster_size);
|
||||||
@ -42,6 +45,7 @@ int fat12_mkfs(struct pang_io *io, uint32_t bytes) {
|
|||||||
fprintf(stderr, "root_directory_sector_count: %d\n", root_directory_sector_count);
|
fprintf(stderr, "root_directory_sector_count: %d\n", root_directory_sector_count);
|
||||||
fprintf(stderr, "root_directory_entry_count: %d\n", root_directory_entry_count);
|
fprintf(stderr, "root_directory_entry_count: %d\n", root_directory_entry_count);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
memset(mbr, 0, sizeof(mbr));
|
memset(mbr, 0, sizeof(mbr));
|
||||||
|
|
||||||
|
@ -73,25 +73,30 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *foo_filename[] = { "foo.bar", NULL };
|
||||||
|
const char *baz_filename[] = { "baz.qux", NULL };
|
||||||
|
|
||||||
memset_str(tmp_bfr, "baz.qux\x0a", 16384);
|
memset_str(tmp_bfr, "baz.qux\x0a", 16384);
|
||||||
fat12_write_file(part, "baz.qux", tmp_bfr, 16384);
|
fat12_write_file(part, baz_filename, tmp_bfr, 16384);
|
||||||
// run_command("yes baz.qux | dd bs=16384 count=1 | fattool build/fat12-fragmented.img writefile baz.qux");
|
// run_command("yes baz.qux | dd bs=16384 count=1 | fattool build/fat12-fragmented.img writefile baz.qux");
|
||||||
|
|
||||||
memset_str(tmp_bfr, "foo.bar\x0a", 16384);
|
memset_str(tmp_bfr, "foo.bar\x0a", 16384);
|
||||||
fat12_write_file(part, "foo.bar", tmp_bfr, 16384);
|
fat12_write_file(part, foo_filename, tmp_bfr, 16384);
|
||||||
// run_command("yes foo.bar | dd bs=16384 count=1 | fattool build/fat12-fragmented.img writefile foo.bar");
|
// run_command("yes foo.bar | dd bs=16384 count=1 | fattool build/fat12-fragmented.img writefile foo.bar");
|
||||||
|
|
||||||
fat12_delete_file(part, "baz.qux");
|
fat12_delete_file(part, baz_filename);
|
||||||
// fat12_flush(part);
|
// fat12_flush(part);
|
||||||
// run_command("fattool build/fat12-fragmented.img deletefile baz.qux");
|
// run_command("fattool build/fat12-fragmented.img deletefile baz.qux");
|
||||||
// fat12_sync(part);
|
// fat12_sync(part);
|
||||||
|
|
||||||
memset_str(tmp_bfr, "baz.qux\x0a", 32768);
|
memset_str(tmp_bfr, "baz.qux\x0a", 32768);
|
||||||
fat12_write_file(part, "baz.qux", tmp_bfr, 32768);
|
fat12_write_file(part, baz_filename, tmp_bfr, 32768);
|
||||||
// run_command("yes baz.qux | dd bs=16384 count=2 | fattool build/fat12-fragmented.img writefile baz.qux");
|
// run_command("yes baz.qux | dd bs=16384 count=2 | fattool build/fat12-fragmented.img writefile baz.qux");
|
||||||
|
|
||||||
fat12_ls_foreach(part, 0, NULL, list_directory);
|
fat12_ls_foreach(part, 0, NULL, list_directory);
|
||||||
|
|
||||||
|
fat12_defragment_file(part, baz_filename);//const char *path[])
|
||||||
|
|
||||||
fat12_close(part);
|
fat12_close(part);
|
||||||
fat12_free(&part);
|
fat12_free(&part);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user