From 7f7b05cf05649d36934d70b3a0e630a767114759 Mon Sep 17 00:00:00 2001 From: snow flurry Date: Tue, 17 Nov 2020 12:55:16 -0800 Subject: [PATCH] dosfs: parsing fixes * don't include spaces in fext * read fat12 chains properly --- src/dosfs.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/dosfs.c b/src/dosfs.c index e295be4..c5c8b8b 100644 --- a/src/dosfs.c +++ b/src/dosfs.c @@ -147,9 +147,14 @@ dos_listdir(dosfs_t *fsd, unsigned int offset) cur->fname[8] = 0; for (j = 0; j < 3; j++) { - cur->fext[j] = dirs[i].filename[j+8]; + if (dirs[i].filename[j+8] == ' ') { + cur->fext[j] = 0; + break; + } else { + cur->fext[j] = dirs[i].filename[j+8]; + } } - cur->fext[4] = 0; + cur->fext[3] = 0; (void)memcpy(&cur->ent, &dirs[i], sizeof(struct dos_dirent)); @@ -190,8 +195,9 @@ dos_freedir(dosfile_t *dirs) static unsigned int * read_fat_chain(dosfs_t *fsd, unsigned int first, int *length) { - unsigned int cur, foff, byte_off, *chain = NULL; - uint16_t next; + unsigned int foff, byte_off, *chain = NULL; + uint16_t next, cur; + uint8_t nbuf[3]; int len = 0, res; cur = first; @@ -204,12 +210,12 @@ read_fat_chain(dosfs_t *fsd, unsigned int first, int *length) return NULL; } - foff = (fsd->fs_ver == 12) ? (cur + (cur / 2)) : /* fat12 */ + /* get byte offset of FAT entry */ + foff = (fsd->fs_ver == 12) ? ((cur / 2)*3) : /* fat12 */ (cur * 2); /* fat16 */ byte_off = (fsd->ib.resv_sect * fsd->ib.sect_size) + foff; - /* XXX: endianness */ - res = pread(fsd->ifd, &next, 2, byte_off); + res = pread(fsd->ifd, &nbuf, 3, byte_off); if (res == -1) { DPRINTF(("pread failed\n")); free(chain); @@ -217,21 +223,27 @@ read_fat_chain(dosfs_t *fsd, unsigned int first, int *length) } if (fsd->fs_ver == 12) { - if (cur & 0x0001) { - next = next >> 4; + if (cur % 2) { + next = (nbuf[1] >> 4) | (uint16_t)(nbuf[2] << 4); } else { - next = next & 0x0FFF; + next = (uint16_t)(nbuf[1] & 0x0f) << 8 | nbuf[0]; } if (next == 0x0FFF) { break; + } else if (next < 2 || next > 0xFF7) { + DPRINTF(("got weird sector %x from %x, bailing...\n", next, cur)); + free(chain); + return NULL; } } else { + next = nbuf[0] | (uint16_t)nbuf[1] << 8; if (next == 0xFFFF) { break; } } chain[len-1] = next; + cur = next; } *length = len; @@ -249,7 +261,7 @@ get_byte_offset(dosfs_t *fsd, dosfile_t *file, unsigned int f_offset) if (f_offset > file->ent.size) { DPRINTF(("offset requested is out of bounds!\n")); - return -EINVAL; + return -ERANGE; } /* size in bytes of a cluster */ @@ -265,3 +277,4 @@ get_byte_offset(dosfs_t *fsd, dosfile_t *file, unsigned int f_offset) return (file->fat_chain[coff] * csz) + (f_offset % csz); } +