summaryrefslogtreecommitdiffstats
path: root/lib/libstand
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libstand')
-rw-r--r--lib/libstand/cd9660.c11
-rw-r--r--lib/libstand/dosfs.c227
-rw-r--r--lib/libstand/dosfs.h2
-rw-r--r--lib/libstand/ext2fs.c12
-rw-r--r--lib/libstand/read.c2
-rw-r--r--lib/libstand/stand.h22
-rw-r--r--lib/libstand/ufs.c14
-rw-r--r--lib/libstand/write.c2
8 files changed, 189 insertions, 103 deletions
diff --git a/lib/libstand/cd9660.c b/lib/libstand/cd9660.c
index a730a8e..5d9b57b 100644
--- a/lib/libstand/cd9660.c
+++ b/lib/libstand/cd9660.c
@@ -143,7 +143,7 @@ susp_lookup_record(struct open_file *f, const char *identifier,
if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
shc = (ISO_RRIP_CONT *)sh;
error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
- cdb2devb(isonum_733(shc->location)),
+ cdb2devb(isonum_733(shc->location)), 0,
ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read);
/* Bail if it fails. */
@@ -288,7 +288,7 @@ cd9660_open(const char *path, struct open_file *f)
for (bno = 16;; bno++) {
twiddle(1);
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
- ISO_DEFAULT_BLOCK_SIZE, buf, &read);
+ 0, ISO_DEFAULT_BLOCK_SIZE, buf, &read);
if (rc)
goto out;
if (read != ISO_DEFAULT_BLOCK_SIZE) {
@@ -322,7 +322,7 @@ cd9660_open(const char *path, struct open_file *f)
twiddle(1);
rc = f->f_dev->dv_strategy
(f->f_devdata, F_READ,
- cdb2devb(bno + boff),
+ cdb2devb(bno + boff), 0,
ISO_DEFAULT_BLOCK_SIZE,
buf, &read);
if (rc)
@@ -381,7 +381,7 @@ cd9660_open(const char *path, struct open_file *f)
bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
twiddle(1);
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
- ISO_DEFAULT_BLOCK_SIZE, buf, &read);
+ 0, ISO_DEFAULT_BLOCK_SIZE, buf, &read);
if (rc)
goto out;
if (read != ISO_DEFAULT_BLOCK_SIZE) {
@@ -438,7 +438,8 @@ buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
twiddle(16);
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ,
- cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, fp->f_buf, &read);
+ cdb2devb(blkno), 0, ISO_DEFAULT_BLOCK_SIZE,
+ fp->f_buf, &read);
if (rc)
return (rc);
if (read != ISO_DEFAULT_BLOCK_SIZE)
diff --git a/lib/libstand/dosfs.c b/lib/libstand/dosfs.c
index b75d752..0ab5b97 100644
--- a/lib/libstand/dosfs.c
+++ b/lib/libstand/dosfs.c
@@ -131,7 +131,18 @@ static DOS_DE dot[2] = {
#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \
((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 **);
@@ -143,8 +154,36 @@ static int fatcnt(DOS_FS *, u_int);
static int fatget(DOS_FS *, u_int *);
static int fatend(u_int, u_int);
static int ioread(DOS_FS *, u_int, void *, u_int);
-static int iobuf(DOS_FS *, u_int);
-static int ioget(struct open_file *, u_int, void *, u_int);
+static int ioget(struct open_file *, daddr_t, size_t, void *, u_int);
+
+static void
+dos_read_fat(DOS_FS *fs, struct open_file *fd)
+{
+ struct devdesc *dd = fd->f_devdata;
+
+ if (fat.buf != NULL) { /* can we reuse old buffer? */
+ if (fat.size != fs->spf) {
+ free(fat.buf); /* no, free old buffer */
+ fat.buf = NULL;
+ }
+ }
+
+ if (fat.buf == NULL)
+ fat.buf = malloc(secbyt(fs->spf));
+
+ if (fat.buf != NULL) {
+ if (ioget(fd, fs->lsnfat, 0, 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;
+}
/*
* Mount DOS filesystem
@@ -153,15 +192,25 @@ static int
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 = !(fs->buf = malloc(SECSIZ)) ? errno : 0) ||
- (err = ioget(fs->fd, 0, fs->buf, 1)) ||
- (err = parsebs(fs, (DOS_BS *)fs->buf))) {
+
+ if ((err = !(buf = malloc(secbyt(1))) ? errno : 0) ||
+ (err = ioget(fs->fd, 0, 0, buf, secbyt(1))) ||
+ (err = parsebs(fs, (DOS_BS *)buf))) {
+ if (buf != NULL)
+ free(buf);
(void)dosunmount(fs);
return(err);
}
+ free(buf);
+
+ if (fat.buf == NULL || fat.unit != dd->d_unit)
+ dos_read_fat(fs, fd);
+
fs->root = dot[0];
fs->root.name[0] = ' ';
if (fs->fatsz == 32) {
@@ -194,8 +243,6 @@ dos_unmount(DOS_FS *fs)
static int
dosunmount(DOS_FS *fs)
{
- if (fs->buf)
- free(fs->buf);
free(fs);
return(0);
}
@@ -252,42 +299,47 @@ dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid)
DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
int err = 0;
+ /*
+ * as ioget() can be called *a lot*, use twiddle here.
+ * also 4 seems to be good value not to slow loading down too much:
+ * with 270MB file (~540k ioget() calls, twiddle can easily waste 4-5sec.
+ */
+ twiddle(4);
nb = (u_int)nbyte;
if ((size = fsize(f->fs, &f->de)) == -1)
return EINVAL;
if (nb > (n = size - f->offset))
- nb = n;
+ nb = n;
off = f->offset;
if ((clus = stclus(f->fs->fatsz, &f->de)))
- off &= f->fs->bsize - 1;
+ off &= f->fs->bsize - 1;
c = f->c;
cnt = nb;
while (cnt) {
- n = 0;
- if (!c) {
- if ((c = clus))
- n = bytblk(f->fs, f->offset);
- } else if (!off)
- n++;
- while (n--) {
- if ((err = fatget(f->fs, &c)))
+ n = 0;
+ if (!c) {
+ if ((c = clus))
+ n = bytblk(f->fs, f->offset);
+ } else if (!off)
+ n++;
+ while (n--) {
+ if ((err = fatget(f->fs, &c)))
goto out;
- if (!okclus(f->fs, c)) {
+ if (!okclus(f->fs, c)) {
err = EINVAL;
goto out;
}
- }
- if (!clus || (n = f->fs->bsize - off) > cnt)
- n = cnt;
- if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) :
- secbyt(f->fs->lsndir)) + off,
- buf, n)))
+ }
+ if (!clus || (n = f->fs->bsize - off) > cnt)
+ n = cnt;
+ if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) :
+ secbyt(f->fs->lsndir)) + off, buf, n)))
goto out;
- f->offset += n;
- f->c = c;
- off = 0;
- buf = (char *)buf + n;
- cnt -= n;
+ f->offset += n;
+ f->c = c;
+ off = 0;
+ buf = (char *)buf + n;
+ cnt -= n;
}
out:
if (resid)
@@ -364,6 +416,23 @@ dos_stat(struct open_file *fd, struct stat *sb)
}
static int
+dos_checksum(char *name, char *ext)
+{
+ int x, i;
+ char buf[11];
+
+ bcopy(name, buf, 8);
+ bcopy(ext, buf+8, 3);
+ x = 0;
+ for (i = 0; i < 11; i++) {
+ x = ((x & 1) << 7) | (x >> 1);
+ x += buf[i];
+ x &= 0xff;
+ }
+ return (x);
+}
+
+static int
dos_readdir(struct open_file *fd, struct dirent *d)
{
/* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */
@@ -417,12 +486,7 @@ dos_readdir(struct open_file *fd, struct dirent *d)
}
} else {
if (xdn == 1) {
- x = 0;
- for (i = 0; i < 11; i++) {
- x = ((x & 1) << 7) | (x >> 1);
- x += dd.de.name[i];
- x &= 0xff;
- }
+ x = dos_checksum(dd.de.name, dd.de.ext);
if (x == chk)
break;
} else {
@@ -555,7 +619,7 @@ lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep)
else
return EINVAL;
for (sec = 0; sec < nsec; sec++) {
- if ((err = ioget(fs->fd, lsec + sec, dir, 1)))
+ if ((err = ioget(fs->fd, lsec + sec, 0, dir, secbyt(1))))
return err;
for (ent = 0; ent < DEPSEC; ent++) {
if (!*dir[ent].de.name)
@@ -577,9 +641,7 @@ lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep)
}
} else if (!(dir[ent].de.attr & FA_LABEL)) {
if ((ok = xdn == 1)) {
- for (x = 0, i = 0; i < 11; i++)
- x = ((((x & 1) << 7) | (x >> 1)) +
- dir[ent].de.name[i]) & 0xff;
+ x = dos_checksum(dir[ent].de.name, dir[ent].de.ext);
ok = chk == x &&
!strcasecmp(name, (const char *)lfn);
}
@@ -699,22 +761,52 @@ fatcnt(DOS_FS *fs, u_int c)
}
/*
- * Get next cluster in cluster chain
+ * Get next cluster in cluster chain. Use in core fat cache unless another
+ * device replaced it.
*/
static int
fatget(DOS_FS *fs, u_int *c)
{
u_char buf[4];
- u_int x;
- int err;
+ u_char *s;
+ u_int x, offset, off, n, nbyte, lsec;
+ struct devdesc *dd = fs->fd->f_devdata;
+ int err = 0;
+
+ if (fat.unit != dd->d_unit) {
+ /* fat cache was changed to another device, dont 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;
+
+ s = buf;
+ if ((off = offset & (SECSIZ - 1))) {
+ offset -= off;
+ lsec = bytsec(offset);
+ offset += SECSIZ;
+ if ((n = SECSIZ - off) > nbyte)
+ n = nbyte;
+ memcpy(s, fat.buf + secbyt(lsec) + off, n);
+ s += n;
+ nbyte -= n;
+ }
+ n = nbyte & (SECSIZ - 1);
+ if (nbyte -= n) {
+ memcpy(s, fat.buf + secbyt(bytsec(offset)), nbyte);
+ offset += nbyte;
+ s += nbyte;
+ }
+ if (n)
+ memcpy(s, fat.buf + secbyt(bytsec(offset)), n);
+ }
- err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf,
- fs->fatsz != 32 ? 2 : 4);
- if (err)
- return err;
x = fs->fatsz != 32 ? cv2(buf) : cv4(buf);
*c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x;
- return 0;
+ return (0);
}
/*
@@ -739,42 +831,24 @@ ioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte)
s = buf;
if ((off = offset & (SECSIZ - 1))) {
offset -= off;
- if ((err = iobuf(fs, bytsec(offset))))
- return err;
- offset += SECSIZ;
if ((n = SECSIZ - off) > nbyte)
n = nbyte;
- memcpy(s, fs->buf + off, n);
+ if ((err = ioget(fs->fd, bytsec(offset), off, s, n)))
+ return err;
+ offset += SECSIZ;
s += n;
nbyte -= n;
}
n = nbyte & (SECSIZ - 1);
if (nbyte -= n) {
- if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte))))
+ if ((err = ioget(fs->fd, bytsec(offset), 0, s, nbyte)))
return err;
offset += nbyte;
s += nbyte;
}
if (n) {
- if ((err = iobuf(fs, bytsec(offset))))
- return err;
- memcpy(s, fs->buf, n);
- }
- return 0;
-}
-
-/*
- * Buffered sector-based I/O primitive
- */
-static int
-iobuf(DOS_FS *fs, u_int lsec)
-{
- int err;
-
- if (fs->bufsec != lsec) {
- if ((err = ioget(fs->fd, lsec, fs->buf, 1)))
+ if ((err = ioget(fs->fd, bytsec(offset), 0, s, n)))
return err;
- fs->bufsec = lsec;
}
return 0;
}
@@ -783,13 +857,8 @@ iobuf(DOS_FS *fs, u_int lsec)
* Sector-based I/O primitive
*/
static int
-ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec)
+ioget(struct open_file *fd, daddr_t lsec, size_t offset, void *buf, u_int size)
{
- int err;
-
- twiddle(1);
- if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec,
- secbyt(nsec), buf, NULL)))
- return(err);
- return(0);
+ return ((fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, offset,
+ size, buf, NULL));
}
diff --git a/lib/libstand/dosfs.h b/lib/libstand/dosfs.h
index 9e5744d..f2370ee 100644
--- a/lib/libstand/dosfs.h
+++ b/lib/libstand/dosfs.h
@@ -96,8 +96,6 @@ typedef union {
typedef struct {
struct open_file *fd; /* file descriptor */
- u_char *buf; /* buffer */
- u_int bufsec; /* buffered sector */
u_int links; /* active links to structure */
u_int spc; /* sectors per cluster */
u_int bsize; /* cluster size in bytes */
diff --git a/lib/libstand/ext2fs.c b/lib/libstand/ext2fs.c
index d0b91e0..bbc3be4 100644
--- a/lib/libstand/ext2fs.c
+++ b/lib/libstand/ext2fs.c
@@ -355,7 +355,7 @@ ext2fs_open(const char *upath, struct open_file *f)
fp->f_fs = fs;
twiddle(1);
error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size);
+ EXT2_SBLOCK, 0, EXT2_SBSIZE, (char *)fs, &buf_size);
if (error)
goto out;
@@ -397,7 +397,7 @@ ext2fs_open(const char *upath, struct open_file *f)
fp->f_bg = malloc(len);
twiddle(1);
error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len,
+ EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, 0, len,
(char *)fp->f_bg, &buf_size);
if (error)
goto out;
@@ -509,7 +509,7 @@ ext2fs_open(const char *upath, struct open_file *f)
twiddle(1);
error = (f->f_dev->dv_strategy)(f->f_devdata,
- F_READ, fsb_to_db(fs, disk_block),
+ F_READ, fsb_to_db(fs, disk_block), 0,
fs->fs_bsize, buf, &buf_size);
if (error)
goto out;
@@ -570,7 +570,7 @@ read_inode(ino_t inumber, struct open_file *f)
buf = malloc(fs->fs_bsize);
twiddle(1);
error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize);
+ ino_to_db(fs, fp->f_bg, inumber), 0, fs->fs_bsize, buf, &rsize);
if (error)
goto out;
if (rsize != fs->fs_bsize) {
@@ -667,7 +667,7 @@ block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
malloc(fs->fs_bsize);
twiddle(1);
error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize,
+ fsb_to_db(fp->f_fs, ind_block_num), 0, fs->fs_bsize,
fp->f_blk[level], &fp->f_blksize[level]);
if (error)
return (error);
@@ -725,7 +725,7 @@ buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
} else {
twiddle(4);
error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsb_to_db(fs, disk_block), block_size,
+ fsb_to_db(fs, disk_block), 0, block_size,
fp->f_buf, &fp->f_buf_size);
if (error)
goto done;
diff --git a/lib/libstand/read.c b/lib/libstand/read.c
index a984dbe..0e47fc2 100644
--- a/lib/libstand/read.c
+++ b/lib/libstand/read.c
@@ -79,7 +79,7 @@ read(int fd, void *dest, size_t bcount)
if (f->f_flags & F_RAW) {
twiddle(4);
errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- btodb(f->f_offset), bcount, dest, &resid);
+ btodb(f->f_offset), 0, bcount, dest, &resid);
if (errno)
return (-1);
f->f_offset += resid;
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index a841523..238f9ed 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -138,8 +138,8 @@ struct devsw {
const char dv_name[8];
int dv_type; /* opaque type constant, arch-dependant */
int (*dv_init)(void); /* early probe call */
- int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size,
- char *buf, size_t *rsize);
+ int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
+ size_t offset, size_t size, char *buf, size_t *rsize);
int (*dv_open)(struct open_file *f, ...);
int (*dv_close)(struct open_file *f);
int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data);
@@ -154,6 +154,24 @@ extern struct devsw netdev;
extern int errno;
+/*
+ * Generic device specifier; architecture-dependent
+ * versions may be larger, but should be allowed to
+ * overlap.
+ */
+struct devdesc
+{
+ struct devsw *d_dev;
+ int d_type;
+#define DEVT_NONE 0
+#define DEVT_DISK 1
+#define DEVT_NET 2
+#define DEVT_CD 3
+#define DEVT_ZFS 4
+ int d_unit;
+ void *d_opendata;
+};
+
struct open_file {
int f_flags; /* see F_* below */
struct devsw *f_dev; /* pointer to device operations */
diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c
index 928a1d1..21e341f 100644
--- a/lib/libstand/ufs.c
+++ b/lib/libstand/ufs.c
@@ -157,7 +157,7 @@ read_inode(inumber, f)
buf = malloc(fs->fs_bsize);
twiddle(1);
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
+ fsbtodb(fs, ino_to_fsba(fs, inumber)), 0, fs->fs_bsize,
buf, &rsize);
if (rc)
goto out;
@@ -267,7 +267,7 @@ block_map(f, file_block, disk_block_p)
malloc(fs->fs_bsize);
twiddle(1);
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsbtodb(fp->f_fs, ind_block_num),
+ fsbtodb(fp->f_fs, ind_block_num), 0,
fs->fs_bsize,
fp->f_blk[level],
&fp->f_blksize[level]);
@@ -348,7 +348,7 @@ buf_write_file(f, buf_p, size_p)
twiddle(4);
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsbtodb(fs, disk_block),
+ fsbtodb(fs, disk_block), 0,
block_size, fp->f_buf, &fp->f_buf_size);
if (rc)
return (rc);
@@ -367,7 +367,7 @@ buf_write_file(f, buf_p, size_p)
twiddle(4);
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
- fsbtodb(fs, disk_block),
+ fsbtodb(fs, disk_block), 0,
block_size, fp->f_buf, &fp->f_buf_size);
return (rc);
}
@@ -408,7 +408,7 @@ buf_read_file(f, buf_p, size_p)
} else {
twiddle(4);
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- fsbtodb(fs, disk_block),
+ fsbtodb(fs, disk_block), 0,
block_size, fp->f_buf, &fp->f_buf_size);
if (rc)
return (rc);
@@ -521,7 +521,7 @@ ufs_open(upath, f)
*/
for (i = 0; sblock_try[i] != -1; i++) {
rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
- sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
+ sblock_try[i] / DEV_BSIZE, 0, SBLOCKSIZE,
(char *)fs, &buf_size);
if (rc)
goto out;
@@ -651,7 +651,7 @@ ufs_open(upath, f)
twiddle(1);
rc = (f->f_dev->dv_strategy)(f->f_devdata,
- F_READ, fsbtodb(fs, disk_block),
+ F_READ, fsbtodb(fs, disk_block), 0,
fs->fs_bsize, buf, &buf_size);
if (rc)
goto out;
diff --git a/lib/libstand/write.c b/lib/libstand/write.c
index 9e02f08..daf33cf 100644
--- a/lib/libstand/write.c
+++ b/lib/libstand/write.c
@@ -82,7 +82,7 @@ write(fd, dest, bcount)
if (f->f_flags & F_RAW) {
twiddle(4);
errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
- btodb(f->f_offset), bcount, dest, &resid);
+ btodb(f->f_offset), 0, bcount, dest, &resid);
if (errno)
return (-1);
f->f_offset += resid;
OpenPOWER on IntegriCloud