summaryrefslogtreecommitdiffstats
path: root/release
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1998-03-03 04:29:01 +0000
committerjkh <jkh@FreeBSD.org>1998-03-03 04:29:01 +0000
commitd1ab9135f210e56e4a1b5104d638e7f9976b7930 (patch)
tree31c478b6a0196ca78ec4c1f8e5cc48b4d9008998 /release
parent8acfb4f2c51b23fb6afd9a5460c3e5747c9f4a82 (diff)
downloadFreeBSD-src-d1ab9135f210e56e4a1b5104d638e7f9976b7930.zip
FreeBSD-src-d1ab9135f210e56e4a1b5104d638e7f9976b7930.tar.gz
Update stand-alone DOS I/O routines to be able to read from FAT32/VFAT
partitions. This should allow sysinstall to function properly in all Win95 installation based scenarios now. Submitted by: Robert Nordier <rnordier@iafrica.com>
Diffstat (limited to 'release')
-rw-r--r--release/sysinstall/dosio.c949
-rw-r--r--release/sysinstall/dosio.h164
2 files changed, 530 insertions, 583 deletions
diff --git a/release/sysinstall/dosio.c b/release/sysinstall/dosio.c
index eb94214..68a7336 100644
--- a/release/sysinstall/dosio.c
+++ b/release/sysinstall/dosio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996 Robert Nordier
+ * Copyright (c) 1996, 1998 Robert Nordier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -8,30 +8,30 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <ctype.h>
#include <string.h>
#include "dosio.h"
@@ -39,71 +39,73 @@
#define SSHIFT 9 /* SECSIZ shift */
#define DEPSEC 16 /* directory entries per sector */
#define DSHIFT 4 /* DEPSEC shift */
-#define NFATS 2 /* number of FATs */
-#define DENMSZ 8 /* DE name size */
-#define DEXTSZ 3 /* DE extension size */
-#define DENXSZ 11 /* DE name + extension size */
#define LOCLUS 2 /* lowest cluster number */
/* DOS "BIOS Parameter Block" */
typedef struct {
- u_char secsiz[2]; /* sector size */
- u_char spc; /* sectors per cluster */
- u_char ressec[2]; /* reserved sectors */
- u_char fats; /* FATs */
- u_char dirents[2]; /* root directory entries */
- u_char secs[2]; /* total sectors */
- u_char media; /* media descriptor */
- u_char spf[2]; /* sectors per FAT */
- u_char spt[2]; /* sectors per track */
- u_char heads[2]; /* drive heads */
- u_char hidsec[4]; /* hidden sectors */
- u_char lsecs[4]; /* huge sectors */
+ u_char secsiz[2]; /* sector size */
+ u_char spc; /* sectors per cluster */
+ u_char ressec[2]; /* reserved sectors */
+ u_char fats; /* FATs */
+ u_char dirents[2]; /* root directory entries */
+ u_char secs[2]; /* total sectors */
+ u_char media; /* media descriptor */
+ u_char spf[2]; /* sectors per FAT */
+ u_char spt[2]; /* sectors per track */
+ u_char heads[2]; /* drive heads */
+ u_char hidsec[4]; /* hidden sectors */
+ u_char lsecs[4]; /* huge sectors */
+ u_char lspf[4]; /* huge sectors per FAT */
+ u_char xflg[2]; /* flags */
+ u_char vers[2]; /* filesystem version */
+ u_char rdcl[4]; /* root directory start cluster */
+ u_char infs[2]; /* filesystem info sector */
+ u_char bkbs[2]; /* backup boot sector */
} DOS_BPB;
-/* Fixed portion of DOS boot sector */
+/* Initial portion of DOS boot sector */
typedef struct {
- u_char jmp[3]; /* usually 80x86 'jmp' opcode */
- u_char oem[8]; /* OEM name and version */
- DOS_BPB bpb; /* BPB */
- u_char drive; /* drive number */
- u_char reserved; /* reserved */
- u_char extsig; /* extended boot signature */
- u_char volid[4]; /* volume ID */
- u_char label[11]; /* volume label */
- u_char fstype[8]; /* file system type */
+ u_char jmp[3]; /* usually 80x86 'jmp' opcode */
+ u_char oem[8]; /* OEM name and version */
+ DOS_BPB bpb; /* BPB */
} DOS_BS;
/* Supply missing "." and ".." root directory entries */
+static const char *const dotstr[2] = {".", ".."};
static DOS_DE dot[2] = {
- {". ", " ", FA_DIR, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0} },
- {".. ", " ", FA_DIR, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0} }
+ {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}},
+ {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}
};
-/* I/O error handler address */
-int (*dos_ioerr)(int op) = NULL;
-
/* The usual conversion macros to avoid multiplication and division */
-#define bytsec(n) ((n) >> (SSHIFT))
-#define secbyt(s) ((u_long)(s) << (SSHIFT))
-#define entsec(e) ((e) >> (DSHIFT))
+#define bytsec(n) ((n) >> SSHIFT)
+#define secbyt(s) ((s) << SSHIFT)
+#define entsec(e) ((e) >> DSHIFT)
#define bytblk(fs, n) ((n) >> (fs)->bshift)
-#define blkbyt(fs, b) ((u_long)(b) << (fs)->bshift)
-#define blksec(fs, b) ((u_long)(b) << ((fs)->bshift - (SSHIFT)))
+#define blkbyt(fs, b) ((b) << (fs)->bshift)
+#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT))
+#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT))
/* Convert cluster number to offset within filesystem */
-#define blkoff(fs, b) secbyt((fs)->lsndta) + blkbyt(fs, (b) - (LOCLUS))
+#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS))
/* Convert cluster number to logical sector number */
-#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - (LOCLUS)))
+#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS))
/* Convert cluster number to offset within FAT */
-#define fatoff(fat12, c) ((u_long)(c) + ((fat12) ? (c) >> 1 : (c)))
+#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \
+ (sz) == 16 ? (c) << 1 : \
+ (c) << 2)
/* Does cluster number reference a valid data cluster? */
-#define okclus(fs, c) ((c) >= (LOCLUS) && (c) <= (fs)->xclus)
+#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus)
+
+/* Get start cluster from directory entry */
+#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \
+ ((u_int)cv2((de)->dex.h_clus) << 16) | \
+ cv2((de)->clus))
/* Return on error */
#define RETERR(err) { \
@@ -111,47 +113,39 @@ int (*dos_ioerr)(int op) = NULL;
return -1; \
}
-static int dosunmount(DOS_FS *fs);
-static int dosstat(DOS_FS *fs, DOS_DE *de, struct stat *sb);
-static int parsebs(DOS_FS *fs, DOS_BS *bs);
-static int namede(DOS_FS *fs, const char *path, DOS_DE **dep);
-static DOS_DE *lookup(DOS_FS *fs, unsigned c, const u_char *nx, int *err);
-static off_t fsize(DOS_FS *fs, DOS_DE *de);
-static u_short fatget(DOS_FS *fs, u_short c);
-static int fatend(int fat12, u_short c);
-static int fatcnt(DOS_FS *fs, u_short c);
-static int ioread(int fd, off_t offset, void *buf, size_t nbytes);
-static int ioget(int fd, u_long lsec, void *buf, u_int nsec);
-static u_char *nxname(const char *name, char **endptr);
-static int sepchar(int c);
-static int wildchar(int c);
-static int doschar(int c);
+static int dosunmount(DOS_FS *);
+static int dosread(void *, char *, int);
+static fpos_t dosseek(void *, fpos_t, int);
+static int dosclose(void *);
+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 **);
+static void cp_xdnm(u_char *, DOS_XDE *);
+static void cp_sfn(u_char *, DOS_DE *);
+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(int, u_int, void *, u_int);
/*
* Mount DOS filesystem
*/
int
-dos_mount(DOS_FS *fs, const char *devname)
+dos_mount(DOS_FS *fs, const char *dname)
{
- char buf[SECSIZ];
- int err;
-
- memset(fs, 0, sizeof(DOS_FS));
- if ((fs->fd = open(devname, O_RDONLY)) == -1)
- RETERR(errno);
- if (!(err = ioget(fs->fd, 0, buf, 1)) &&
- !(err = parsebs(fs, (DOS_BS *)buf)))
- if (!(fs->fat = malloc(secbyt(fs->spf))))
- err = errno;
- else
- err = ioget(fs->fd, fs->lsnfat, fs->fat, fs->spf);
- if (err) {
- dosunmount(fs);
- RETERR(err);
- }
- fs->bsize = secbyt(fs->spc);
- fs->bshift = ffs(fs->bsize) - 1;
- return 0;
+ int err;
+
+ memset(fs, 0, sizeof(DOS_FS));
+ if ((fs->fd = open(dname, O_RDONLY)) == -1)
+ return -1;
+ if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) ||
+ (err = ioget(fs->fd, 0, fs->buf, 1)) ||
+ (err = parsebs(fs, (DOS_BS *)fs->buf))) {
+ (void)dosunmount(fs);
+ RETERR(err);
+ }
+ return 0;
}
/*
@@ -160,233 +154,146 @@ dos_mount(DOS_FS *fs, const char *devname)
int
dos_unmount(DOS_FS *fs)
{
- int err;
+ int err;
- if (fs->links)
- RETERR(EBUSY);
- if ((err = dosunmount(fs)))
- RETERR(err);
- return 0;
+ if (fs->links)
+ RETERR(EBUSY);
+ if ((err = dosunmount(fs)))
+ RETERR(err);
+ return 0;
}
/*
* Common code shared by dos_mount() and dos_unmount()
*/
-static
-int dosunmount(DOS_FS *fs)
+static int
+dosunmount(DOS_FS *fs)
{
- if (fs->fat)
- free(fs->fat);
- return close(fs->fd) ? errno : 0;
+ if (fs->buf)
+ free(fs->buf);
+ return close(fs->fd) ? errno : 0;
}
/*
- * Determine free data space in filesystem (in bytes)
+ * Open DOS file
*/
-u_long
-dos_free(DOS_FS *fs)
+FILE *
+dos_open(DOS_FS *fs, const char *path)
{
- unsigned n, c;
-
- n = 0;
- for (c = LOCLUS; c <= fs->xclus; c++)
- if (!fatget(fs, c))
- n++;
- return blkbyt(fs, n);
+ DOS_DE *de;
+ DOS_FILE *f;
+ u_int size, clus;
+ int err;
+
+ if ((err = namede(fs, path, &de))) {
+ errno = err;
+ return NULL;
+ }
+ if (de->attr & FA_DIR) {
+ errno = EISDIR;
+ return NULL;
+ }
+ clus = stclus(fs->fatsz, de);
+ size = cv4(de->size);
+ if (!clus ^ !size || (clus && !okclus(fs, clus))) {
+ errno = EINVAL;
+ return NULL;
+ }
+ f = malloc(sizeof(DOS_FILE));
+ memset(f, 0, sizeof(DOS_FILE));
+ f->fs = fs;
+ fs->links++;
+ f->de = *de;
+ return funopen(f, dosread, NULL, dosseek, dosclose);
}
/*
- * Close open file
+ * Read from file
*/
-int
-dos_close(void *v)
+static int
+dosread(void *v, char *buf, int nbyte)
{
+ u_int nb, off, clus, c, cnt, n;
+ int err;
DOS_FILE *f = v;
- f->fs->links--;
- free(f);
- return 0;
+ nb = (u_int)nbyte;
+ if (nb > (n = cv4(f->de.size) - f->offset))
+ nb = n;
+ off = f->offset;
+ if ((clus = stclus(f->fs->fatsz, &f->de)))
+ 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)))
+ RETERR(err);
+ if (!okclus(f->fs, c))
+ RETERR(EINVAL);
+ }
+ if (!clus || (n = f->fs->bsize - off) > cnt)
+ n = cnt;
+ if ((err = ioread(f->fs, blkoff(f->fs, c) + off, buf, n)))
+ RETERR(err);
+ f->offset += n;
+ f->c = c;
+ off = 0;
+ buf += n;
+ cnt -= n;
+ }
+ return (int)nb;
}
/*
* Reposition with file
*/
-fpos_t
-dos_seek(void *v, fpos_t offset, int whence)
+static fpos_t
+dosseek(void *v, fpos_t offset, int whence)
{
- off_t off;
- u_long size;
- DOS_FILE *f = v;
-
- size = cv4(f->de.size);
- switch (whence) {
- case SEEK_SET:
- off = 0;
- break;
- case SEEK_CUR:
- off = f->offset;
- break;
- case SEEK_END:
- off = size;
- break;
- default:
- RETERR(EINVAL);
- }
- off += offset;
- if (off < 0 || off > size)
- RETERR(EINVAL);
- f->offset = off;
- f->c = 0;
- return 0;
-}
-
-/*
- * Read from file
- */
-int
-dos_read(void *v, char *buf, int nbytes)
-{
- off_t size;
- u_long off, cnt, n;
- unsigned clus, c;
- int err;
- DOS_FILE *f = v;
-
- if ((size = fsize(f->fs, &f->de)) == -1)
- RETERR(EBADFS);
- if (nbytes > (n = size - f->offset))
- nbytes = n;
- off = f->offset;
- if ((clus = cv2(f->de.clus)))
- off &= f->fs->bsize - 1;
- c = f->c;
- cnt = nbytes;
- while (cnt) {
- n = 0;
- if (!c) {
- if ((c = clus))
- n = bytblk(f->fs, f->offset);
- } else if (!off)
- n++;
- while (n--) {
- c = fatget(f->fs, c);
- if (!okclus(f->fs, c))
- RETERR(EBADFS);
- }
- if (!clus || (n = f->fs->bsize - off) > cnt)
- n = cnt;
- if ((err = ioread(f->fs->fd, (c ? blkoff(f->fs, c) :
- secbyt(f->fs->lsndir)) + off,
- buf, n)))
- RETERR(err);
- f->offset += n;
- f->c = c;
- off = 0;
- buf += n;
- cnt -= n;
- }
- return nbytes;
-}
-
-/*
- * Get file status
- */
-int
-dos_stat(DOS_FS *fs, const char *path, struct stat *sb)
-{
- DOS_DE *de;
- int err;
-
- if ((err = namede(fs, path, &de)) || (err = dosstat(fs, de, sb)))
- RETERR(err);
- return 0;
-}
-
-/*
- * Get file status of open file
- */
-int
-dos_fstat(DOS_FILE *f, struct stat *sb)
-{
- int err;
+ off_t off;
+ u_int size;
+ DOS_FILE *f = v;
- if ((err = dosstat(f->fs, &f->de, sb)))
- RETERR(err);
- return 0;
+ size = cv4(f->de.size);
+ switch (whence) {
+ case SEEK_SET:
+ off = 0;
+ break;
+ case SEEK_CUR:
+ off = f->offset;
+ break;
+ case SEEK_END:
+ off = size;
+ break;
+ default:
+ RETERR(EINVAL);
+ }
+ off += offset;
+ if (off < 0 || off > size)
+ RETERR(EINVAL);
+ f->offset = (u_int)off;
+ f->c = 0;
+ return off;
}
/*
- * File status primitive
+ * Close open file
*/
static int
-dosstat(DOS_FS *fs, DOS_DE *de, struct stat *sb)
+dosclose(void *v)
{
+ DOS_FILE *f = v;
- memset(sb, 0, sizeof(struct stat));
- sb->st_mode = (de->attr & FA_DIR) ? S_IFDIR | 0777 : S_IFREG | 0666;
- if (de->attr & FA_RDONLY)
- sb->st_mode &= ~0222;
- if (de->attr & FA_HIDDEN)
- sb->st_mode &= ~0007;
- if (de->attr & FA_SYSTEM)
- sb->st_mode &= ~0077;
- sb->st_nlink = 1;
- dos_cvtime(&sb->st_atime, cv2(de->date), cv2(de->time));
- sb->st_mtime = sb->st_atime;
- sb->st_ctime = sb->st_atime;
- if ((sb->st_size = fsize(fs, de)) == -1)
- return EBADFS;
- if (!(de->attr & FA_DIR) || cv2(de->clus))
- sb->st_blocks = bytblk(fs, sb->st_size + fs->bsize - 1);
- sb->st_blksize = fs->bsize;
- return 0;
-}
-
-/*
- * Convert from DOS date and time
- */
-void
-dos_cvtime(time_t *timer, u_short ddate, u_short dtime)
-{
- struct tm tm;
-
- memset(&tm, 0, sizeof(tm));
- tm.tm_sec = (dtime & 0x1f) << 1;
- tm.tm_min = dtime >> 5 & 0x3f;
- tm.tm_hour = dtime >> 11;
- tm.tm_mday = ddate & 0x1f;
- tm.tm_mon = (ddate >> 5 & 0xf) - 1;
- tm.tm_year = 80 + (ddate >> 9);
- *timer = mktime(&tm);
-}
-
-/*
- * Open DOS file
- */
-FILE *
-dos_open(DOS_FS *fs, const char *path)
-{
- DOS_DE *de;
- DOS_FILE *f;
- u_long size;
- u_int clus;
- int err;
- FILE *fp;
-
- if ((err = namede(fs, path, &de)))
- return NULL;
- clus = cv2(de->clus);
- size = cv4(de->size);
- if ((clus && (!okclus(fs, clus) || (!(de->attr & FA_DIR) && !size))) ||
- (!clus && !(de->attr & FA_DIR) && size))
- return NULL;
- f = (DOS_FILE *)malloc(sizeof(DOS_FILE));
- memset(f, 0, sizeof(DOS_FILE));
- f->fs = fs;
- fs->links++;
- f->de = *de;
- fp = funopen(f, dos_read, NULL, dos_seek, dos_close);
- return fp;
+ f->fs->links--;
+ free(f);
+ return 0;
}
/*
@@ -395,35 +302,47 @@ dos_open(DOS_FS *fs, const char *path)
static int
parsebs(DOS_FS *fs, DOS_BS *bs)
{
- u_long sc;
-
- if ((bs->jmp[0] != 0xe9 && (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) ||
- bs->bpb.media < 0xf0 ||
- cv2(bs->bpb.secsiz) != SECSIZ ||
- !bs->bpb.spc || (bs->bpb.spc ^ (bs->bpb.spc - 1)) < bs->bpb.spc)
- return EINVAL;
- fs->spf = cv2(bs->bpb.spf);
- fs->dirents = cv2(bs->bpb.dirents);
- fs->spc = bs->bpb.spc;
- sc = cv2(bs->bpb.secs);
- if (!sc && bs->extsig == 0x29)
- sc = cv4(bs->bpb.lsecs);
- if (!sc || bs->bpb.fats != NFATS || bs->bpb.spc > 64)
- return EINVAL;
- if (!fs->dirents || fs->dirents & (DEPSEC - 1))
- return EINVAL;
- fs->lsnfat = cv2(bs->bpb.ressec);
- fs->lsndir = fs->lsnfat + (u_long)fs->spf * NFATS;
- fs->lsndta = fs->lsndir + entsec(fs->dirents);
- if (fs->lsndta > sc || !(sc = (sc - fs->lsndta) / fs->spc) || sc >= 0xfff6)
- return EINVAL;
- fs->fat12 = sc < 0xff6;
- fs->xclus = sc + 1;
- if (fs->spf < bytsec(fatoff(fs->fat12, fs->xclus) + SECSIZ))
- return EINVAL;
- if (bs->extsig == 0x29)
- fs->volid = cv4(bs->volid);
- return 0;
+ u_int sc;
+
+ if ((bs->jmp[0] != 0x69 &&
+ bs->jmp[0] != 0xe9 &&
+ (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) ||
+ bs->bpb.media < 0xf0)
+ return EINVAL;
+ if (cv2(bs->bpb.secsiz) != SECSIZ)
+ return EINVAL;
+ if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1))
+ return EINVAL;
+ fs->bsize = secbyt(fs->spc);
+ fs->bshift = ffs(fs->bsize) - 1;
+ if ((fs->spf = cv2(bs->bpb.spf))) {
+ if (bs->bpb.fats != 2)
+ return EINVAL;
+ if (!(fs->dirents = cv2(bs->bpb.dirents)))
+ return EINVAL;
+ } else {
+ if (!(fs->spf = cv4(bs->bpb.lspf)))
+ return EINVAL;
+ if (!bs->bpb.fats || bs->bpb.fats > 16)
+ return EINVAL;
+ if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS)
+ return EINVAL;
+ }
+ if (!(fs->lsnfat = cv2(bs->bpb.ressec)))
+ return EINVAL;
+ fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats;
+ fs->lsndta = fs->lsndir + entsec(fs->dirents);
+ if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs)))
+ return EINVAL;
+ if (fs->lsndta > sc)
+ return EINVAL;
+ if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS)
+ return EINVAL;
+ fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32;
+ sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1;
+ if (fs->xclus > sc)
+ fs->xclus = sc;
+ return 0;
}
/*
@@ -432,243 +351,265 @@ parsebs(DOS_FS *fs, DOS_BS *bs)
static int
namede(DOS_FS *fs, const char *path, DOS_DE **dep)
{
- DOS_DE *de;
- u_char *nx;
- int err;
-
- err = 0;
- de = dot;
- if (*path == '/')
- path++;
- while (*path) {
- if (!(nx = nxname(path, (char **)&path)))
- return EINVAL;
- if (!(de->attr & FA_DIR))
- return ENOTDIR;
- if (!(de = lookup(fs, cv2(de->clus), nx, &err)))
- return err ? err : ENOENT;
- if (*path == '/')
- path++;
- }
- *dep = de;
- return 0;
+ char name[256];
+ DOS_DE *de;
+ char *s;
+ size_t n;
+ int err;
+
+ err = 0;
+ de = dot;
+ if (*path == '/')
+ path++;
+ while (*path) {
+ if (!(s = strchr(path, '/')))
+ s = strchr(path, 0);
+ if ((n = s - path) > 255)
+ return ENAMETOOLONG;
+ memcpy(name, path, n);
+ name[n] = 0;
+ path = s;
+ if (!(de->attr & FA_DIR))
+ return ENOTDIR;
+ if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de)))
+ return err;
+ if (*path == '/')
+ path++;
+ }
+ *dep = de;
+ return 0;
}
/*
* Lookup path segment
*/
-static DOS_DE *
-lookup(DOS_FS *fs, unsigned c, const u_char *nx, int *err)
+static int
+lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep)
{
- static DOS_DE dir[DEPSEC];
- u_long lsec;
- u_int nsec;
- int s, e;
-
- if (!c)
- for (e = 0; e < 2; e++)
- if (!memcmp(dot + e, nx, DENXSZ))
- return dot + e;
- nsec = !c ? entsec(fs->dirents) : fs->spc;
- lsec = 0;
- do {
- if (!c && !lsec)
- lsec = fs->lsndir;
- else if okclus(fs, c)
- lsec = blklsn(fs, c);
- else {
- *err = EBADFS;
- return NULL;
- }
- for (s = 0; s < nsec; s++) {
- if ((e = ioget(fs->fd, lsec + s, dir, 1))) {
- *err = e;
- return NULL;
- }
- for (e = 0; e < DEPSEC; e++) {
- if (!*dir[e].name)
- return NULL;
- if (*dir[e].name == 0xe5 || dir[e].attr & FA_LABEL)
- continue;
- if (!memcmp(dir + e, nx, DENXSZ))
- return dir + e;
- }
- }
- } while (c && !fatend(fs->fat12, c = fatget(fs, c)));
- return NULL;
+ static DOS_DIR dir[DEPSEC];
+ u_char lfn[261];
+ u_char sfn[13];
+ u_int nsec, lsec, xdn, chk, sec, ent, x;
+ int err, ok, i;
+
+ if (!clus)
+ for (ent = 0; ent < 2; ent++)
+ if (!strcasecmp(name, dotstr[ent])) {
+ *dep = dot + ent;
+ return 0;
+ }
+ if (!clus && fs->fatsz == 32)
+ clus = fs->rdcl;
+ nsec = !clus ? entsec(fs->dirents) : fs->spc;
+ lsec = 0;
+ xdn = chk = 0;
+ for (;;) {
+ if (!clus && !lsec)
+ lsec = fs->lsndir;
+ else if (okclus(fs, clus))
+ lsec = blklsn(fs, clus);
+ else
+ return EINVAL;
+ for (sec = 0; sec < nsec; sec++) {
+ if ((err = ioget(fs->fd, lsec + sec, dir, 1)))
+ return err;
+ for (ent = 0; ent < DEPSEC; ent++) {
+ if (!*dir[ent].de.name)
+ return ENOENT;
+ if (*dir[ent].de.name != 0xe5)
+ if ((dir[ent].de.attr & FA_MASK) == FA_XDE) {
+ x = dir[ent].xde.seq;
+ if (x & 0x40 || (x + 1 == xdn &&
+ dir[ent].xde.chk == chk)) {
+ if (x & 0x40) {
+ chk = dir[ent].xde.chk;
+ x &= ~0x40;
+ }
+ if (x >= 1 && x <= 20) {
+ cp_xdnm(lfn, &dir[ent].xde);
+ xdn = x;
+ continue;
+ }
+ }
+ } 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;
+ ok = chk == x &&
+ !strcasecmp(name, (const char *)lfn);
+ }
+ if (!ok) {
+ cp_sfn(sfn, &dir[ent].de);
+ ok = !strcasecmp(name, (const char *)sfn);
+ }
+ if (ok) {
+ *dep = &dir[ent].de;
+ return 0;
+ }
+ }
+ xdn = 0;
+ }
+ }
+ if (!clus)
+ break;
+ if ((err = fatget(fs, &clus)))
+ return err;
+ if (fatend(fs->fatsz, clus))
+ break;
+ }
+ return ENOENT;
}
/*
- * Return size of file in bytes
+ * Copy name from extended directory entry
*/
-static off_t
-fsize(DOS_FS *fs, DOS_DE *de)
+static void
+cp_xdnm(u_char *lfn, DOS_XDE *xde)
{
- u_long size;
- u_int c;
- int n;
-
- if (!(size = cv4(de->size)) && de->attr & FA_DIR)
- if (!(c = cv2(de->clus)))
- size = fs->dirents * sizeof(DOS_DE);
- else {
- if ((n = fatcnt(fs, c)) == -1)
- return n;
- size = blkbyt(fs, n);
- }
- return size;
+ static struct {
+ u_int off;
+ u_int dim;
+ } ix[3] = {
+ {offsetof(DOS_XDE, name1), sizeof(xde->name1) / 2},
+ {offsetof(DOS_XDE, name2), sizeof(xde->name2) / 2},
+ {offsetof(DOS_XDE, name3), sizeof(xde->name3) / 2}
+ };
+ u_char *p;
+ u_int n, x, c;
+
+ lfn += 13 * ((xde->seq & ~0x40) - 1);
+ for (n = 0; n < 3; n++)
+ for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x;
+ p += 2, x--) {
+ if ((c = cv2(p)) && (c < 32 || c > 127))
+ c = '?';
+ if (!(*lfn++ = c))
+ return;
+ }
+ if (xde->seq & 0x40)
+ *lfn = 0;
}
/*
- * Return next cluster in cluster chain
+ * Copy short filename
*/
-static u_short
-fatget(DOS_FS *fs, u_short c)
+static void
+cp_sfn(u_char *sfn, DOS_DE *de)
{
- u_short x;
-
- x = cv2(fs->fat + fatoff(fs->fat12, c));
- return fs->fat12 ? c & 1 ? x >> 4 : x & 0xfff : x;
+ u_char *p;
+ int j, i;
+
+ p = sfn;
+ if (*de->name != ' ') {
+ for (j = 7; de->name[j] == ' '; j--);
+ for (i = 0; i <= j; i++)
+ *p++ = de->name[i];
+ if (*de->ext != ' ') {
+ *p++ = '.';
+ for (j = 2; de->ext[j] == ' '; j--);
+ for (i = 0; i <= j; i++)
+ *p++ = de->ext[i];
+ }
+ }
+ *p = 0;
+ if (*sfn == 5)
+ *sfn = 0xe5;
}
/*
- * Count number of clusters in chain
+ * Get next cluster in cluster chain
*/
static int
-fatcnt(DOS_FS *fs, u_short c)
+fatget(DOS_FS *fs, u_int *c)
{
- int n;
-
- for (n = 0; okclus(fs, c); n++)
- c = fatget(fs, c);
- return fatend(fs->fat12, c) ? n : -1;
+ u_char buf[4];
+ u_int x;
+ int err;
+
+ 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;
}
/*
* Is cluster an end-of-chain marker?
*/
static int
-fatend(int fat12, u_short c)
+fatend(u_int sz, u_int c)
{
- return c > (fat12 ? 0xff7 : 0xfff7) || c == 0xfff0;
+ return c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7);
}
/*
* Offset-based I/O primitive
*/
static int
-ioread(int fd, off_t offset, void *buf, size_t nbytes)
+ioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte)
{
- char tmp[SECSIZ];
- u_int off, n;
- int err;
-
- if ((off = offset & (SECSIZ - 1))) {
- offset -= off;
- if ((err = ioget(fd, bytsec(offset), tmp, 1)))
- return err;
- offset += SECSIZ;
- if ((n = SECSIZ - off) > nbytes)
- n = nbytes;
- memcpy(buf, tmp + off, n);
- buf += n;
- nbytes -= n;
- }
- n = nbytes & (SECSIZ - 1);
- if (nbytes -= n) {
- if ((err = ioget(fd, bytsec(offset), buf, bytsec(nbytes))))
- return err;
- offset += nbytes;
- buf += nbytes;
- }
- if (n) {
- if ((err = ioget(fd, bytsec(offset), tmp, 1)))
- return err;
- memcpy(buf, tmp, n);
- }
- return 0;
-}
-
-/*
- * Sector-based I/O primitive
- */
-static int
-ioget(int fd, u_long lsec, void *buf, u_int nsec)
-{
- size_t nbytes;
- ssize_t n;
-
- nbytes = secbyt(nsec);
- do {
- if (lseek(fd, secbyt(lsec), SEEK_SET) == -1)
- return errno;
- n = read(fd, buf, nbytes);
- } while (n == -1 && errno == EIO && dos_ioerr && dos_ioerr(0));
- if (n != nbytes)
- return n == -1 ? errno : EIO;
- return 0;
-}
-
-/*
- * Convert name to DOS directory (name + extension) format
- */
-static u_char *
-nxname(const char *name, char **endptr)
-{
- static u_char nx[DENXSZ];
- int i;
-
- memset(nx, ' ', sizeof(nx));
- for (i = 0; i < DENMSZ && doschar(*name); i++)
- nx[i] = toupper(*name++);
- if (i) {
- if (i == DENMSZ)
- while (!sepchar(*name))
- name++;
- if (*name == '.') {
- name++;
- for (i = 0; i < DEXTSZ && doschar(*name); i++)
- nx[DENMSZ + i] = toupper(*name++);
- if (i == DEXTSZ)
- while(!sepchar(*name))
- name++;
- }
- } else if (*name == '.') {
- nx[0] = *name++;
- if (*name == '.')
- nx[1] = *name++;
- }
- if ((*name && *name != '/') || *nx == ' ')
- return NULL;
- if (*nx == 0xe5)
- *nx = 5;
- *endptr = (char *)name;
- return nx;
+ char *s;
+ u_int off, n;
+ int err;
+
+ 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);
+ s += n;
+ nbyte -= n;
+ }
+ n = nbyte & (SECSIZ - 1);
+ if (nbyte -= n) {
+ if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte))))
+ return err;
+ offset += nbyte;
+ s += nbyte;
+ }
+ if (n) {
+ if ((err = iobuf(fs, bytsec(offset))))
+ return err;
+ memcpy(s, fs->buf, n);
+ }
+ return 0;
}
/*
- * Is character a path-separator?
+ * Buffered sector-based I/O primitive
*/
static int
-sepchar(int c)
+iobuf(DOS_FS *fs, u_int lsec)
{
- return !wildchar(c) && !doschar(c);
-}
+ int err;
-/*
- * Is character a wildcard?
- */
-static int
-wildchar(int c)
-{
- return c == '*' || c == '?';
+ if (fs->bufsec != lsec) {
+ if ((err = ioget(fs->fd, lsec, fs->buf, 1)))
+ return err;
+ fs->bufsec = lsec;
+ }
+ return 0;
}
/*
- * Is character valid in a DOS name?
+ * Sector-based I/O primitive
*/
static int
-doschar(int c)
+ioget(int fd, u_int lsec, void *buf, u_int nsec)
{
- return c & 0x80 || (c >= ' ' && !strchr("\"*+,./:;<=>?[\\]|", c));
+ size_t nbyte;
+ ssize_t n;
+
+ if (lseek(fd, secbyt(lsec), SEEK_SET) == -1)
+ return errno;
+ nbyte = secbyt(nsec);
+ n = read(fd, buf, nbyte);
+ return n == -1 ? errno : (size_t)n != nbyte ? EIO : 0;
}
diff --git a/release/sysinstall/dosio.h b/release/sysinstall/dosio.h
index 37756b1..5f4fc69 100644
--- a/release/sysinstall/dosio.h
+++ b/release/sysinstall/dosio.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996 Robert Nordier
+ * Copyright (c) 1996, 1998 Robert Nordier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -8,111 +8,117 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DOSIO_H
#define DOSIO_H
-/*
+/*
* DOS file attributes
*/
-#define FA_RDONLY 0x01 /* read-only */
-#define FA_HIDDEN 0x02 /* hidden file */
-#define FA_SYSTEM 0x04 /* system file */
-#define FA_LABEL 0x08 /* volume label */
-#define FA_DIR 0x10 /* directory */
-#define FA_ARCH 0x20 /* archive (file modified) */
-
-/*
- * Error number to overload if filesystem errors are detected during
- * routine processing
- */
-
-#define EBADFS EINVAL
+#define FA_RDONLY 001 /* read-only */
+#define FA_HIDDEN 002 /* hidden file */
+#define FA_SYSTEM 004 /* system file */
+#define FA_LABEL 010 /* volume label */
+#define FA_DIR 020 /* directory */
+#define FA_ARCH 040 /* archive (file modified) */
+#define FA_XDE 017 /* extended directory entry */
+#define FA_MASK 077 /* all attributes */
/*
* Macros to convert DOS-format 16-bit and 32-bit quantities
*/
-#define cv2(p) ((u_short)(p)[0] | \
- ((u_short)(p)[1] << 010))
-
-#define cv4(p) ((u_long)(p)[0] | \
- ((u_long)(p)[1] << 010) | \
- ((u_long)(p)[2] << 020) | \
- ((u_long)(p)[3] << 030))
+#define cv2(p) ((u_int16_t)(p)[0] | \
+ ((u_int16_t)(p)[1] << 010))
+#define cv4(p) ((u_int32_t)(p)[0] | \
+ ((u_int32_t)(p)[1] << 010) | \
+ ((u_int32_t)(p)[2] << 020) | \
+ ((u_int32_t)(p)[3] << 030))
/*
- * DOS directory structure
+ * Directory, filesystem, and file structures.
*/
typedef struct {
- u_char name[8]; /* name */
- u_char ext[3]; /* extension */
- u_char attr; /* attributes */
- u_char reserved[10]; /* reserved */
- u_char time[2]; /* time */
- u_char date[2]; /* date */
- u_char clus[2]; /* starting cluster */
- u_char size[4]; /* file size */
+ u_char x_case; /* case */
+ u_char c_hsec; /* created: secs/100 */
+ u_char c_time[2]; /* created: time */
+ u_char c_date[2]; /* created: date */
+ u_char a_date[2]; /* accessed: date */
+ u_char h_clus[2]; /* clus[hi] */
+} DOS_DEX;
+
+typedef struct {
+ u_char name[8]; /* name */
+ u_char ext[3]; /* extension */
+ u_char attr; /* attributes */
+ DOS_DEX dex; /* VFAT/FAT32 only */
+ u_char time[2]; /* modified: time */
+ u_char date[2]; /* modified: date */
+ u_char clus[2]; /* starting cluster */
+ u_char size[4]; /* size */
} DOS_DE;
typedef struct {
- u_char *fat; /* FAT */
- u_long volid; /* volume id */
- u_long lsnfat; /* logical sector number: fat */
- u_long lsndir; /* logical sector number: dir */
- u_long lsndta; /* logical sector number: data area */
- short fd; /* file descriptor */
- short fat12; /* 12-bit FAT entries */
- u_short spf; /* sectors per fat */
- u_short dirents; /* root directory entries */
- u_short spc; /* sectors per cluster */
- u_short xclus; /* maximum cluster number */
- u_short bsize; /* cluster size in bytes */
- u_short bshift; /* cluster conversion shift */
- u_short links; /* active links to structure */
+ u_char seq; /* flags */
+ u_char name1[5][2]; /* 1st name area */
+ u_char attr; /* (see fat_de) */
+ u_char res; /* reserved */
+ u_char chk; /* checksum */
+ u_char name2[6][2]; /* 2nd name area */
+ u_char clus[2]; /* (see fat_de) */
+ u_char name3[2][2]; /* 3rd name area */
+} DOS_XDE;
+
+typedef union {
+ DOS_DE de; /* standard directory entry */
+ DOS_XDE xde; /* extended directory entry */
+} DOS_DIR;
+
+typedef struct {
+ int 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 */
+ u_int bshift; /* cluster conversion shift */
+ u_int dirents; /* root directory entries */
+ u_int spf; /* sectors per fat */
+ u_int rdcl; /* root directory start cluster */
+ u_int lsnfat; /* start of fat */
+ u_int lsndir; /* start of root dir */
+ u_int lsndta; /* start of data area */
+ u_int fatsz; /* FAT entry size */
+ u_int xclus; /* maximum cluster number */
} DOS_FS;
typedef struct {
- DOS_FS *fs; /* associated filesystem */
- DOS_DE de; /* directory entry */
- u_long offset; /* current offset */
- u_short c; /* last cluster read */
+ DOS_FS *fs; /* associated filesystem */
+ DOS_DE de; /* directory entry */
+ u_int offset; /* current offset */
+ u_int c; /* last cluster read */
} DOS_FILE;
-/*
- * The following variable can be set to the address of an error-handling
- * routine which will be invoked when a read() returns EIO. The handler
- * should return 1 to retry the read, otherwise 0.
- */
-
-extern int (*dos_ioerr)(int op);
-
-int dos_mount(DOS_FS *fs, const char *devname);
-int dos_unmount(DOS_FS *fs);
-u_long dos_free(DOS_FS *fs);
-FILE *dos_open(DOS_FS *fs, const char *path);
-int dos_close(void *v);
-fpos_t dos_seek(void *v, fpos_t offset, int whence);
-int dos_read(void *v, char *buf, int nbytes);
-int dos_stat(DOS_FS *fs, const char *path, struct stat *sb);
-int dos_fstat(DOS_FILE *f, struct stat *sb);
-void dos_cvtime(time_t *timer, u_short ddate, u_short dtime);
+int dos_mount(DOS_FS *, const char *);
+int dos_unmount(DOS_FS *);
+FILE *dos_open(DOS_FS *, const char *);
-#endif /* !DOSIO_H */
+#endif /* !DOSIO_H */
OpenPOWER on IntegriCloud