dosfs.c revision 40005
138451Smsmith/* 238451Smsmith * Copyright (c) 1996, 1998 Robert Nordier 338451Smsmith * All rights reserved. 438451Smsmith * 538451Smsmith * Redistribution and use in source and binary forms, with or without 638451Smsmith * modification, are permitted provided that the following conditions 738451Smsmith * are met: 838451Smsmith * 1. Redistributions of source code must retain the above copyright 938451Smsmith * notice, this list of conditions and the following disclaimer. 1038451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138451Smsmith * notice, this list of conditions and the following disclaimer in 1238451Smsmith * the documentation and/or other materials provided with the 1338451Smsmith * distribution. 1438451Smsmith * 1538451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 1638451Smsmith * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1738451Smsmith * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1838451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY 1938451Smsmith * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2038451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 2138451Smsmith * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2238451Smsmith * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2338451Smsmith * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2438451Smsmith * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 2538451Smsmith * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2638451Smsmith */ 2738451Smsmith 2838451Smsmith/* 2938451Smsmith * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, 3038451Smsmith * also supports VFAT. 3138451Smsmith */ 3238451Smsmith 3338451Smsmith#include <sys/types.h> 3438451Smsmith#include <string.h> 3538451Smsmith#include <stddef.h> 3638451Smsmith 3738451Smsmith#include "stand.h" 3838451Smsmith 3938451Smsmith#include "dosfs.h" 4038451Smsmith 4138451Smsmith 4240005Smsmithstatic int dos_open(const char *path, struct open_file *fd); 4338451Smsmithstatic int dos_close(struct open_file *fd); 4438451Smsmithstatic int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid); 4538451Smsmithstatic off_t dos_seek(struct open_file *fd, off_t offset, int whence); 4638451Smsmithstatic int dos_stat(struct open_file *fd, struct stat *sb); 4738451Smsmith 4838582Srnordierstruct fs_ops dosfs_fsops = { 4938451Smsmith "dosfs", dos_open, dos_close, dos_read, null_write, dos_seek, dos_stat 5038451Smsmith}; 5138451Smsmith 5238451Smsmith#define SECSIZ 512 /* sector size */ 5338451Smsmith#define SSHIFT 9 /* SECSIZ shift */ 5438451Smsmith#define DEPSEC 16 /* directory entries per sector */ 5538451Smsmith#define DSHIFT 4 /* DEPSEC shift */ 5638451Smsmith#define LOCLUS 2 /* lowest cluster number */ 5738451Smsmith 5838451Smsmith/* DOS "BIOS Parameter Block" */ 5938451Smsmithtypedef struct { 6038451Smsmith u_char secsiz[2]; /* sector size */ 6138451Smsmith u_char spc; /* sectors per cluster */ 6238451Smsmith u_char ressec[2]; /* reserved sectors */ 6338451Smsmith u_char fats; /* FATs */ 6438451Smsmith u_char dirents[2]; /* root directory entries */ 6538451Smsmith u_char secs[2]; /* total sectors */ 6638451Smsmith u_char media; /* media descriptor */ 6738451Smsmith u_char spf[2]; /* sectors per FAT */ 6838451Smsmith u_char spt[2]; /* sectors per track */ 6938451Smsmith u_char heads[2]; /* drive heads */ 7038451Smsmith u_char hidsec[4]; /* hidden sectors */ 7138451Smsmith u_char lsecs[4]; /* huge sectors */ 7238451Smsmith u_char lspf[4]; /* huge sectors per FAT */ 7338451Smsmith u_char xflg[2]; /* flags */ 7438451Smsmith u_char vers[2]; /* filesystem version */ 7538451Smsmith u_char rdcl[4]; /* root directory start cluster */ 7638451Smsmith u_char infs[2]; /* filesystem info sector */ 7738451Smsmith u_char bkbs[2]; /* backup boot sector */ 7838451Smsmith} DOS_BPB; 7938451Smsmith 8038451Smsmith/* Initial portion of DOS boot sector */ 8138451Smsmithtypedef struct { 8238451Smsmith u_char jmp[3]; /* usually 80x86 'jmp' opcode */ 8338451Smsmith u_char oem[8]; /* OEM name and version */ 8438451Smsmith DOS_BPB bpb; /* BPB */ 8538451Smsmith} DOS_BS; 8638451Smsmith 8738451Smsmith/* Supply missing "." and ".." root directory entries */ 8838451Smsmithstatic const char *const dotstr[2] = {".", ".."}; 8938451Smsmithstatic DOS_DE dot[2] = { 9038451Smsmith {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 9138451Smsmith {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}, 9238451Smsmith {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 9338451Smsmith {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}} 9438451Smsmith}; 9538451Smsmith 9638451Smsmith/* The usual conversion macros to avoid multiplication and division */ 9738451Smsmith#define bytsec(n) ((n) >> SSHIFT) 9838451Smsmith#define secbyt(s) ((s) << SSHIFT) 9938451Smsmith#define entsec(e) ((e) >> DSHIFT) 10038451Smsmith#define bytblk(fs, n) ((n) >> (fs)->bshift) 10138451Smsmith#define blkbyt(fs, b) ((b) << (fs)->bshift) 10238451Smsmith#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT)) 10338451Smsmith#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT)) 10438451Smsmith 10538451Smsmith/* Convert cluster number to offset within filesystem */ 10638451Smsmith#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS)) 10738451Smsmith 10838451Smsmith/* Convert cluster number to logical sector number */ 10938451Smsmith#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS)) 11038451Smsmith 11138451Smsmith/* Convert cluster number to offset within FAT */ 11238451Smsmith#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \ 11338451Smsmith (sz) == 16 ? (c) << 1 : \ 11438451Smsmith (c) << 2) 11538451Smsmith 11638451Smsmith/* Does cluster number reference a valid data cluster? */ 11738451Smsmith#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) 11838451Smsmith 11938451Smsmith/* Get start cluster from directory entry */ 12038451Smsmith#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ 12138451Smsmith ((u_int)cv2((de)->dex.h_clus) << 16) | \ 12238451Smsmith cv2((de)->clus)) 12338451Smsmith 12438451Smsmithstatic int dosunmount(DOS_FS *); 12538451Smsmithstatic int parsebs(DOS_FS *, DOS_BS *); 12638451Smsmithstatic int namede(DOS_FS *, const char *, DOS_DE **); 12738451Smsmithstatic int lookup(DOS_FS *, u_int, const char *, DOS_DE **); 12838451Smsmithstatic void cp_xdnm(u_char *, DOS_XDE *); 12938451Smsmithstatic void cp_sfn(u_char *, DOS_DE *); 13038582Srnordierstatic off_t fsize(DOS_FS *, DOS_DE *); 13138582Srnordierstatic int fatcnt(DOS_FS *, u_int); 13238451Smsmithstatic int fatget(DOS_FS *, u_int *); 13338451Smsmithstatic int fatend(u_int, u_int); 13438451Smsmithstatic int ioread(DOS_FS *, u_int, void *, u_int); 13538451Smsmithstatic int iobuf(DOS_FS *, u_int); 13638451Smsmithstatic int ioget(struct open_file *, u_int, void *, u_int); 13738451Smsmith 13838451Smsmith/* 13938451Smsmith * Mount DOS filesystem 14038451Smsmith */ 14138451Smsmithstatic int 14238451Smsmithdos_mount(DOS_FS *fs, struct open_file *fd) 14338451Smsmith{ 14438451Smsmith int err; 14538451Smsmith 14638451Smsmith bzero(fs, sizeof(DOS_FS)); 14738451Smsmith fs->fd = fd; 14838582Srnordier if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) || 14938451Smsmith (err = ioget(fs->fd, 0, fs->buf, 1)) || 15038451Smsmith (err = parsebs(fs, (DOS_BS *)fs->buf))) { 15138451Smsmith (void)dosunmount(fs); 15238451Smsmith return(err); 15338451Smsmith } 15438451Smsmith return 0; 15538451Smsmith} 15638451Smsmith 15738451Smsmith/* 15838451Smsmith * Unmount mounted filesystem 15938451Smsmith */ 16038451Smsmithstatic int 16138451Smsmithdos_unmount(DOS_FS *fs) 16238451Smsmith{ 16338451Smsmith int err; 16438451Smsmith 16538451Smsmith if (fs->links) 16638451Smsmith return(EBUSY); 16738451Smsmith if ((err = dosunmount(fs))) 16838451Smsmith return(err); 16938451Smsmith return 0; 17038451Smsmith} 17138451Smsmith 17238451Smsmith/* 17338451Smsmith * Common code shared by dos_mount() and dos_unmount() 17438451Smsmith */ 17538451Smsmithstatic int 17638451Smsmithdosunmount(DOS_FS *fs) 17738451Smsmith{ 17838451Smsmith if (fs->buf) 17938582Srnordier free(fs->buf); 18038582Srnordier free(fs); 18138451Smsmith return(0); 18238451Smsmith} 18338451Smsmith 18438451Smsmith/* 18538451Smsmith * Open DOS file 18638451Smsmith */ 18738451Smsmithstatic int 18840005Smsmithdos_open(const char *path, struct open_file *fd) 18938451Smsmith{ 19038451Smsmith DOS_DE *de; 19138451Smsmith DOS_FILE *f; 19238451Smsmith DOS_FS *fs; 19338451Smsmith u_int size, clus; 19438451Smsmith int err = 0; 19538451Smsmith 19638451Smsmith /* Allocate mount structure, associate with open */ 19738582Srnordier fs = malloc(sizeof(DOS_FS)); 19838451Smsmith 19938451Smsmith if ((err = dos_mount(fs, fd))) 20038451Smsmith goto out; 20138451Smsmith 20238451Smsmith if ((err = namede(fs, path, &de))) 20338451Smsmith goto out; 20438451Smsmith 20538451Smsmith clus = stclus(fs->fatsz, de); 20638451Smsmith size = cv4(de->size); 20738582Srnordier 20838582Srnordier if ((!(de->attr & FA_DIR) && (!clus != !size)) || 20938582Srnordier ((de->attr & FA_DIR) && size) || 21038582Srnordier (clus && !okclus(fs, clus))) { 21138451Smsmith err = EINVAL; 21238451Smsmith goto out; 21338451Smsmith } 21438582Srnordier f = malloc(sizeof(DOS_FILE)); 21538451Smsmith bzero(f, sizeof(DOS_FILE)); 21638451Smsmith f->fs = fs; 21738451Smsmith fs->links++; 21838451Smsmith f->de = *de; 21938451Smsmith fd->f_fsdata = (void *)f; 22038451Smsmith 22138451Smsmith out: 22238451Smsmith return(err); 22338451Smsmith} 22438451Smsmith 22538451Smsmith/* 22638451Smsmith * Read from file 22738451Smsmith */ 22838451Smsmithstatic int 22938451Smsmithdos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) 23038451Smsmith{ 23138582Srnordier off_t size; 23238451Smsmith u_int nb, off, clus, c, cnt, n; 23338451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 23438451Smsmith int err = 0; 23538451Smsmith 23638451Smsmith nb = (u_int)nbyte; 23738582Srnordier if ((size = fsize(f->fs, &f->de)) == -1) 23838582Srnordier return EINVAL; 23938582Srnordier if (nb > (n = size - f->offset)) 24038451Smsmith nb = n; 24138451Smsmith off = f->offset; 24238451Smsmith if ((clus = stclus(f->fs->fatsz, &f->de))) 24338451Smsmith off &= f->fs->bsize - 1; 24438451Smsmith c = f->c; 24538451Smsmith cnt = nb; 24638451Smsmith while (cnt) { 24738451Smsmith n = 0; 24838451Smsmith if (!c) { 24938451Smsmith if ((c = clus)) 25038451Smsmith n = bytblk(f->fs, f->offset); 25138451Smsmith } else if (!off) 25238451Smsmith n++; 25338451Smsmith while (n--) { 25438451Smsmith if ((err = fatget(f->fs, &c))) 25538451Smsmith goto out; 25638451Smsmith if (!okclus(f->fs, c)) { 25738451Smsmith err = EINVAL; 25838451Smsmith goto out; 25938451Smsmith } 26038451Smsmith } 26138451Smsmith if (!clus || (n = f->fs->bsize - off) > cnt) 26238451Smsmith n = cnt; 26338582Srnordier if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : 26438582Srnordier secbyt(f->fs->lsndir)) + off, 26538582Srnordier buf, n))) 26638451Smsmith goto out; 26738451Smsmith f->offset += n; 26838451Smsmith f->c = c; 26938451Smsmith off = 0; 27038451Smsmith buf += n; 27138451Smsmith cnt -= n; 27238451Smsmith } 27338451Smsmith out: 27438451Smsmith if (resid) 27538582Srnordier *resid = nbyte - nb + cnt; 27638451Smsmith return(err); 27738451Smsmith} 27838451Smsmith 27938451Smsmith/* 28038451Smsmith * Reposition within file 28138451Smsmith */ 28238451Smsmithstatic off_t 28338451Smsmithdos_seek(struct open_file *fd, off_t offset, int whence) 28438451Smsmith{ 28538451Smsmith off_t off; 28638451Smsmith u_int size; 28738451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 28838451Smsmith 28938451Smsmith size = cv4(f->de.size); 29038451Smsmith switch (whence) { 29138451Smsmith case SEEK_SET: 29238451Smsmith off = 0; 29338451Smsmith break; 29438451Smsmith case SEEK_CUR: 29538451Smsmith off = f->offset; 29638451Smsmith break; 29738451Smsmith case SEEK_END: 29838451Smsmith off = size; 29938451Smsmith break; 30038451Smsmith default: 30138451Smsmith return(-1); 30238451Smsmith } 30338451Smsmith off += offset; 30438451Smsmith if (off < 0 || off > size) 30538451Smsmith return(-1); 30638451Smsmith f->offset = (u_int)off; 30738451Smsmith f->c = 0; 30838451Smsmith return(off); 30938451Smsmith} 31038451Smsmith 31138451Smsmith/* 31238451Smsmith * Close open file 31338451Smsmith */ 31438451Smsmithstatic int 31538451Smsmithdos_close(struct open_file *fd) 31638451Smsmith{ 31738451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 31838451Smsmith DOS_FS *fs = f->fs; 31938451Smsmith 32038451Smsmith f->fs->links--; 32138582Srnordier free(f); 32238451Smsmith dos_unmount(fs); 32338451Smsmith return 0; 32438451Smsmith} 32538451Smsmith 32638451Smsmith/* 32738451Smsmith * Return some stat information on a file. 32838451Smsmith */ 32938451Smsmithstatic int 33038451Smsmithdos_stat(struct open_file *fd, struct stat *sb) 33138451Smsmith{ 33238451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 33338451Smsmith 33438451Smsmith /* only important stuff */ 33538582Srnordier sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444; 33638451Smsmith sb->st_nlink = 1; 33738451Smsmith sb->st_uid = 0; 33838451Smsmith sb->st_gid = 0; 33938582Srnordier if ((sb->st_size = fsize(f->fs, &f->de)) == -1) 34038582Srnordier return EINVAL; 34138451Smsmith return (0); 34238451Smsmith} 34338451Smsmith 34438451Smsmith/* 34538451Smsmith * Parse DOS boot sector 34638451Smsmith */ 34738451Smsmithstatic int 34838451Smsmithparsebs(DOS_FS *fs, DOS_BS *bs) 34938451Smsmith{ 35038451Smsmith u_int sc; 35138451Smsmith 35238451Smsmith if ((bs->jmp[0] != 0x69 && 35338451Smsmith bs->jmp[0] != 0xe9 && 35438451Smsmith (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) || 35538451Smsmith bs->bpb.media < 0xf0) 35638451Smsmith return EINVAL; 35738451Smsmith if (cv2(bs->bpb.secsiz) != SECSIZ) 35838451Smsmith return EINVAL; 35938451Smsmith if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1)) 36038451Smsmith return EINVAL; 36138451Smsmith fs->bsize = secbyt(fs->spc); 36238451Smsmith fs->bshift = ffs(fs->bsize) - 1; 36338451Smsmith if ((fs->spf = cv2(bs->bpb.spf))) { 36438451Smsmith if (bs->bpb.fats != 2) 36538451Smsmith return EINVAL; 36638451Smsmith if (!(fs->dirents = cv2(bs->bpb.dirents))) 36738451Smsmith return EINVAL; 36838451Smsmith } else { 36938451Smsmith if (!(fs->spf = cv4(bs->bpb.lspf))) 37038451Smsmith return EINVAL; 37138451Smsmith if (!bs->bpb.fats || bs->bpb.fats > 16) 37238451Smsmith return EINVAL; 37338451Smsmith if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS) 37438451Smsmith return EINVAL; 37538451Smsmith } 37638451Smsmith if (!(fs->lsnfat = cv2(bs->bpb.ressec))) 37738451Smsmith return EINVAL; 37838451Smsmith fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats; 37938451Smsmith fs->lsndta = fs->lsndir + entsec(fs->dirents); 38038451Smsmith if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs))) 38138451Smsmith return EINVAL; 38238451Smsmith if (fs->lsndta > sc) 38338451Smsmith return EINVAL; 38438451Smsmith if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS) 38538451Smsmith return EINVAL; 38638451Smsmith fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32; 38738451Smsmith sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1; 38838451Smsmith if (fs->xclus > sc) 38938451Smsmith fs->xclus = sc; 39038451Smsmith return 0; 39138451Smsmith} 39238451Smsmith 39338451Smsmith/* 39438451Smsmith * Return directory entry from path 39538451Smsmith */ 39638451Smsmithstatic int 39738451Smsmithnamede(DOS_FS *fs, const char *path, DOS_DE **dep) 39838451Smsmith{ 39938451Smsmith char name[256]; 40038451Smsmith DOS_DE *de; 40138451Smsmith char *s; 40238451Smsmith size_t n; 40338451Smsmith int err; 40438451Smsmith 40538451Smsmith err = 0; 40638451Smsmith de = dot; 40738451Smsmith if (*path == '/') 40838451Smsmith path++; 40938451Smsmith while (*path) { 41038451Smsmith if (!(s = strchr(path, '/'))) 41138451Smsmith s = strchr(path, 0); 41238451Smsmith if ((n = s - path) > 255) 41338451Smsmith return ENAMETOOLONG; 41438451Smsmith memcpy(name, path, n); 41538451Smsmith name[n] = 0; 41638451Smsmith path = s; 41738451Smsmith if (!(de->attr & FA_DIR)) 41838451Smsmith return ENOTDIR; 41938451Smsmith if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de))) 42038451Smsmith return err; 42138451Smsmith if (*path == '/') 42238451Smsmith path++; 42338451Smsmith } 42438451Smsmith *dep = de; 42538451Smsmith return 0; 42638451Smsmith} 42738451Smsmith 42838451Smsmith/* 42938451Smsmith * Lookup path segment 43038451Smsmith */ 43138451Smsmithstatic int 43238451Smsmithlookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep) 43338451Smsmith{ 43438451Smsmith static DOS_DIR dir[DEPSEC]; 43538451Smsmith u_char lfn[261]; 43638451Smsmith u_char sfn[13]; 43738451Smsmith u_int nsec, lsec, xdn, chk, sec, ent, x; 43838451Smsmith int err, ok, i; 43938451Smsmith 44038451Smsmith if (!clus) 44138451Smsmith for (ent = 0; ent < 2; ent++) 44238451Smsmith if (!strcasecmp(name, dotstr[ent])) { 44338451Smsmith *dep = dot + ent; 44438451Smsmith return 0; 44538451Smsmith } 44638451Smsmith if (!clus && fs->fatsz == 32) 44738451Smsmith clus = fs->rdcl; 44838451Smsmith nsec = !clus ? entsec(fs->dirents) : fs->spc; 44938451Smsmith lsec = 0; 45038451Smsmith xdn = chk = 0; 45138451Smsmith for (;;) { 45238451Smsmith if (!clus && !lsec) 45338451Smsmith lsec = fs->lsndir; 45438451Smsmith else if (okclus(fs, clus)) 45538451Smsmith lsec = blklsn(fs, clus); 45638451Smsmith else 45738451Smsmith return EINVAL; 45838451Smsmith for (sec = 0; sec < nsec; sec++) { 45938451Smsmith if ((err = ioget(fs->fd, lsec + sec, dir, 1))) 46038451Smsmith return err; 46138451Smsmith for (ent = 0; ent < DEPSEC; ent++) { 46238451Smsmith if (!*dir[ent].de.name) 46338451Smsmith return ENOENT; 46438451Smsmith if (*dir[ent].de.name != 0xe5) 46538451Smsmith if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { 46638451Smsmith x = dir[ent].xde.seq; 46738451Smsmith if (x & 0x40 || (x + 1 == xdn && 46838451Smsmith dir[ent].xde.chk == chk)) { 46938451Smsmith if (x & 0x40) { 47038451Smsmith chk = dir[ent].xde.chk; 47138451Smsmith x &= ~0x40; 47238451Smsmith } 47338451Smsmith if (x >= 1 && x <= 20) { 47438451Smsmith cp_xdnm(lfn, &dir[ent].xde); 47538451Smsmith xdn = x; 47638451Smsmith continue; 47738451Smsmith } 47838451Smsmith } 47938451Smsmith } else if (!(dir[ent].de.attr & FA_LABEL)) { 48038451Smsmith if ((ok = xdn == 1)) { 48138451Smsmith for (x = 0, i = 0; i < 11; i++) 48238451Smsmith x = ((((x & 1) << 7) | (x >> 1)) + 48338451Smsmith dir[ent].de.name[i]) & 0xff; 48438451Smsmith ok = chk == x && 48538451Smsmith !strcasecmp(name, (const char *)lfn); 48638451Smsmith } 48738451Smsmith if (!ok) { 48838451Smsmith cp_sfn(sfn, &dir[ent].de); 48938451Smsmith ok = !strcasecmp(name, (const char *)sfn); 49038451Smsmith } 49138451Smsmith if (ok) { 49238451Smsmith *dep = &dir[ent].de; 49338451Smsmith return 0; 49438451Smsmith } 49538451Smsmith } 49638451Smsmith xdn = 0; 49738451Smsmith } 49838451Smsmith } 49938451Smsmith if (!clus) 50038451Smsmith break; 50138451Smsmith if ((err = fatget(fs, &clus))) 50238451Smsmith return err; 50338451Smsmith if (fatend(fs->fatsz, clus)) 50438451Smsmith break; 50538451Smsmith } 50638451Smsmith return ENOENT; 50738451Smsmith} 50838451Smsmith 50938451Smsmith/* 51038451Smsmith * Copy name from extended directory entry 51138451Smsmith */ 51238451Smsmithstatic void 51338451Smsmithcp_xdnm(u_char *lfn, DOS_XDE *xde) 51438451Smsmith{ 51538451Smsmith static struct { 51638451Smsmith u_int off; 51738451Smsmith u_int dim; 51838451Smsmith } ix[3] = { 51938451Smsmith {offsetof(DOS_XDE, name1), sizeof(xde->name1) / 2}, 52038451Smsmith {offsetof(DOS_XDE, name2), sizeof(xde->name2) / 2}, 52138451Smsmith {offsetof(DOS_XDE, name3), sizeof(xde->name3) / 2} 52238451Smsmith }; 52338451Smsmith u_char *p; 52438451Smsmith u_int n, x, c; 52538451Smsmith 52638451Smsmith lfn += 13 * ((xde->seq & ~0x40) - 1); 52738451Smsmith for (n = 0; n < 3; n++) 52838451Smsmith for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x; 52938451Smsmith p += 2, x--) { 53038451Smsmith if ((c = cv2(p)) && (c < 32 || c > 127)) 53138451Smsmith c = '?'; 53238451Smsmith if (!(*lfn++ = c)) 53338451Smsmith return; 53438451Smsmith } 53538451Smsmith if (xde->seq & 0x40) 53638451Smsmith *lfn = 0; 53738451Smsmith} 53838451Smsmith 53938451Smsmith/* 54038451Smsmith * Copy short filename 54138451Smsmith */ 54238451Smsmithstatic void 54338451Smsmithcp_sfn(u_char *sfn, DOS_DE *de) 54438451Smsmith{ 54538451Smsmith u_char *p; 54638451Smsmith int j, i; 54738451Smsmith 54838451Smsmith p = sfn; 54938451Smsmith if (*de->name != ' ') { 55038451Smsmith for (j = 7; de->name[j] == ' '; j--); 55138451Smsmith for (i = 0; i <= j; i++) 55238451Smsmith *p++ = de->name[i]; 55338451Smsmith if (*de->ext != ' ') { 55438451Smsmith *p++ = '.'; 55538451Smsmith for (j = 2; de->ext[j] == ' '; j--); 55638451Smsmith for (i = 0; i <= j; i++) 55738451Smsmith *p++ = de->ext[i]; 55838451Smsmith } 55938451Smsmith } 56038451Smsmith *p = 0; 56138451Smsmith if (*sfn == 5) 56238451Smsmith *sfn = 0xe5; 56338451Smsmith} 56438451Smsmith 56538451Smsmith/* 56638582Srnordier * Return size of file in bytes 56738582Srnordier */ 56838582Srnordierstatic off_t 56938582Srnordierfsize(DOS_FS *fs, DOS_DE *de) 57038582Srnordier{ 57138582Srnordier u_long size; 57238582Srnordier u_int c; 57338582Srnordier int n; 57438582Srnordier 57538582Srnordier if (!(size = cv4(de->size)) && de->attr & FA_DIR) 57638582Srnordier if (!(c = cv2(de->clus))) 57738582Srnordier size = fs->dirents * sizeof(DOS_DE); 57838582Srnordier else { 57938582Srnordier if ((n = fatcnt(fs, c)) == -1) 58038582Srnordier return n; 58138582Srnordier size = blkbyt(fs, n); 58238582Srnordier } 58338582Srnordier return size; 58438582Srnordier} 58538582Srnordier 58638582Srnordier/* 58738582Srnordier * Count number of clusters in chain 58838582Srnordier */ 58938582Srnordierstatic int 59038582Srnordierfatcnt(DOS_FS *fs, u_int c) 59138582Srnordier{ 59238582Srnordier int n; 59338582Srnordier 59438582Srnordier for (n = 0; okclus(fs, c); n++) 59538582Srnordier if (fatget(fs, &c)) 59638582Srnordier return -1; 59738582Srnordier return fatend(fs->fatsz, c) ? n : -1; 59838582Srnordier} 59938582Srnordier 60038582Srnordier/* 60138451Smsmith * Get next cluster in cluster chain 60238451Smsmith */ 60338451Smsmithstatic int 60438451Smsmithfatget(DOS_FS *fs, u_int *c) 60538451Smsmith{ 60638451Smsmith u_char buf[4]; 60738451Smsmith u_int x; 60838451Smsmith int err; 60938451Smsmith 61038451Smsmith err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, 61138451Smsmith fs->fatsz != 32 ? 2 : 4); 61238451Smsmith if (err) 61338451Smsmith return err; 61438451Smsmith x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); 61538451Smsmith *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; 61638451Smsmith return 0; 61738451Smsmith} 61838451Smsmith 61938451Smsmith/* 62038451Smsmith * Is cluster an end-of-chain marker? 62138451Smsmith */ 62238451Smsmithstatic int 62338451Smsmithfatend(u_int sz, u_int c) 62438451Smsmith{ 62538451Smsmith return c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7); 62638451Smsmith} 62738451Smsmith 62838451Smsmith/* 62938451Smsmith * Offset-based I/O primitive 63038451Smsmith */ 63138451Smsmithstatic int 63238451Smsmithioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte) 63338451Smsmith{ 63438451Smsmith char *s; 63538451Smsmith u_int off, n; 63638451Smsmith int err; 63738451Smsmith 63838451Smsmith s = buf; 63938451Smsmith if ((off = offset & (SECSIZ - 1))) { 64038451Smsmith offset -= off; 64138451Smsmith if ((err = iobuf(fs, bytsec(offset)))) 64238451Smsmith return err; 64338451Smsmith offset += SECSIZ; 64438451Smsmith if ((n = SECSIZ - off) > nbyte) 64538451Smsmith n = nbyte; 64638451Smsmith memcpy(s, fs->buf + off, n); 64738451Smsmith s += n; 64838451Smsmith nbyte -= n; 64938451Smsmith } 65038451Smsmith n = nbyte & (SECSIZ - 1); 65138451Smsmith if (nbyte -= n) { 65238451Smsmith if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte)))) 65338451Smsmith return err; 65438451Smsmith offset += nbyte; 65538451Smsmith s += nbyte; 65638451Smsmith } 65738451Smsmith if (n) { 65838451Smsmith if ((err = iobuf(fs, bytsec(offset)))) 65938451Smsmith return err; 66038451Smsmith memcpy(s, fs->buf, n); 66138451Smsmith } 66238451Smsmith return 0; 66338451Smsmith} 66438451Smsmith 66538451Smsmith/* 66638451Smsmith * Buffered sector-based I/O primitive 66738451Smsmith */ 66838451Smsmithstatic int 66938451Smsmithiobuf(DOS_FS *fs, u_int lsec) 67038451Smsmith{ 67138451Smsmith int err; 67238451Smsmith 67338451Smsmith if (fs->bufsec != lsec) { 67438451Smsmith if ((err = ioget(fs->fd, lsec, fs->buf, 1))) 67538451Smsmith return err; 67638451Smsmith fs->bufsec = lsec; 67738451Smsmith } 67838451Smsmith return 0; 67938451Smsmith} 68038451Smsmith 68138451Smsmith/* 68238451Smsmith * Sector-based I/O primitive 68338451Smsmith */ 68438451Smsmithstatic int 68538451Smsmithioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec) 68638451Smsmith{ 68738451Smsmith int err; 68838451Smsmith 68938451Smsmith if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, 69038451Smsmith secbyt(nsec), buf, NULL))) 69138451Smsmith return(err); 69238451Smsmith return(0); 69338451Smsmith} 694