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 2884221Sdillon#include <sys/cdefs.h> 2984221Sdillon__FBSDID("$FreeBSD$"); 3084221Sdillon 3138451Smsmith/* 3238451Smsmith * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, 3338451Smsmith * also supports VFAT. 3438451Smsmith */ 3538451Smsmith 3638451Smsmith#include <sys/types.h> 3738451Smsmith#include <string.h> 3838451Smsmith#include <stddef.h> 3938451Smsmith 4038451Smsmith#include "stand.h" 4138451Smsmith 4238451Smsmith#include "dosfs.h" 4338451Smsmith 4438451Smsmith 4540005Smsmithstatic int dos_open(const char *path, struct open_file *fd); 4638451Smsmithstatic int dos_close(struct open_file *fd); 4738451Smsmithstatic int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid); 4838451Smsmithstatic off_t dos_seek(struct open_file *fd, off_t offset, int whence); 4938451Smsmithstatic int dos_stat(struct open_file *fd, struct stat *sb); 50201937Smarcelstatic int dos_readdir(struct open_file *fd, struct dirent *d); 5138451Smsmith 5238582Srnordierstruct fs_ops dosfs_fsops = { 5359766Sjlemon "dosfs", 5459766Sjlemon dos_open, 5559766Sjlemon dos_close, 5659766Sjlemon dos_read, 5759766Sjlemon null_write, 5859766Sjlemon dos_seek, 5959766Sjlemon dos_stat, 60201937Smarcel dos_readdir 6138451Smsmith}; 6238451Smsmith 6338451Smsmith#define SECSIZ 512 /* sector size */ 6438451Smsmith#define SSHIFT 9 /* SECSIZ shift */ 6538451Smsmith#define DEPSEC 16 /* directory entries per sector */ 6638451Smsmith#define DSHIFT 4 /* DEPSEC shift */ 6738451Smsmith#define LOCLUS 2 /* lowest cluster number */ 6838451Smsmith 6938451Smsmith/* DOS "BIOS Parameter Block" */ 7038451Smsmithtypedef struct { 7138451Smsmith u_char secsiz[2]; /* sector size */ 7238451Smsmith u_char spc; /* sectors per cluster */ 7338451Smsmith u_char ressec[2]; /* reserved sectors */ 7438451Smsmith u_char fats; /* FATs */ 7538451Smsmith u_char dirents[2]; /* root directory entries */ 7638451Smsmith u_char secs[2]; /* total sectors */ 7738451Smsmith u_char media; /* media descriptor */ 7838451Smsmith u_char spf[2]; /* sectors per FAT */ 7938451Smsmith u_char spt[2]; /* sectors per track */ 8038451Smsmith u_char heads[2]; /* drive heads */ 8138451Smsmith u_char hidsec[4]; /* hidden sectors */ 8238451Smsmith u_char lsecs[4]; /* huge sectors */ 8338451Smsmith u_char lspf[4]; /* huge sectors per FAT */ 8438451Smsmith u_char xflg[2]; /* flags */ 8538451Smsmith u_char vers[2]; /* filesystem version */ 8638451Smsmith u_char rdcl[4]; /* root directory start cluster */ 8738451Smsmith u_char infs[2]; /* filesystem info sector */ 8838451Smsmith u_char bkbs[2]; /* backup boot sector */ 8938451Smsmith} DOS_BPB; 9038451Smsmith 9138451Smsmith/* Initial portion of DOS boot sector */ 9238451Smsmithtypedef struct { 9338451Smsmith u_char jmp[3]; /* usually 80x86 'jmp' opcode */ 9438451Smsmith u_char oem[8]; /* OEM name and version */ 9538451Smsmith DOS_BPB bpb; /* BPB */ 9638451Smsmith} DOS_BS; 9738451Smsmith 9838451Smsmith/* Supply missing "." and ".." root directory entries */ 9938451Smsmithstatic const char *const dotstr[2] = {".", ".."}; 10038451Smsmithstatic DOS_DE dot[2] = { 10138451Smsmith {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 10238451Smsmith {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}, 10338451Smsmith {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 10438451Smsmith {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}} 10538451Smsmith}; 10638451Smsmith 10738451Smsmith/* The usual conversion macros to avoid multiplication and division */ 10838451Smsmith#define bytsec(n) ((n) >> SSHIFT) 10938451Smsmith#define secbyt(s) ((s) << SSHIFT) 11038451Smsmith#define entsec(e) ((e) >> DSHIFT) 11138451Smsmith#define bytblk(fs, n) ((n) >> (fs)->bshift) 11238451Smsmith#define blkbyt(fs, b) ((b) << (fs)->bshift) 11338451Smsmith#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT)) 11438451Smsmith#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT)) 11538451Smsmith 11638451Smsmith/* Convert cluster number to offset within filesystem */ 11738451Smsmith#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS)) 11838451Smsmith 11938451Smsmith/* Convert cluster number to logical sector number */ 12038451Smsmith#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS)) 12138451Smsmith 12238451Smsmith/* Convert cluster number to offset within FAT */ 12338451Smsmith#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \ 12438451Smsmith (sz) == 16 ? (c) << 1 : \ 12538451Smsmith (c) << 2) 12638451Smsmith 12738451Smsmith/* Does cluster number reference a valid data cluster? */ 12838451Smsmith#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) 12938451Smsmith 13038451Smsmith/* Get start cluster from directory entry */ 13138451Smsmith#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ 13238451Smsmith ((u_int)cv2((de)->dex.h_clus) << 16) | \ 13338451Smsmith cv2((de)->clus)) 13438451Smsmith 13538451Smsmithstatic int dosunmount(DOS_FS *); 13638451Smsmithstatic int parsebs(DOS_FS *, DOS_BS *); 13738451Smsmithstatic int namede(DOS_FS *, const char *, DOS_DE **); 13838451Smsmithstatic int lookup(DOS_FS *, u_int, const char *, DOS_DE **); 13938451Smsmithstatic void cp_xdnm(u_char *, DOS_XDE *); 14038451Smsmithstatic void cp_sfn(u_char *, DOS_DE *); 14138582Srnordierstatic off_t fsize(DOS_FS *, DOS_DE *); 14238582Srnordierstatic int fatcnt(DOS_FS *, u_int); 14338451Smsmithstatic int fatget(DOS_FS *, u_int *); 14438451Smsmithstatic int fatend(u_int, u_int); 14538451Smsmithstatic int ioread(DOS_FS *, u_int, void *, u_int); 14638451Smsmithstatic int iobuf(DOS_FS *, u_int); 14738451Smsmithstatic int ioget(struct open_file *, u_int, void *, u_int); 14838451Smsmith 14938451Smsmith/* 15038451Smsmith * Mount DOS filesystem 15138451Smsmith */ 15238451Smsmithstatic int 15338451Smsmithdos_mount(DOS_FS *fs, struct open_file *fd) 15438451Smsmith{ 15538451Smsmith int err; 15638451Smsmith 15738451Smsmith bzero(fs, sizeof(DOS_FS)); 15838451Smsmith fs->fd = fd; 15938582Srnordier if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) || 16038451Smsmith (err = ioget(fs->fd, 0, fs->buf, 1)) || 16138451Smsmith (err = parsebs(fs, (DOS_BS *)fs->buf))) { 16238451Smsmith (void)dosunmount(fs); 16338451Smsmith return(err); 16438451Smsmith } 16538451Smsmith return 0; 16638451Smsmith} 16738451Smsmith 16838451Smsmith/* 16938451Smsmith * Unmount mounted filesystem 17038451Smsmith */ 17138451Smsmithstatic int 17238451Smsmithdos_unmount(DOS_FS *fs) 17338451Smsmith{ 17438451Smsmith int err; 17538451Smsmith 17638451Smsmith if (fs->links) 17738451Smsmith return(EBUSY); 17838451Smsmith if ((err = dosunmount(fs))) 17938451Smsmith return(err); 18038451Smsmith return 0; 18138451Smsmith} 18238451Smsmith 18338451Smsmith/* 18438451Smsmith * Common code shared by dos_mount() and dos_unmount() 18538451Smsmith */ 18638451Smsmithstatic int 18738451Smsmithdosunmount(DOS_FS *fs) 18838451Smsmith{ 18938451Smsmith if (fs->buf) 19038582Srnordier free(fs->buf); 19138582Srnordier free(fs); 19238451Smsmith return(0); 19338451Smsmith} 19438451Smsmith 19538451Smsmith/* 19638451Smsmith * Open DOS file 19738451Smsmith */ 19838451Smsmithstatic int 19940005Smsmithdos_open(const char *path, struct open_file *fd) 20038451Smsmith{ 20138451Smsmith DOS_DE *de; 20238451Smsmith DOS_FILE *f; 20338451Smsmith DOS_FS *fs; 20438451Smsmith u_int size, clus; 20538451Smsmith int err = 0; 20638451Smsmith 20738451Smsmith /* Allocate mount structure, associate with open */ 20838582Srnordier fs = malloc(sizeof(DOS_FS)); 20938451Smsmith 21038451Smsmith if ((err = dos_mount(fs, fd))) 21138451Smsmith goto out; 21238451Smsmith 21338451Smsmith if ((err = namede(fs, path, &de))) 21438451Smsmith goto out; 21538451Smsmith 21638451Smsmith clus = stclus(fs->fatsz, de); 21738451Smsmith size = cv4(de->size); 21838582Srnordier 21938582Srnordier if ((!(de->attr & FA_DIR) && (!clus != !size)) || 22038582Srnordier ((de->attr & FA_DIR) && size) || 22138582Srnordier (clus && !okclus(fs, clus))) { 22238451Smsmith err = EINVAL; 22338451Smsmith goto out; 22438451Smsmith } 22538582Srnordier f = malloc(sizeof(DOS_FILE)); 22638451Smsmith bzero(f, sizeof(DOS_FILE)); 22738451Smsmith f->fs = fs; 22838451Smsmith fs->links++; 22938451Smsmith f->de = *de; 23038451Smsmith fd->f_fsdata = (void *)f; 23138451Smsmith 23238451Smsmith out: 23338451Smsmith return(err); 23438451Smsmith} 23538451Smsmith 23638451Smsmith/* 23738451Smsmith * Read from file 23838451Smsmith */ 23938451Smsmithstatic int 24038451Smsmithdos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) 24138451Smsmith{ 24238582Srnordier off_t size; 24338451Smsmith u_int nb, off, clus, c, cnt, n; 24438451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 24538451Smsmith int err = 0; 24638451Smsmith 24738451Smsmith nb = (u_int)nbyte; 24838582Srnordier if ((size = fsize(f->fs, &f->de)) == -1) 24938582Srnordier return EINVAL; 25038582Srnordier if (nb > (n = size - f->offset)) 25138451Smsmith nb = n; 25238451Smsmith off = f->offset; 25338451Smsmith if ((clus = stclus(f->fs->fatsz, &f->de))) 25438451Smsmith off &= f->fs->bsize - 1; 25538451Smsmith c = f->c; 25638451Smsmith cnt = nb; 25738451Smsmith while (cnt) { 25838451Smsmith n = 0; 25938451Smsmith if (!c) { 26038451Smsmith if ((c = clus)) 26138451Smsmith n = bytblk(f->fs, f->offset); 26238451Smsmith } else if (!off) 26338451Smsmith n++; 26438451Smsmith while (n--) { 26538451Smsmith if ((err = fatget(f->fs, &c))) 26638451Smsmith goto out; 26738451Smsmith if (!okclus(f->fs, c)) { 26838451Smsmith err = EINVAL; 26938451Smsmith goto out; 27038451Smsmith } 27138451Smsmith } 27238451Smsmith if (!clus || (n = f->fs->bsize - off) > cnt) 27338451Smsmith n = cnt; 27438582Srnordier if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : 27538582Srnordier secbyt(f->fs->lsndir)) + off, 27638582Srnordier buf, n))) 27738451Smsmith goto out; 27838451Smsmith f->offset += n; 27938451Smsmith f->c = c; 28038451Smsmith off = 0; 281136093Sstefanf buf = (char *)buf + n; 28238451Smsmith cnt -= n; 28338451Smsmith } 28438451Smsmith out: 28538451Smsmith if (resid) 28638582Srnordier *resid = nbyte - nb + cnt; 28738451Smsmith return(err); 28838451Smsmith} 28938451Smsmith 29038451Smsmith/* 29138451Smsmith * Reposition within file 29238451Smsmith */ 29338451Smsmithstatic off_t 29438451Smsmithdos_seek(struct open_file *fd, off_t offset, int whence) 29538451Smsmith{ 29638451Smsmith off_t off; 29738451Smsmith u_int size; 29838451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 29938451Smsmith 30038451Smsmith size = cv4(f->de.size); 30138451Smsmith switch (whence) { 30238451Smsmith case SEEK_SET: 30338451Smsmith off = 0; 30438451Smsmith break; 30538451Smsmith case SEEK_CUR: 30638451Smsmith off = f->offset; 30738451Smsmith break; 30838451Smsmith case SEEK_END: 30938451Smsmith off = size; 31038451Smsmith break; 31138451Smsmith default: 312124811Sjhb errno = EINVAL; 31338451Smsmith return(-1); 31438451Smsmith } 31538451Smsmith off += offset; 316124811Sjhb if (off < 0 || off > size) { 317124811Sjhb errno = EINVAL; 31838451Smsmith return(-1); 319124811Sjhb } 32038451Smsmith f->offset = (u_int)off; 32138451Smsmith f->c = 0; 32238451Smsmith return(off); 32338451Smsmith} 32438451Smsmith 32538451Smsmith/* 32638451Smsmith * Close open file 32738451Smsmith */ 32838451Smsmithstatic int 32938451Smsmithdos_close(struct open_file *fd) 33038451Smsmith{ 33138451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 33238451Smsmith DOS_FS *fs = f->fs; 33338451Smsmith 33438451Smsmith f->fs->links--; 33538582Srnordier free(f); 33638451Smsmith dos_unmount(fs); 33738451Smsmith return 0; 33838451Smsmith} 33938451Smsmith 34038451Smsmith/* 34138451Smsmith * Return some stat information on a file. 34238451Smsmith */ 34338451Smsmithstatic int 34438451Smsmithdos_stat(struct open_file *fd, struct stat *sb) 34538451Smsmith{ 34638451Smsmith DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 34738451Smsmith 34838451Smsmith /* only important stuff */ 34938582Srnordier sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444; 35038451Smsmith sb->st_nlink = 1; 35138451Smsmith sb->st_uid = 0; 35238451Smsmith sb->st_gid = 0; 35338582Srnordier if ((sb->st_size = fsize(f->fs, &f->de)) == -1) 35438582Srnordier return EINVAL; 35538451Smsmith return (0); 35638451Smsmith} 35738451Smsmith 358201937Smarcelstatic int 359201937Smarceldos_readdir(struct open_file *fd, struct dirent *d) 360201937Smarcel{ 361221365Srodrigc /* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */ 362201937Smarcel u_char fn[261]; 363201937Smarcel DOS_DIR dd; 364201937Smarcel size_t res; 365201937Smarcel u_int chk, i, x, xdn; 366201937Smarcel int err; 367201937Smarcel 368201937Smarcel x = chk = 0; 369201937Smarcel while (1) { 370201937Smarcel xdn = x; 371201937Smarcel x = 0; 372201937Smarcel err = dos_read(fd, &dd, sizeof(dd), &res); 373201937Smarcel if (err) 374201937Smarcel return (err); 375201937Smarcel if (res == sizeof(dd)) 376201937Smarcel return (ENOENT); 377201937Smarcel if (dd.de.name[0] == 0) 378201937Smarcel return (ENOENT); 379201937Smarcel 380201937Smarcel /* Skip deleted entries */ 381201937Smarcel if (dd.de.name[0] == 0xe5) 382201937Smarcel continue; 383201937Smarcel 384201937Smarcel /* Skip volume labels */ 385201937Smarcel if (dd.de.attr & FA_LABEL) 386201937Smarcel continue; 387201937Smarcel 388201937Smarcel if ((dd.de.attr & FA_MASK) == FA_XDE) { 389201937Smarcel if (dd.xde.seq & 0x40) 390201937Smarcel chk = dd.xde.chk; 391201937Smarcel else if (dd.xde.seq != xdn - 1 || dd.xde.chk != chk) 392201937Smarcel continue; 393201937Smarcel x = dd.xde.seq & ~0x40; 394201937Smarcel if (x < 1 || x > 20) { 395201937Smarcel x = 0; 396201937Smarcel continue; 397201937Smarcel } 398201937Smarcel cp_xdnm(fn, &dd.xde); 399201937Smarcel } else { 400201937Smarcel if (xdn == 1) { 401201937Smarcel x = 0; 402201937Smarcel for (i = 0; i < 11; i++) { 403201937Smarcel x = ((x & 1) << 7) | (x >> 1); 404201937Smarcel x += dd.de.name[i]; 405201937Smarcel x &= 0xff; 406201937Smarcel } 407201937Smarcel if (x == chk) 408201937Smarcel break; 409201937Smarcel } else { 410201937Smarcel cp_sfn(fn, &dd.de); 411201937Smarcel break; 412201937Smarcel } 413201937Smarcel x = 0; 414201937Smarcel } 415201937Smarcel } 416201937Smarcel 417221365Srodrigc d->d_fileno = (dd.de.clus[1] << 8) + dd.de.clus[0]; 418201937Smarcel d->d_reclen = sizeof(*d); 419201937Smarcel d->d_type = (dd.de.attr & FA_DIR) ? DT_DIR : DT_REG; 420201937Smarcel memcpy(d->d_name, fn, sizeof(d->d_name)); 421201937Smarcel return(0); 422201937Smarcel} 423201937Smarcel 42438451Smsmith/* 42538451Smsmith * Parse DOS boot sector 42638451Smsmith */ 42738451Smsmithstatic int 42838451Smsmithparsebs(DOS_FS *fs, DOS_BS *bs) 42938451Smsmith{ 43038451Smsmith u_int sc; 43138451Smsmith 43238451Smsmith if ((bs->jmp[0] != 0x69 && 43338451Smsmith bs->jmp[0] != 0xe9 && 43438451Smsmith (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) || 43538451Smsmith bs->bpb.media < 0xf0) 43638451Smsmith return EINVAL; 43738451Smsmith if (cv2(bs->bpb.secsiz) != SECSIZ) 43838451Smsmith return EINVAL; 43938451Smsmith if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1)) 44038451Smsmith return EINVAL; 44138451Smsmith fs->bsize = secbyt(fs->spc); 44238451Smsmith fs->bshift = ffs(fs->bsize) - 1; 44338451Smsmith if ((fs->spf = cv2(bs->bpb.spf))) { 44438451Smsmith if (bs->bpb.fats != 2) 44538451Smsmith return EINVAL; 44638451Smsmith if (!(fs->dirents = cv2(bs->bpb.dirents))) 44738451Smsmith return EINVAL; 44838451Smsmith } else { 44938451Smsmith if (!(fs->spf = cv4(bs->bpb.lspf))) 45038451Smsmith return EINVAL; 45138451Smsmith if (!bs->bpb.fats || bs->bpb.fats > 16) 45238451Smsmith return EINVAL; 45338451Smsmith if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS) 45438451Smsmith return EINVAL; 45538451Smsmith } 45638451Smsmith if (!(fs->lsnfat = cv2(bs->bpb.ressec))) 45738451Smsmith return EINVAL; 45838451Smsmith fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats; 45938451Smsmith fs->lsndta = fs->lsndir + entsec(fs->dirents); 46038451Smsmith if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs))) 46138451Smsmith return EINVAL; 46238451Smsmith if (fs->lsndta > sc) 46338451Smsmith return EINVAL; 46438451Smsmith if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS) 46538451Smsmith return EINVAL; 46638451Smsmith fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32; 46738451Smsmith sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1; 46838451Smsmith if (fs->xclus > sc) 46938451Smsmith fs->xclus = sc; 47038451Smsmith return 0; 47138451Smsmith} 47238451Smsmith 47338451Smsmith/* 47438451Smsmith * Return directory entry from path 47538451Smsmith */ 47638451Smsmithstatic int 47738451Smsmithnamede(DOS_FS *fs, const char *path, DOS_DE **dep) 47838451Smsmith{ 47938451Smsmith char name[256]; 48038451Smsmith DOS_DE *de; 48138451Smsmith char *s; 48238451Smsmith size_t n; 48338451Smsmith int err; 48438451Smsmith 48538451Smsmith err = 0; 48638451Smsmith de = dot; 48738451Smsmith if (*path == '/') 48838451Smsmith path++; 48938451Smsmith while (*path) { 49038451Smsmith if (!(s = strchr(path, '/'))) 49138451Smsmith s = strchr(path, 0); 49238451Smsmith if ((n = s - path) > 255) 49338451Smsmith return ENAMETOOLONG; 49438451Smsmith memcpy(name, path, n); 49538451Smsmith name[n] = 0; 49638451Smsmith path = s; 49738451Smsmith if (!(de->attr & FA_DIR)) 49838451Smsmith return ENOTDIR; 49938451Smsmith if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de))) 50038451Smsmith return err; 50138451Smsmith if (*path == '/') 50238451Smsmith path++; 50338451Smsmith } 50438451Smsmith *dep = de; 50538451Smsmith return 0; 50638451Smsmith} 50738451Smsmith 50838451Smsmith/* 50938451Smsmith * Lookup path segment 51038451Smsmith */ 51138451Smsmithstatic int 51238451Smsmithlookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep) 51338451Smsmith{ 51438451Smsmith static DOS_DIR dir[DEPSEC]; 51538451Smsmith u_char lfn[261]; 51638451Smsmith u_char sfn[13]; 51738451Smsmith u_int nsec, lsec, xdn, chk, sec, ent, x; 51838451Smsmith int err, ok, i; 51938451Smsmith 52038451Smsmith if (!clus) 52138451Smsmith for (ent = 0; ent < 2; ent++) 52238451Smsmith if (!strcasecmp(name, dotstr[ent])) { 52338451Smsmith *dep = dot + ent; 52438451Smsmith return 0; 52538451Smsmith } 52638451Smsmith if (!clus && fs->fatsz == 32) 52738451Smsmith clus = fs->rdcl; 52838451Smsmith nsec = !clus ? entsec(fs->dirents) : fs->spc; 52938451Smsmith lsec = 0; 53038451Smsmith xdn = chk = 0; 53138451Smsmith for (;;) { 53238451Smsmith if (!clus && !lsec) 53338451Smsmith lsec = fs->lsndir; 53438451Smsmith else if (okclus(fs, clus)) 53538451Smsmith lsec = blklsn(fs, clus); 53638451Smsmith else 53738451Smsmith return EINVAL; 53838451Smsmith for (sec = 0; sec < nsec; sec++) { 53938451Smsmith if ((err = ioget(fs->fd, lsec + sec, dir, 1))) 54038451Smsmith return err; 54138451Smsmith for (ent = 0; ent < DEPSEC; ent++) { 54238451Smsmith if (!*dir[ent].de.name) 54338451Smsmith return ENOENT; 54446079Simp if (*dir[ent].de.name != 0xe5) { 54538451Smsmith if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { 54638451Smsmith x = dir[ent].xde.seq; 54738451Smsmith if (x & 0x40 || (x + 1 == xdn && 54838451Smsmith dir[ent].xde.chk == chk)) { 54938451Smsmith if (x & 0x40) { 55038451Smsmith chk = dir[ent].xde.chk; 55138451Smsmith x &= ~0x40; 55238451Smsmith } 55338451Smsmith if (x >= 1 && x <= 20) { 55438451Smsmith cp_xdnm(lfn, &dir[ent].xde); 55538451Smsmith xdn = x; 55638451Smsmith continue; 55738451Smsmith } 55838451Smsmith } 55938451Smsmith } else if (!(dir[ent].de.attr & FA_LABEL)) { 56038451Smsmith if ((ok = xdn == 1)) { 56138451Smsmith for (x = 0, i = 0; i < 11; i++) 56238451Smsmith x = ((((x & 1) << 7) | (x >> 1)) + 56338451Smsmith dir[ent].de.name[i]) & 0xff; 56438451Smsmith ok = chk == x && 56538451Smsmith !strcasecmp(name, (const char *)lfn); 56638451Smsmith } 56738451Smsmith if (!ok) { 56838451Smsmith cp_sfn(sfn, &dir[ent].de); 56938451Smsmith ok = !strcasecmp(name, (const char *)sfn); 57038451Smsmith } 57138451Smsmith if (ok) { 57238451Smsmith *dep = &dir[ent].de; 57338451Smsmith return 0; 57438451Smsmith } 57538451Smsmith } 57646079Simp } 57738451Smsmith xdn = 0; 57838451Smsmith } 57938451Smsmith } 58038451Smsmith if (!clus) 58138451Smsmith break; 58238451Smsmith if ((err = fatget(fs, &clus))) 58338451Smsmith return err; 58438451Smsmith if (fatend(fs->fatsz, clus)) 58538451Smsmith break; 58638451Smsmith } 58738451Smsmith return ENOENT; 58838451Smsmith} 58938451Smsmith 59038451Smsmith/* 59138451Smsmith * Copy name from extended directory entry 59238451Smsmith */ 59338451Smsmithstatic void 59438451Smsmithcp_xdnm(u_char *lfn, DOS_XDE *xde) 59538451Smsmith{ 59638451Smsmith static struct { 59738451Smsmith u_int off; 59838451Smsmith u_int dim; 59938451Smsmith } ix[3] = { 60038451Smsmith {offsetof(DOS_XDE, name1), sizeof(xde->name1) / 2}, 60138451Smsmith {offsetof(DOS_XDE, name2), sizeof(xde->name2) / 2}, 60238451Smsmith {offsetof(DOS_XDE, name3), sizeof(xde->name3) / 2} 60338451Smsmith }; 60438451Smsmith u_char *p; 60538451Smsmith u_int n, x, c; 60638451Smsmith 60738451Smsmith lfn += 13 * ((xde->seq & ~0x40) - 1); 60838451Smsmith for (n = 0; n < 3; n++) 60938451Smsmith for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x; 61038451Smsmith p += 2, x--) { 61138451Smsmith if ((c = cv2(p)) && (c < 32 || c > 127)) 61238451Smsmith c = '?'; 61338451Smsmith if (!(*lfn++ = c)) 61438451Smsmith return; 61538451Smsmith } 61638451Smsmith if (xde->seq & 0x40) 61738451Smsmith *lfn = 0; 61838451Smsmith} 61938451Smsmith 62038451Smsmith/* 62138451Smsmith * Copy short filename 62238451Smsmith */ 62338451Smsmithstatic void 62438451Smsmithcp_sfn(u_char *sfn, DOS_DE *de) 62538451Smsmith{ 62638451Smsmith u_char *p; 62738451Smsmith int j, i; 62838451Smsmith 62938451Smsmith p = sfn; 63038451Smsmith if (*de->name != ' ') { 63138451Smsmith for (j = 7; de->name[j] == ' '; j--); 63238451Smsmith for (i = 0; i <= j; i++) 63338451Smsmith *p++ = de->name[i]; 63438451Smsmith if (*de->ext != ' ') { 63538451Smsmith *p++ = '.'; 63638451Smsmith for (j = 2; de->ext[j] == ' '; j--); 63738451Smsmith for (i = 0; i <= j; i++) 63838451Smsmith *p++ = de->ext[i]; 63938451Smsmith } 64038451Smsmith } 64138451Smsmith *p = 0; 64238451Smsmith if (*sfn == 5) 64338451Smsmith *sfn = 0xe5; 64438451Smsmith} 64538451Smsmith 64638451Smsmith/* 64738582Srnordier * Return size of file in bytes 64838582Srnordier */ 64938582Srnordierstatic off_t 65038582Srnordierfsize(DOS_FS *fs, DOS_DE *de) 65138582Srnordier{ 65238582Srnordier u_long size; 65338582Srnordier u_int c; 65438582Srnordier int n; 65538582Srnordier 65646079Simp if (!(size = cv4(de->size)) && de->attr & FA_DIR) { 65738582Srnordier if (!(c = cv2(de->clus))) 65838582Srnordier size = fs->dirents * sizeof(DOS_DE); 65938582Srnordier else { 66038582Srnordier if ((n = fatcnt(fs, c)) == -1) 66138582Srnordier return n; 66238582Srnordier size = blkbyt(fs, n); 66338582Srnordier } 66446079Simp } 66538582Srnordier return size; 66638582Srnordier} 66738582Srnordier 66838582Srnordier/* 66938582Srnordier * Count number of clusters in chain 67038582Srnordier */ 67138582Srnordierstatic int 67238582Srnordierfatcnt(DOS_FS *fs, u_int c) 67338582Srnordier{ 67438582Srnordier int n; 67538582Srnordier 67638582Srnordier for (n = 0; okclus(fs, c); n++) 67738582Srnordier if (fatget(fs, &c)) 67838582Srnordier return -1; 67938582Srnordier return fatend(fs->fatsz, c) ? n : -1; 68038582Srnordier} 68138582Srnordier 68238582Srnordier/* 68338451Smsmith * Get next cluster in cluster chain 68438451Smsmith */ 68538451Smsmithstatic int 68638451Smsmithfatget(DOS_FS *fs, u_int *c) 68738451Smsmith{ 68838451Smsmith u_char buf[4]; 68938451Smsmith u_int x; 69038451Smsmith int err; 69138451Smsmith 69238451Smsmith err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, 69338451Smsmith fs->fatsz != 32 ? 2 : 4); 69438451Smsmith if (err) 69538451Smsmith return err; 69638451Smsmith x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); 69738451Smsmith *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; 69838451Smsmith return 0; 69938451Smsmith} 70038451Smsmith 70138451Smsmith/* 70238451Smsmith * Is cluster an end-of-chain marker? 70338451Smsmith */ 70438451Smsmithstatic int 70538451Smsmithfatend(u_int sz, u_int c) 70638451Smsmith{ 70738451Smsmith return c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7); 70838451Smsmith} 70938451Smsmith 71038451Smsmith/* 71138451Smsmith * Offset-based I/O primitive 71238451Smsmith */ 71338451Smsmithstatic int 71438451Smsmithioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte) 71538451Smsmith{ 71638451Smsmith char *s; 71738451Smsmith u_int off, n; 71838451Smsmith int err; 71938451Smsmith 72038451Smsmith s = buf; 72138451Smsmith if ((off = offset & (SECSIZ - 1))) { 72238451Smsmith offset -= off; 72338451Smsmith if ((err = iobuf(fs, bytsec(offset)))) 72438451Smsmith return err; 72538451Smsmith offset += SECSIZ; 72638451Smsmith if ((n = SECSIZ - off) > nbyte) 72738451Smsmith n = nbyte; 72838451Smsmith memcpy(s, fs->buf + off, n); 72938451Smsmith s += n; 73038451Smsmith nbyte -= n; 73138451Smsmith } 73238451Smsmith n = nbyte & (SECSIZ - 1); 73338451Smsmith if (nbyte -= n) { 73438451Smsmith if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte)))) 73538451Smsmith return err; 73638451Smsmith offset += nbyte; 73738451Smsmith s += nbyte; 73838451Smsmith } 73938451Smsmith if (n) { 74038451Smsmith if ((err = iobuf(fs, bytsec(offset)))) 74138451Smsmith return err; 74238451Smsmith memcpy(s, fs->buf, n); 74338451Smsmith } 74438451Smsmith return 0; 74538451Smsmith} 74638451Smsmith 74738451Smsmith/* 74838451Smsmith * Buffered sector-based I/O primitive 74938451Smsmith */ 75038451Smsmithstatic int 75138451Smsmithiobuf(DOS_FS *fs, u_int lsec) 75238451Smsmith{ 75338451Smsmith int err; 75438451Smsmith 75538451Smsmith if (fs->bufsec != lsec) { 75638451Smsmith if ((err = ioget(fs->fd, lsec, fs->buf, 1))) 75738451Smsmith return err; 75838451Smsmith fs->bufsec = lsec; 75938451Smsmith } 76038451Smsmith return 0; 76138451Smsmith} 76238451Smsmith 76338451Smsmith/* 76438451Smsmith * Sector-based I/O primitive 76538451Smsmith */ 76638451Smsmithstatic int 76738451Smsmithioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec) 76838451Smsmith{ 76938451Smsmith int err; 770281317Sjhb 771281317Sjhb twiddle(1); 77238451Smsmith if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, 77338451Smsmith secbyt(nsec), buf, NULL))) 77438451Smsmith return(err); 77538451Smsmith return(0); 77638451Smsmith} 777