summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2024-11-04 19:48:17 -0500
committerSolomon Peachy <pizza@shaftnet.org>2024-11-09 16:32:40 -0500
commit7ecab006c054d963f74f628390f8140fd8f64d50 (patch)
tree9505b3cf722f5cb30db86f4007f7579762dc5f87
parente519356c473b081bc012fe49f09b7c755c355978 (diff)
downloadrockbox-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.c43
-rw-r--r--firmware/drivers/fat.c80
-rw-r--r--firmware/export/fat.h2
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);