diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-11-04 19:48:17 -0500 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-11-09 16:32:40 -0500 |
commit | 7ecab006c054d963f74f628390f8140fd8f64d50 (patch) | |
tree | 9505b3cf722f5cb30db86f4007f7579762dc5f87 | |
parent | e519356c473b081bc012fe49f09b7c755c355978 (diff) | |
download | rockbox-7ecab006c0.tar.gz rockbox-7ecab006c0.zip |
fat: Allow use of variable logical sector sizes
Only used if MAX_LOG_SECTOR_SIZE is defined
This allows a single build to seamlessly work with (eg) 512B or 4K sectors.
Change-Id: I85d2a6612afca6a1d7a3bd49c588b5745ab2b220
-rw-r--r-- | firmware/common/file.c | 43 | ||||
-rw-r--r-- | firmware/drivers/fat.c | 80 | ||||
-rw-r--r-- | firmware/export/fat.h | 2 |
3 files changed, 84 insertions, 41 deletions
diff --git a/firmware/common/file.c b/firmware/common/file.c index 202410db81..845fa44309 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c @@ -103,12 +103,12 @@ static int alloc_filestr(struct filestr_desc **filep) } /* return the file size in sectors */ -static inline unsigned long filesize_sectors(file_size_t size) +static inline unsigned long filesize_sectors(uint16_t sector_size, file_size_t size) { /* overflow proof whereas "(x + y - 1) / y" is not */ - unsigned long numsectors = size / SECTOR_SIZE; + unsigned long numsectors = size / sector_size; - if (size % SECTOR_SIZE) + if (size % sector_size) numsectors++; return numsectors; @@ -196,10 +196,11 @@ file_error: return rc; } -/* Handle syncing all file's streams to the truncation */ +/* Handle syncing all file's streams to the truncation */ static void handle_truncate(struct filestr_desc * const file, file_size_t size) { - unsigned long filesectors = filesize_sectors(size); + uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep); + unsigned long filesectors = filesize_sectors(sector_size, size); struct filestr_base *s = NULL; while ((s = fileobj_get_next_stream(&file->stream, s))) @@ -229,9 +230,11 @@ static int ftruncate_internal(struct filestr_desc *file, file_size_t size, file_size_t cursize = *file->sizep; file_size_t truncsize = MIN(size, cursize); + uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep); + if (write_now) { - unsigned long sector = filesize_sectors(truncsize); + unsigned long sector = filesize_sectors(sector_size, truncsize); struct filestr_cache *const cachep = file->stream.cachep; if (cachep->flags == (FSC_NEW|FSC_DIRTY) && @@ -244,7 +247,7 @@ static int ftruncate_internal(struct filestr_desc *file, file_size_t size, { /* no space left on device; further truncation needed */ discard_cache(file); - truncsize = ALIGN_DOWN(truncsize - 1, SECTOR_SIZE); + truncsize = ALIGN_DOWN(truncsize - 1, sector_size); sector--; rc = rc2; } @@ -292,6 +295,7 @@ static int fsync_internal(struct filestr_desc *file) file_size_t size = *file->sizep; unsigned int foflags = fileobj_get_flags(&file->stream); + uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep); /* flush sector cache? */ struct filestr_cache *const cachep = file->stream.cachep; @@ -302,7 +306,7 @@ static int fsync_internal(struct filestr_desc *file) { /* no space left on device so this must be dropped */ discard_cache(file); - size = ALIGN_DOWN(size - 1, SECTOR_SIZE); + size = ALIGN_DOWN(size - 1, sector_size); foflags |= FO_TRUNC; rc = rc2; } @@ -407,7 +411,7 @@ static int open_internal_inner2(const char *path, /* not found; try to create it */ callflags &= ~FO_TRUNC; - rc = create_stream_internal(&compinfo.parentinfo, compinfo.name, + rc = create_stream_internal(&compinfo.parentinfo, compinfo.name, compinfo.length, ATTR_NEW_FILE, callflags, &file->stream); if (rc < 0) @@ -649,15 +653,16 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, struct filestr_cache * const cachep = file->stream.cachep; void * const bufstart = buf; + uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep); - const unsigned long filesectors = filesize_sectors(size); - unsigned long sector = file->offset / SECTOR_SIZE; - unsigned long sectoroffs = file->offset % SECTOR_SIZE; + const unsigned long filesectors = filesize_sectors(sector_size, size); + unsigned long sector = file->offset / sector_size; + unsigned long sectoroffs = file->offset % sector_size; /* any head bytes? */ if (sectoroffs) { - size_t headbytes = MIN(nbyte, SECTOR_SIZE - sectoroffs); + size_t headbytes = MIN(nbyte, sector_size - sectoroffs); rc = readwrite_partial(file, cachep, sector, sectoroffs, buf, headbytes, filesectors, write); if (rc <= 0) @@ -676,7 +681,7 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, } /* read/write whole sectors right into/from the supplied buffer */ - unsigned long sectorcount = nbyte / SECTOR_SIZE; + unsigned long sectorcount = nbyte / sector_size; while (sectorcount) { @@ -728,8 +733,8 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, } else { - buf += rc * SECTOR_SIZE; - nbyte -= rc * SECTOR_SIZE; + buf += rc * sector_size; + nbyte -= rc * sector_size; sector += rc; sectorcount -= rc; @@ -745,9 +750,9 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, if (UNLIKELY(sectorcount && sector == cachep->sector)) { /* do this one sector with the cache */ - readwrite_cache(cachep, buf, 0, SECTOR_SIZE, write); - buf += SECTOR_SIZE; - nbyte -= SECTOR_SIZE; + readwrite_cache(cachep, buf, 0, sector_size, write); + buf += sector_size; + nbyte -= sector_size; sector++; sectorcount--; } diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index f3c273cc05..e16463ab8c 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -35,6 +35,7 @@ #include "rbunicode.h" #include "debug.h" #include "panic.h" +#include "disk.h" /*#define LOGF_ENABLE*/ #include "logf.h" @@ -162,9 +163,15 @@ union raw_dirent #define FAT_NTRES_LC_NAME 0x08 #define FAT_NTRES_LC_EXT 0x10 -#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4) -#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2) -#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE) +#ifdef MAX_LOG_SECTOR_SIZE +#define LOG_SECTOR_SIZE(bpb) fat_bpb->sector_size +#else +#define LOG_SECTOR_SIZE(bpb) SECTOR_SIZE +#endif + +#define CLUSTERS_PER_FAT_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / 4) +#define CLUSTERS_PER_FAT16_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / 2) +#define DIR_ENTRIES_PER_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / DIR_ENTRY_SIZE) #define DIR_ENTRY_SIZE 32 #define FAT_BAD_MARK 0x0ffffff7 #define FAT_EOF_MARK 0x0ffffff8 @@ -208,8 +215,10 @@ struct bpb; static void update_fsinfo32(struct bpb *fat_bpb); /* Note: This struct doesn't hold the raw values after mounting if - * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte - * physical sectors. */ + * bpb_bytspersec isn't the same as the underlying device's logical + sector size. Sector counts are then normalized to that sector + size. +*/ static struct bpb { unsigned long bpb_bytspersec; /* Bytes per sector, typically 512 */ @@ -263,12 +272,19 @@ static struct bpb int BPB_FN_DECL(update_fat_entry, unsigned long, unsigned long); void BPB_FN_DECL(fat_recalc_free_internal); #endif /* HAVE_FAT16SUPPORT */ - +#ifdef MAX_LOG_SECTOR_SIZE + uint16_t sector_size; +#endif } fat_bpbs[NUM_VOLUMES]; /* mounted partition info */ #ifdef STORAGE_NEEDS_BOUNCE_BUFFER +#ifdef MAX_LOG_SECTOR_SIZE +#define BOUNCE_SECTOR_SIZE MAX_LOG_SECTOR_SIZE +#else +#define BOUNCE_SECTOR_SIZE SECTOR_SIZE +#endif #define FAT_BOUNCE_SECTORS 10 -static uint8_t fat_bounce_buffers[NUM_VOLUMES][SECTOR_SIZE*FAT_BOUNCE_SECTORS] STORAGE_ALIGN_ATTR; +static uint8_t fat_bounce_buffers[NUM_VOLUMES][BOUNCE_SECTOR_SIZE*FAT_BOUNCE_SECTORS] STORAGE_ALIGN_ATTR; #define FAT_BOUNCE_BUFFER(bpb) \ (fat_bounce_buffers[IF_MV_VOL((bpb)->volume)]) #endif @@ -394,7 +410,7 @@ static void raw_dirent_set_fstclus(union raw_dirent *ent, long fstclus) static int bpb_is_sane(struct bpb *fat_bpb) { - if (fat_bpb->bpb_bytspersec % SECTOR_SIZE) + if (fat_bpb->bpb_bytspersec % LOG_SECTOR_SIZE(fat_bpb)) { DEBUGF("%s() - Error: sector size is not sane (%lu)\n", __func__, fat_bpb->bpb_bytspersec); @@ -402,9 +418,9 @@ static int bpb_is_sane(struct bpb *fat_bpb) } /* The fat_bpb struct does not hold the raw value of bpb_bytspersec, the - * value is multiplied in cases where bpb_bytspersec != SECTOR_SIZE. We need + * value is multiplied in cases where bpb_bytspersec != sector_size. We need * to undo that multiplication before we do the sanity check. */ - unsigned long secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE; + unsigned long secmult = fat_bpb->bpb_bytspersec / LOG_SECTOR_SIZE(fat_bpb); if (fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec / secmult > 128*1024ul) { @@ -1141,7 +1157,7 @@ static int fat_mount_internal(struct bpb *fat_bpb) } fat_bpb->bpb_bytspersec = BYTES2INT16(buf, BPB_BYTSPERSEC); - unsigned long secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE; + unsigned long secmult = fat_bpb->bpb_bytspersec / LOG_SECTOR_SIZE(fat_bpb); /* Sanity check is performed later */ fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS]; @@ -1426,7 +1442,7 @@ static int fat_extend_dir(struct bpb *fat_bpb, struct fat_filestr *dirstr) FAT_ERROR(-2); } - memset(sec, 0, SECTOR_SIZE); + memset(sec, 0, LOG_SECTOR_SIZE(fat_bpb)); dc_dirty_buf(sec); dc_unlock_cache(); } @@ -1981,6 +1997,15 @@ static int free_cluster_chain(struct bpb *fat_bpb, long startcluster) /** File entity functions **/ +int fat_file_sector_size(const struct fat_file *file) +{ +#ifdef MAX_LOG_SECTOR_SIZE + const struct bpb *fat_bpb = FAT_BPB(file->volume); +#endif + + return LOG_SECTOR_SIZE(fat_bpb); +} + int fat_create_file(struct fat_file *parent, const char *name, uint8_t attr, struct fat_file *file, struct fat_direntry *fatent) @@ -2362,11 +2387,11 @@ int fat_closewrite(struct fat_filestr *filestr, uint32_t size, count++; } - uint32_t len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE; + uint32_t len = count * fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb); DEBUGF("File is %lu clusters (chainlen=%lu, size=%lu)\n", count, len, size ); - if (len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE) + if (len > size + fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb)) panicf("Cluster chain is too long\n"); if (len < size) @@ -2429,22 +2454,22 @@ static long transfer(struct bpb *fat_bpb, sector_t start, long count, if(UNLIKELY(STORAGE_OVERLAP((uintptr_t)buf))) { void* xfer_buf = FAT_BOUNCE_BUFFER(fat_bpb); while(count > 0) { - int xfer_count = MIN(count, FAT_BOUNCE_SECTORS); + int xfer_count = MIN(count*LOG_SECTOR_SIZE(fat_bpb), (FAT_BOUNCE_SECTORS * BOUNCE_SECTOR_SIZE)) / LOG_SECTOR_SIZE(fat_bpb); if(write) { - memcpy(xfer_buf, buf, xfer_count * SECTOR_SIZE); + memcpy(xfer_buf, buf, xfer_count * LOG_SECTOR_SIZE(fat_bpb)); rc = storage_write_sectors(IF_MD(fat_bpb->drive,) start + fat_bpb->startsector, xfer_count, xfer_buf); } else { rc = storage_read_sectors(IF_MD(fat_bpb->drive,) start + fat_bpb->startsector, xfer_count, xfer_buf); - memcpy(buf, xfer_buf, xfer_count * SECTOR_SIZE); + memcpy(buf, xfer_buf, xfer_count * LOG_SECTOR_SIZE(fat_bpb)); } if(rc < 0) break; - buf += xfer_count * SECTOR_SIZE; + buf += xfer_count * LOG_SECTOR_SIZE(fat_bpb); start += xfer_count; count -= xfer_count; } @@ -2571,7 +2596,7 @@ long fat_readwrite(struct fat_filestr *filestr, unsigned long sectorcount, FAT_ERROR(rc * 10 - 2); transferred += count; - buf += count * SECTOR_SIZE; + buf += count * LOG_SECTOR_SIZE(fat_bpb); count = 0; } @@ -2744,6 +2769,11 @@ int fat_readdir(struct fat_filestr *dirstr, struct fat_dirscan_info *scan, scan->entries = 0; +#ifdef MAX_LOG_SECTOR_SIZE + struct fat_file *file = dirstr->fatfilep; + const struct bpb *fat_bpb = FAT_BPB(file->volume); +#endif + while (1) { unsigned int direntry = ++scan->entry; @@ -2863,7 +2893,6 @@ void fat_rewinddir(struct fat_dirscan_info *scan) scan->entries = 0; } - /** Mounting and unmounting functions **/ bool fat_ismounted(IF_MV_NONVOID(int volume)) @@ -2888,6 +2917,10 @@ int fat_mount(IF_MV(int volume,) IF_MD(int drive,) unsigned long startsector) fat_bpb->drive = drive; #endif +#ifdef MAX_LOG_SECTOR_SIZE + fat_bpb->sector_size = disk_get_log_sector_size(IF_MD(drive)); +#endif + rc = fat_mount_internal(fat_bpb); if (rc < 0) FAT_ERROR(rc * 10 - 2); @@ -2927,6 +2960,9 @@ int fat_unmount(IF_MV_NONVOID(int volume)) /** Debug screen stuff **/ #ifdef MAX_LOG_SECTOR_SIZE +/* This isn't necessarily the same as storage's logical sector size; + we can have situations where the filesystem (and partition table) + uses a larger "virtual sector" than the underlying storage device */ int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume)) { int bytes = 0; @@ -2945,7 +2981,7 @@ unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)) struct bpb * const fat_bpb = FAT_BPB(volume); if (fat_bpb) - size = fat_bpb->bpb_secperclus * SECTOR_SIZE; + size = fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb); return size; } @@ -2967,7 +3003,7 @@ bool fat_size(IF_MV(int volume,) sector_t *size, sector_t *free) if (!fat_bpb) return false; - unsigned long factor = fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024; + unsigned long factor = fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb) / 1024; if (size) *size = fat_bpb->dataclusters * factor; if (free) *free = fat_bpb->fsinfo.freecount * factor; diff --git a/firmware/export/fat.h b/firmware/export/fat.h index 7382d85ce4..61fe53d1cb 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h @@ -143,6 +143,8 @@ int fat_rename(struct fat_file *parent, struct fat_file *file, int fat_modtime(struct fat_file *parent, struct fat_file *file, time_t modtime); +int fat_file_sector_size(const struct fat_file *file); + /** File stream functions **/ int fat_closewrite(struct fat_filestr *filestr, uint32_t size, struct fat_direntry *fatentp); |