Page MenuHomeFreeBSD

D9547.id26427.diff
No OneTemporary

D9547.id26427.diff

Index: lib/libstand/dosfs.h
===================================================================
--- lib/libstand/dosfs.h
+++ lib/libstand/dosfs.h
@@ -96,6 +96,8 @@
typedef struct {
struct open_file *fd; /* file descriptor */
+ u_char *fatbuf; /* FAT cache buffer */
+ u_int fatbuf_blknum; /* number of 128K block in FAT cache buffer */
u_int links; /* active links to structure */
u_int spc; /* sectors per cluster */
u_int bsize; /* cluster size in bytes */
Index: lib/libstand/dosfs.c
===================================================================
--- lib/libstand/dosfs.c
+++ lib/libstand/dosfs.c
@@ -65,6 +65,7 @@
#define DEPSEC 16 /* directory entries per sector */
#define DSHIFT 4 /* DEPSEC shift */
#define LOCLUS 2 /* lowest cluster number */
+#define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */
/* DOS "BIOS Parameter Block" */
typedef struct {
@@ -132,18 +133,6 @@
((u_int)cv2((de)->dex.h_clus) << 16) | \
cv2((de)->clus))
-/*
- * fat cache metadata
- */
-struct fatcache {
- int unit; /* disk unit number */
- int size; /* buffer (and fat) size in sectors */
- u_char *buf;
-};
-
-static struct fatcache fat;
-
-static int dosunmount(DOS_FS *);
static int parsebs(DOS_FS *, DOS_BS *);
static int namede(DOS_FS *, const char *, DOS_DE **);
static int lookup(DOS_FS *, u_int, const char *, DOS_DE **);
@@ -156,33 +145,34 @@
static int ioread(DOS_FS *, u_int, void *, u_int);
static int ioget(struct open_file *, daddr_t, void *, u_int);
-static void
-dos_read_fat(DOS_FS *fs, struct open_file *fd)
+static int
+dos_read_fatblk(DOS_FS *fs, struct open_file *fd, u_int blknum)
{
- struct devdesc *dd = fd->f_devdata;
+ int err;
+ u_int io_size;
+ daddr_t offset_in_fat, max_offset_in_fat;
- if (fat.buf != NULL) { /* can we reuse old buffer? */
- if (fat.size != fs->spf) {
- free(fat.buf); /* no, free old buffer */
- fat.buf = NULL;
- }
+ offset_in_fat = ((daddr_t)blknum) * FATBLKSZ;
+ max_offset_in_fat = secbyt(fs->spf);
+ io_size = FATBLKSZ;
+ if (offset_in_fat > max_offset_in_fat)
+ offset_in_fat = max_offset_in_fat;
+ if (offset_in_fat + io_size > max_offset_in_fat)
+ io_size = ((u_int)(max_offset_in_fat - offset_in_fat));
+
+ if (io_size != 0) {
+ err = ioget(fd, fs->lsnfat + bytsec(offset_in_fat),
+ fs->fatbuf, io_size);
+ if (err != 0) {
+ fs->fatbuf_blknum = ((u_int)(-1));
+ return (err);
+ }
}
+ if (io_size < FATBLKSZ)
+ memset(fs->fatbuf + io_size, 0, FATBLKSZ - io_size);
- if (fat.buf == NULL)
- fat.buf = malloc(secbyt(fs->spf));
-
- if (fat.buf != NULL) {
- if (ioget(fd, fs->lsnfat, fat.buf, secbyt(fs->spf)) == 0) {
- fat.size = fs->spf;
- fat.unit = dd->d_unit;
- return;
- }
- }
- if (fat.buf != NULL) /* got IO error */
- free(fat.buf);
- fat.buf = NULL;
- fat.unit = -1; /* impossible unit */
- fat.size = 0;
+ fs->fatbuf_blknum = blknum;
+ return (0);
}
/*
@@ -192,24 +182,27 @@
dos_mount(DOS_FS *fs, struct open_file *fd)
{
int err;
- struct devdesc *dd = fd->f_devdata;
u_char *buf;
bzero(fs, sizeof(DOS_FS));
fs->fd = fd;
- if ((err = !(buf = malloc(secbyt(1))) ? errno : 0) ||
- (err = ioget(fs->fd, 0, buf, secbyt(1))) ||
+ if ((buf = malloc(secbyt(1))) == NULL)
+ return (errno);
+ if ((err = ioget(fs->fd, 0, buf, secbyt(1))) ||
(err = parsebs(fs, (DOS_BS *)buf))) {
- if (buf != NULL)
- free(buf);
- (void)dosunmount(fs);
+ free(buf);
return (err);
}
free(buf);
- if (fat.buf == NULL || fat.unit != dd->d_unit)
- dos_read_fat(fs, fd);
+ if ((fs->fatbuf = malloc(FATBLKSZ)) == NULL)
+ return (errno);
+ err = dos_read_fatblk(fs, fd, 0);
+ if (err != 0) {
+ free(fs->fatbuf);
+ return (err);
+ }
fs->root = dot[0];
fs->root.name[0] = ' ';
@@ -228,21 +221,9 @@
static int
dos_unmount(DOS_FS *fs)
{
- int err;
-
if (fs->links)
return (EBUSY);
- if ((err = dosunmount(fs)))
- return (err);
- return (0);
-}
-
-/*
- * Common code shared by dos_mount() and dos_unmount()
- */
-static int
-dosunmount(DOS_FS *fs)
-{
+ free(fs->fatbuf);
free(fs);
return (0);
}
@@ -257,16 +238,20 @@
DOS_FILE *f;
DOS_FS *fs;
u_int size, clus;
- int err = 0;
+ int err;
/* Allocate mount structure, associate with open */
- fs = malloc(sizeof(DOS_FS));
-
- if ((err = dos_mount(fs, fd)))
- goto out;
+ if ((fs = malloc(sizeof(DOS_FS))) == NULL)
+ return (errno);
+ if ((err = dos_mount(fs, fd))) {
+ free(fs);
+ return (err);
+ }
- if ((err = namede(fs, path, &de)))
- goto out;
+ if ((err = namede(fs, path, &de))) {
+ dos_unmount(fs);
+ return (err);
+ }
clus = stclus(fs->fatsz, de);
size = cv4(de->size);
@@ -274,18 +259,20 @@
if ((!(de->attr & FA_DIR) && (!clus != !size)) ||
((de->attr & FA_DIR) && size) ||
(clus && !okclus(fs, clus))) {
- err = EINVAL;
- goto out;
+ dos_unmount(fs);
+ return (EINVAL);
+ }
+ if ((f = malloc(sizeof(DOS_FILE))) == NULL) {
+ err = errno;
+ dos_unmount(fs);
+ return (err);
}
- f = malloc(sizeof(DOS_FILE));
bzero(f, sizeof(DOS_FILE));
f->fs = fs;
fs->links++;
f->de = *de;
fd->f_fsdata = (void *)f;
-
- out:
- return (err);
+ return (0);
}
/*
@@ -761,34 +748,57 @@
}
/*
- * Get next cluster in cluster chain. Use in core fat cache unless another
- * device replaced it.
+ * Get next cluster in cluster chain. Use in core fat cache unless
+ * the number of current 128K block in FAT has changed.
*/
static int
fatget(DOS_FS *fs, u_int *c)
{
- u_char buf[4];
- u_int x, offset, n, nbyte;
- struct devdesc *dd = fs->fd->f_devdata;
- int err = 0;
+ u_int val_in, val_out, offset, blknum, nbyte;
+ const u_char *p_entry;
+ int err;
- if (fat.unit != dd->d_unit) {
- /* fat cache was changed to another device, don't use it */
- err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf,
- fs->fatsz != 32 ? 2 : 4);
- if (err)
- return (err);
- } else {
- offset = fatoff(fs->fatsz, *c);
- nbyte = fs->fatsz != 32 ? 2 : 4;
+ /* check input value to prevent overflow in fatoff() */
+ val_in = *c;
+ if (val_in & 0xf0000000)
+ return (EINVAL);
- if (offset + nbyte > secbyt(fat.size))
- return (EINVAL);
- memcpy(buf, fat.buf + offset, nbyte);
+ /* ensure that current 128K FAT block is cached */
+ offset = fatoff(fs->fatsz, val_in);
+ nbyte = fs->fatsz != 32 ? 2 : 4;
+ if (offset + nbyte > secbyt(fs->spf))
+ return (EINVAL);
+ blknum = offset / FATBLKSZ;
+ offset %= FATBLKSZ;
+ if (offset + nbyte > FATBLKSZ)
+ return (EINVAL);
+ if (blknum != fs->fatbuf_blknum) {
+ err = dos_read_fatblk(fs, fs->fd, blknum);
+ if (err != 0)
+ return (err);
}
+ p_entry = fs->fatbuf + offset;
- x = fs->fatsz != 32 ? cv2(buf) : cv4(buf);
- *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x;
+ /* extract cluster number from FAT entry */
+ switch (fs->fatsz) {
+ case 32:
+ val_out = cv4(p_entry);
+ val_out &= 0x0fffffff;
+ break;
+ case 16:
+ val_out = cv2(p_entry);
+ break;
+ case 12:
+ val_out = cv2(p_entry);
+ if (val_in & 1)
+ val_out >>= 4;
+ else
+ val_out &= 0xfff;
+ break;
+ default:
+ return (EINVAL);
+ }
+ *c = val_out;
return (0);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 19, 2:34 PM (53 m, 2 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25642838
Default Alt Text
D9547.id26427.diff (7 KB)

Event Timeline