summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2010-09-06 14:14:07 +0000
committerFrank Gevaerts <frank@gevaerts.be>2010-09-06 14:14:07 +0000
commit5d4b13beefd3c7e92b9f4ebad98022241c6c7e36 (patch)
tree4dc62de2365d1b698fdacc46023f5526670902f6 /firmware
parenta1612bbd1a38041bea8eb9053e4021ace4c59f25 (diff)
downloadrockbox-5d4b13beefd3c7e92b9f4ebad98022241c6c7e36.tar.gz
rockbox-5d4b13beefd3c7e92b9f4ebad98022241c6c7e36.tar.bz2
rockbox-5d4b13beefd3c7e92b9f4ebad98022241c6c7e36.zip
Slightly reorganise the FAT driver to ensure that no more than one sector buffer is ever allocated on the stack simultaneously. Fixes FS#11433
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28011 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/fat.c68
1 files changed, 49 insertions, 19 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index de579f7603..c97772361e 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -296,7 +296,9 @@ void fat_init(void)
#endif
}
-int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
+/* fat_mount_internal is split out of fat_mount() to avoid having both the sector
+ * buffer used here and the sector buffer used by update_fsinfo() on stack */
+static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
{
#ifndef HAVE_MULTIVOLUME
const int volume = 0;
@@ -443,6 +445,20 @@ int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
}
+ return 0;
+}
+
+int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
+{
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ int rc;
+
+ rc = fat_mount_internal(IF_MV2(volume,) IF_MD2(drive,) startsector);
+
+ if(rc!=0) return rc;
/* calculate freecount if unset */
if ( fat_bpb->fsinfo.freecount == 0xffffffff )
@@ -1101,9 +1117,9 @@ static int write_long_name(struct fat_file* file,
unsigned int numentries,
const unsigned char* name,
const unsigned char* shortname,
- bool is_directory)
+ bool is_directory,
+ unsigned char *sector_buffer)
{
- unsigned char buf[SECTOR_SIZE];
unsigned char* entry;
unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
@@ -1120,7 +1136,7 @@ static int write_long_name(struct fat_file* file,
if (rc<0)
return rc * 10 - 1;
- rc = fat_readwrite(file, 1, buf, false);
+ rc = fat_readwrite(file, 1, sector_buffer, false);
if (rc<1)
return rc * 10 - 2;
@@ -1147,25 +1163,25 @@ static int write_long_name(struct fat_file* file,
if (rc<0)
return rc * 10 - 3;
- rc = fat_readwrite(file, 1, buf, true);
+ rc = fat_readwrite(file, 1, sector_buffer, true);
if (rc<1)
return rc * 10 - 4;
/* read next sector */
- rc = fat_readwrite(file, 1, buf, false);
+ rc = fat_readwrite(file, 1, sector_buffer, false);
if (rc<0) {
LDEBUGF("Failed writing new sector: %d\n",rc);
return rc * 10 - 5;
}
if (rc==0)
/* end of dir */
- memset(buf, 0, sizeof buf);
+ memset(sector_buffer, 0, SECTOR_SIZE);
sector++;
idx = 0;
}
- entry = buf + idx * DIR_ENTRY_SIZE;
+ entry = sector_buffer + idx * DIR_ENTRY_SIZE;
/* verify this entry is free */
if (entry[0] && entry[0] != 0xe5 )
@@ -1234,7 +1250,7 @@ static int write_long_name(struct fat_file* file,
if (rc<0)
return rc * 10 - 6;
- rc = fat_readwrite(file, 1, buf, true);
+ rc = fat_readwrite(file, 1, sector_buffer, true);
if (rc<1)
return rc * 10 - 7;
@@ -1411,7 +1427,8 @@ static int add_dir_entry(struct fat_dir* dir,
firstentry, sector);
rc = write_long_name(&dir->file, firstentry,
- entries_needed, name, shortname, is_directory);
+ entries_needed, name,
+ shortname, is_directory, buf);
if (rc < 0)
return rc * 10 - 7;
@@ -1690,6 +1707,23 @@ int fat_create_file(const char* name,
return rc;
}
+/* noinline because this is only split out of fat_create_dir to make sure
+ * the sector buffer doesn't remain on the stack, to avoid nasty stack
+ * overflows later on (when flush_fat() is called */
+static __attribute__((noinline)) int fat_clear_cluster(int sector,
+ struct bpb *fat_bpb)
+{
+ unsigned char buf[SECTOR_SIZE];
+ int i,rc;
+ memset(buf, 0, sizeof buf);
+ for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
+ rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
+ if (rc < 0)
+ return rc * 10 - 2;
+ }
+ return 0;
+}
+
int fat_create_dir(const char* name,
struct fat_dir* newdir,
struct fat_dir* dir)
@@ -1699,8 +1733,6 @@ int fat_create_dir(const char* name,
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
- unsigned char buf[SECTOR_SIZE];
- int i;
long sector;
int rc;
struct fat_file dummyfile;
@@ -1724,13 +1756,11 @@ int fat_create_dir(const char* name,
update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
/* Clear the entire cluster */
- memset(buf, 0, sizeof buf);
sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
- for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
- rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
- if (rc < 0)
- return rc * 10 - 2;
- }
+ rc = fat_clear_cluster(sector,fat_bpb);
+ if (rc < 0)
+ return rc;
+
/* Then add the "." entry */
rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
@@ -1939,7 +1969,6 @@ int fat_rename(struct fat_file* file,
int rc;
struct fat_dir olddir;
struct fat_file newfile = *file;
- unsigned char buf[SECTOR_SIZE];
unsigned char* entry = NULL;
unsigned short* clusptr = NULL;
unsigned int parentcluster;
@@ -1986,6 +2015,7 @@ int fat_rename(struct fat_file* file,
/* if renaming a directory, update the .. entry to make sure
it points to its parent directory (we don't check if it was a move) */
if(FAT_ATTR_DIRECTORY == attr) {
+ unsigned char buf[SECTOR_SIZE];
/* open the dir that was renamed, we re-use the olddir struct */
rc = fat_opendir(IF_MV2(file->volume,) &olddir, newfile.firstcluster,
NULL);