1*0a6a1f1dSLionel Sambuc /* $NetBSD: dosfs.c,v 1.20 2014/03/20 03:13:18 christos Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /*
458a2b000SEvgeniy Ivanov * Copyright (c) 1996, 1998 Robert Nordier
558a2b000SEvgeniy Ivanov * All rights reserved.
658a2b000SEvgeniy Ivanov *
758a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
858a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
958a2b000SEvgeniy Ivanov * are met:
1058a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
1158a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
1258a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1358a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in
1458a2b000SEvgeniy Ivanov * the documentation and/or other materials provided with the
1558a2b000SEvgeniy Ivanov * distribution.
1658a2b000SEvgeniy Ivanov *
1758a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
1858a2b000SEvgeniy Ivanov * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1958a2b000SEvgeniy Ivanov * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2058a2b000SEvgeniy Ivanov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
2158a2b000SEvgeniy Ivanov * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2258a2b000SEvgeniy Ivanov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2358a2b000SEvgeniy Ivanov * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2458a2b000SEvgeniy Ivanov * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2558a2b000SEvgeniy Ivanov * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2658a2b000SEvgeniy Ivanov * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2758a2b000SEvgeniy Ivanov * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2858a2b000SEvgeniy Ivanov */
2958a2b000SEvgeniy Ivanov
3058a2b000SEvgeniy Ivanov /*
3158a2b000SEvgeniy Ivanov * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems,
3258a2b000SEvgeniy Ivanov * also supports VFAT.
3358a2b000SEvgeniy Ivanov */
3458a2b000SEvgeniy Ivanov
3558a2b000SEvgeniy Ivanov /*
3658a2b000SEvgeniy Ivanov * XXX DOES NOT SUPPORT:
3758a2b000SEvgeniy Ivanov *
3858a2b000SEvgeniy Ivanov * LIBSA_FS_SINGLECOMPONENT
3958a2b000SEvgeniy Ivanov */
4058a2b000SEvgeniy Ivanov
4158a2b000SEvgeniy Ivanov #include <sys/param.h>
4258a2b000SEvgeniy Ivanov
4358a2b000SEvgeniy Ivanov #include <fs/msdosfs/bpb.h>
4458a2b000SEvgeniy Ivanov #include <fs/msdosfs/direntry.h>
4558a2b000SEvgeniy Ivanov
4658a2b000SEvgeniy Ivanov #ifdef _STANDALONE
4758a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
4858a2b000SEvgeniy Ivanov #else
4958a2b000SEvgeniy Ivanov #include <string.h>
5058a2b000SEvgeniy Ivanov #include <stddef.h>
5158a2b000SEvgeniy Ivanov #endif
5258a2b000SEvgeniy Ivanov
5358a2b000SEvgeniy Ivanov #include "stand.h"
5458a2b000SEvgeniy Ivanov #include "dosfs.h"
5558a2b000SEvgeniy Ivanov
5658a2b000SEvgeniy Ivanov #define SECSIZ 512 /* sector size */
5758a2b000SEvgeniy Ivanov #define SSHIFT 9 /* SECSIZ shift */
5858a2b000SEvgeniy Ivanov #define DEPSEC 16 /* directory entries per sector */
5958a2b000SEvgeniy Ivanov #define DSHIFT 4 /* DEPSEC shift */
6058a2b000SEvgeniy Ivanov #define LOCLUS 2 /* lowest cluster number */
6158a2b000SEvgeniy Ivanov
6258a2b000SEvgeniy Ivanov typedef union {
6358a2b000SEvgeniy Ivanov struct direntry de; /* standard directory entry */
6458a2b000SEvgeniy Ivanov struct winentry xde; /* extended directory entry */
6558a2b000SEvgeniy Ivanov } DOS_DIR;
6658a2b000SEvgeniy Ivanov
6758a2b000SEvgeniy Ivanov typedef struct {
6858a2b000SEvgeniy Ivanov struct open_file *fd; /* file descriptor */
6958a2b000SEvgeniy Ivanov u_char *buf; /* buffer */
7058a2b000SEvgeniy Ivanov u_int bufsec; /* buffered sector */
7158a2b000SEvgeniy Ivanov u_int links; /* active links to structure */
7258a2b000SEvgeniy Ivanov u_int spc; /* sectors per cluster */
7358a2b000SEvgeniy Ivanov u_int bsize; /* cluster size in bytes */
7458a2b000SEvgeniy Ivanov u_int bshift; /* cluster conversion shift */
7558a2b000SEvgeniy Ivanov u_int dirents; /* root directory entries */
7658a2b000SEvgeniy Ivanov u_int spf; /* sectors per fat */
7758a2b000SEvgeniy Ivanov u_int rdcl; /* root directory start cluster */
7858a2b000SEvgeniy Ivanov u_int lsnfat; /* start of fat */
7958a2b000SEvgeniy Ivanov u_int lsndir; /* start of root dir */
8058a2b000SEvgeniy Ivanov u_int lsndta; /* start of data area */
8158a2b000SEvgeniy Ivanov u_int fatsz; /* FAT entry size */
8258a2b000SEvgeniy Ivanov u_int xclus; /* maximum cluster number */
8358a2b000SEvgeniy Ivanov } DOS_FS;
8458a2b000SEvgeniy Ivanov
8558a2b000SEvgeniy Ivanov typedef struct {
8658a2b000SEvgeniy Ivanov DOS_FS *fs; /* associated filesystem */
8758a2b000SEvgeniy Ivanov struct direntry de; /* directory entry */
8858a2b000SEvgeniy Ivanov u_int offset; /* current offset */
8958a2b000SEvgeniy Ivanov u_int c; /* last cluster read */
9058a2b000SEvgeniy Ivanov } DOS_FILE;
9158a2b000SEvgeniy Ivanov
9258a2b000SEvgeniy Ivanov /* Initial portion of DOS boot sector */
9358a2b000SEvgeniy Ivanov typedef struct {
9458a2b000SEvgeniy Ivanov u_char jmp[3]; /* usually 80x86 'jmp' opcode */
9558a2b000SEvgeniy Ivanov u_char oem[8]; /* OEM name and version */
9658a2b000SEvgeniy Ivanov struct byte_bpb710 bpb; /* BPB */
9758a2b000SEvgeniy Ivanov } DOS_BS;
9858a2b000SEvgeniy Ivanov
9958a2b000SEvgeniy Ivanov /* Supply missing "." and ".." root directory entries */
10058a2b000SEvgeniy Ivanov static const char *const dotstr[2] = {".", ".."};
10158a2b000SEvgeniy Ivanov static const struct direntry dot[2] = {
10258a2b000SEvgeniy Ivanov {". ", " ", ATTR_DIRECTORY,
10358a2b000SEvgeniy Ivanov 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0},
10458a2b000SEvgeniy Ivanov {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}},
10558a2b000SEvgeniy Ivanov
10658a2b000SEvgeniy Ivanov {".. ", " ", ATTR_DIRECTORY,
10758a2b000SEvgeniy Ivanov 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0},
10858a2b000SEvgeniy Ivanov {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}
10958a2b000SEvgeniy Ivanov };
11058a2b000SEvgeniy Ivanov
11158a2b000SEvgeniy Ivanov /* The usual conversion macros to avoid multiplication and division */
11258a2b000SEvgeniy Ivanov #define bytsec(n) ((n) >> SSHIFT)
11358a2b000SEvgeniy Ivanov #define secbyt(s) ((s) << SSHIFT)
11458a2b000SEvgeniy Ivanov #define entsec(e) ((e) >> DSHIFT)
11558a2b000SEvgeniy Ivanov #define bytblk(fs, n) ((n) >> (fs)->bshift)
11658a2b000SEvgeniy Ivanov #define blkbyt(fs, b) ((b) << (fs)->bshift)
11758a2b000SEvgeniy Ivanov #define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT))
11858a2b000SEvgeniy Ivanov #define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT))
11958a2b000SEvgeniy Ivanov
12058a2b000SEvgeniy Ivanov /* Convert cluster number to offset within filesystem */
12158a2b000SEvgeniy Ivanov #define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS))
12258a2b000SEvgeniy Ivanov
12358a2b000SEvgeniy Ivanov /* Convert cluster number to logical sector number */
12458a2b000SEvgeniy Ivanov #define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS))
12558a2b000SEvgeniy Ivanov
12658a2b000SEvgeniy Ivanov /* Convert cluster number to offset within FAT */
12758a2b000SEvgeniy Ivanov #define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \
12858a2b000SEvgeniy Ivanov (sz) == 16 ? (c) << 1 : \
12958a2b000SEvgeniy Ivanov (c) << 2)
13058a2b000SEvgeniy Ivanov
13158a2b000SEvgeniy Ivanov /* Does cluster number reference a valid data cluster? */
13258a2b000SEvgeniy Ivanov #define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus)
13358a2b000SEvgeniy Ivanov
13458a2b000SEvgeniy Ivanov /* Get start cluster from directory entry */
13558a2b000SEvgeniy Ivanov #define stclus(sz, de) ((sz) != 32 ? (u_int)getushort((de)->deStartCluster) : \
13658a2b000SEvgeniy Ivanov ((u_int)getushort((de)->deHighClust) << 16) | \
13758a2b000SEvgeniy Ivanov (u_int)getushort((de)->deStartCluster))
13858a2b000SEvgeniy Ivanov
13958a2b000SEvgeniy Ivanov static int dosunmount(DOS_FS *);
14058a2b000SEvgeniy Ivanov static int parsebs(DOS_FS *, DOS_BS *);
14158a2b000SEvgeniy Ivanov static int namede(DOS_FS *, const char *, const struct direntry **);
14258a2b000SEvgeniy Ivanov static int lookup(DOS_FS *, u_int, const char *, const struct direntry **);
14358a2b000SEvgeniy Ivanov static void cp_xdnm(u_char *, struct winentry *);
14458a2b000SEvgeniy Ivanov static void cp_sfn(u_char *, struct direntry *);
14558a2b000SEvgeniy Ivanov static off_t fsize(DOS_FS *, struct direntry *);
14658a2b000SEvgeniy Ivanov static int fatcnt(DOS_FS *, u_int);
14758a2b000SEvgeniy Ivanov static int fatget(DOS_FS *, u_int *);
14858a2b000SEvgeniy Ivanov static int fatend(u_int, u_int);
14958a2b000SEvgeniy Ivanov static int ioread(DOS_FS *, u_int, void *, u_int);
15058a2b000SEvgeniy Ivanov static int iobuf(DOS_FS *, u_int);
15158a2b000SEvgeniy Ivanov static int ioget(struct open_file *, u_int, void *, u_int);
15258a2b000SEvgeniy Ivanov
15358a2b000SEvgeniy Ivanov #define strcasecmp(s1, s2) dos_strcasecmp(s1, s2)
15458a2b000SEvgeniy Ivanov static int
strcasecmp(const char * s1,const char * s2)15558a2b000SEvgeniy Ivanov strcasecmp(const char *s1, const char *s2)
15658a2b000SEvgeniy Ivanov {
15758a2b000SEvgeniy Ivanov char c1, c2;
15858a2b000SEvgeniy Ivanov #define TO_UPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c) - ('a' - 'A') : (c))
15958a2b000SEvgeniy Ivanov for (;;) {
16058a2b000SEvgeniy Ivanov c1 = *s1++;
16158a2b000SEvgeniy Ivanov c2 = *s2++;
16258a2b000SEvgeniy Ivanov if (TO_UPPER(c1) != TO_UPPER(c2))
16358a2b000SEvgeniy Ivanov return 1;
16458a2b000SEvgeniy Ivanov if (c1 == 0)
16558a2b000SEvgeniy Ivanov return 0;
16658a2b000SEvgeniy Ivanov }
16758a2b000SEvgeniy Ivanov #undef TO_UPPER
16858a2b000SEvgeniy Ivanov }
16958a2b000SEvgeniy Ivanov
17058a2b000SEvgeniy Ivanov /*
17158a2b000SEvgeniy Ivanov * Mount DOS filesystem
17258a2b000SEvgeniy Ivanov */
17358a2b000SEvgeniy Ivanov static int
dos_mount(DOS_FS * fs,struct open_file * fd)17458a2b000SEvgeniy Ivanov dos_mount(DOS_FS *fs, struct open_file *fd)
17558a2b000SEvgeniy Ivanov {
17658a2b000SEvgeniy Ivanov int err;
17758a2b000SEvgeniy Ivanov
17858a2b000SEvgeniy Ivanov (void)memset(fs, 0, sizeof(DOS_FS));
17958a2b000SEvgeniy Ivanov fs->fd = fd;
18058a2b000SEvgeniy Ivanov if ((err = !(fs->buf = alloc(SECSIZ)) ? errno : 0) ||
18158a2b000SEvgeniy Ivanov (err = ioget(fs->fd, 0, fs->buf, 1)) ||
18258a2b000SEvgeniy Ivanov (err = parsebs(fs, (DOS_BS *)fs->buf))) {
18358a2b000SEvgeniy Ivanov (void) dosunmount(fs);
18458a2b000SEvgeniy Ivanov return err;
18558a2b000SEvgeniy Ivanov }
18658a2b000SEvgeniy Ivanov return 0;
18758a2b000SEvgeniy Ivanov }
18858a2b000SEvgeniy Ivanov
18958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_CLOSE
19058a2b000SEvgeniy Ivanov /*
19158a2b000SEvgeniy Ivanov * Unmount mounted filesystem
19258a2b000SEvgeniy Ivanov */
19358a2b000SEvgeniy Ivanov static int
dos_unmount(DOS_FS * fs)19458a2b000SEvgeniy Ivanov dos_unmount(DOS_FS *fs)
19558a2b000SEvgeniy Ivanov {
19658a2b000SEvgeniy Ivanov int err;
19758a2b000SEvgeniy Ivanov
19858a2b000SEvgeniy Ivanov if (fs->links)
19958a2b000SEvgeniy Ivanov return EBUSY;
20058a2b000SEvgeniy Ivanov if ((err = dosunmount(fs)))
20158a2b000SEvgeniy Ivanov return err;
20258a2b000SEvgeniy Ivanov return 0;
20358a2b000SEvgeniy Ivanov }
20458a2b000SEvgeniy Ivanov #endif
20558a2b000SEvgeniy Ivanov
20658a2b000SEvgeniy Ivanov /*
20758a2b000SEvgeniy Ivanov * Common code shared by dos_mount() and dos_unmount()
20858a2b000SEvgeniy Ivanov */
20958a2b000SEvgeniy Ivanov static int
dosunmount(DOS_FS * fs)21058a2b000SEvgeniy Ivanov dosunmount(DOS_FS *fs)
21158a2b000SEvgeniy Ivanov {
21258a2b000SEvgeniy Ivanov if (fs->buf)
21358a2b000SEvgeniy Ivanov dealloc(fs->buf, SECSIZ);
21458a2b000SEvgeniy Ivanov dealloc(fs, sizeof(DOS_FS));
21558a2b000SEvgeniy Ivanov return 0;
21658a2b000SEvgeniy Ivanov }
21758a2b000SEvgeniy Ivanov
21858a2b000SEvgeniy Ivanov /*
21958a2b000SEvgeniy Ivanov * Open DOS file
22058a2b000SEvgeniy Ivanov */
22158a2b000SEvgeniy Ivanov __compactcall int
dosfs_open(const char * path,struct open_file * fd)22258a2b000SEvgeniy Ivanov dosfs_open(const char *path, struct open_file *fd)
22358a2b000SEvgeniy Ivanov {
22458a2b000SEvgeniy Ivanov const struct direntry *de;
22558a2b000SEvgeniy Ivanov DOS_FILE *f;
22658a2b000SEvgeniy Ivanov DOS_FS *fs;
22758a2b000SEvgeniy Ivanov u_int size, clus;
22858a2b000SEvgeniy Ivanov int err = 0;
22958a2b000SEvgeniy Ivanov
23058a2b000SEvgeniy Ivanov /* Allocate mount structure, associate with open */
23158a2b000SEvgeniy Ivanov fs = alloc(sizeof(DOS_FS));
23258a2b000SEvgeniy Ivanov
23358a2b000SEvgeniy Ivanov if ((err = dos_mount(fs, fd)))
23458a2b000SEvgeniy Ivanov goto out;
23558a2b000SEvgeniy Ivanov
23658a2b000SEvgeniy Ivanov if ((err = namede(fs, path, &de)))
23758a2b000SEvgeniy Ivanov goto out;
23858a2b000SEvgeniy Ivanov
23958a2b000SEvgeniy Ivanov clus = stclus(fs->fatsz, de);
24058a2b000SEvgeniy Ivanov size = getulong(de->deFileSize);
24158a2b000SEvgeniy Ivanov
24258a2b000SEvgeniy Ivanov if ((!(de->deAttributes & ATTR_DIRECTORY) && (!clus != !size)) ||
24358a2b000SEvgeniy Ivanov ((de->deAttributes & ATTR_DIRECTORY) && size) ||
24458a2b000SEvgeniy Ivanov (clus && !okclus(fs, clus))) {
24558a2b000SEvgeniy Ivanov err = EINVAL;
24658a2b000SEvgeniy Ivanov goto out;
24758a2b000SEvgeniy Ivanov }
24858a2b000SEvgeniy Ivanov
24958a2b000SEvgeniy Ivanov f = alloc(sizeof(DOS_FILE));
25058a2b000SEvgeniy Ivanov #ifdef BOOTXX
25158a2b000SEvgeniy Ivanov /* due to __internal_memset_ causing all sorts of register spillage
25258a2b000SEvgeniy Ivanov (and being completely unoptimized for zeroing small amounts of
25358a2b000SEvgeniy Ivanov memory), if we hand-initialize the remaining members of f to zero,
25458a2b000SEvgeniy Ivanov the code size drops 68 bytes. This makes no sense, admittedly. */
25558a2b000SEvgeniy Ivanov f->offset = 0;
25658a2b000SEvgeniy Ivanov f->c = 0;
25758a2b000SEvgeniy Ivanov #else
25858a2b000SEvgeniy Ivanov (void)memset(f, 0, sizeof(DOS_FILE));
25958a2b000SEvgeniy Ivanov #endif
26058a2b000SEvgeniy Ivanov f->fs = fs;
26158a2b000SEvgeniy Ivanov fs->links++;
26258a2b000SEvgeniy Ivanov f->de = *de;
26358a2b000SEvgeniy Ivanov fd->f_fsdata = (void *)f;
26458a2b000SEvgeniy Ivanov fsmod = "msdos";
26558a2b000SEvgeniy Ivanov
26658a2b000SEvgeniy Ivanov out:
26758a2b000SEvgeniy Ivanov return err;
26858a2b000SEvgeniy Ivanov }
26958a2b000SEvgeniy Ivanov
27058a2b000SEvgeniy Ivanov /*
27158a2b000SEvgeniy Ivanov * Read from file
27258a2b000SEvgeniy Ivanov */
27358a2b000SEvgeniy Ivanov __compactcall int
dosfs_read(struct open_file * fd,void * vbuf,size_t nbyte,size_t * resid)27458a2b000SEvgeniy Ivanov dosfs_read(struct open_file *fd, void *vbuf, size_t nbyte, size_t *resid)
27558a2b000SEvgeniy Ivanov {
27658a2b000SEvgeniy Ivanov off_t size;
27758a2b000SEvgeniy Ivanov u_int8_t *buf = vbuf;
27858a2b000SEvgeniy Ivanov u_int nb, off, clus, c, cnt, n;
27958a2b000SEvgeniy Ivanov DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
28058a2b000SEvgeniy Ivanov int err = 0;
28158a2b000SEvgeniy Ivanov
28258a2b000SEvgeniy Ivanov nb = (u_int) nbyte;
28358a2b000SEvgeniy Ivanov if ((size = fsize(f->fs, &f->de)) == -1)
28458a2b000SEvgeniy Ivanov return EINVAL;
28558a2b000SEvgeniy Ivanov if (nb > (n = size - f->offset))
28658a2b000SEvgeniy Ivanov nb = n;
28758a2b000SEvgeniy Ivanov off = f->offset;
28858a2b000SEvgeniy Ivanov if ((clus = stclus(f->fs->fatsz, &f->de)))
28958a2b000SEvgeniy Ivanov off &= f->fs->bsize - 1;
29058a2b000SEvgeniy Ivanov c = f->c;
29158a2b000SEvgeniy Ivanov cnt = nb;
29258a2b000SEvgeniy Ivanov while (cnt) {
29358a2b000SEvgeniy Ivanov n = 0;
29458a2b000SEvgeniy Ivanov if (!c) {
29558a2b000SEvgeniy Ivanov if ((c = clus))
29658a2b000SEvgeniy Ivanov n = bytblk(f->fs, f->offset);
29758a2b000SEvgeniy Ivanov } else if (!off) {
29858a2b000SEvgeniy Ivanov n++;
29958a2b000SEvgeniy Ivanov }
30058a2b000SEvgeniy Ivanov while (n--) {
30158a2b000SEvgeniy Ivanov if ((err = fatget(f->fs, &c)))
30258a2b000SEvgeniy Ivanov goto out;
30358a2b000SEvgeniy Ivanov if (!okclus(f->fs, c)) {
30458a2b000SEvgeniy Ivanov err = EINVAL;
30558a2b000SEvgeniy Ivanov goto out;
30658a2b000SEvgeniy Ivanov }
30758a2b000SEvgeniy Ivanov }
30858a2b000SEvgeniy Ivanov if (!clus || (n = f->fs->bsize - off) > cnt)
30958a2b000SEvgeniy Ivanov n = cnt;
31058a2b000SEvgeniy Ivanov if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) :
31158a2b000SEvgeniy Ivanov secbyt(f->fs->lsndir)) + off,
31258a2b000SEvgeniy Ivanov buf, n)))
31358a2b000SEvgeniy Ivanov goto out;
31458a2b000SEvgeniy Ivanov f->offset += n;
31558a2b000SEvgeniy Ivanov f->c = c;
31658a2b000SEvgeniy Ivanov off = 0;
31758a2b000SEvgeniy Ivanov buf += n;
31858a2b000SEvgeniy Ivanov cnt -= n;
31958a2b000SEvgeniy Ivanov }
32058a2b000SEvgeniy Ivanov out:
32158a2b000SEvgeniy Ivanov if (resid)
32258a2b000SEvgeniy Ivanov *resid = nbyte - nb + cnt;
32358a2b000SEvgeniy Ivanov return err;
32458a2b000SEvgeniy Ivanov }
32558a2b000SEvgeniy Ivanov
32658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
32758a2b000SEvgeniy Ivanov /*
32858a2b000SEvgeniy Ivanov * Not implemented.
32958a2b000SEvgeniy Ivanov */
33058a2b000SEvgeniy Ivanov __compactcall int
dosfs_write(struct open_file * fd,void * start,size_t size,size_t * resid)33158a2b000SEvgeniy Ivanov dosfs_write(struct open_file *fd, void *start, size_t size, size_t *resid)
33258a2b000SEvgeniy Ivanov {
33358a2b000SEvgeniy Ivanov
33458a2b000SEvgeniy Ivanov return EROFS;
33558a2b000SEvgeniy Ivanov }
33658a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
33758a2b000SEvgeniy Ivanov
33858a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
33958a2b000SEvgeniy Ivanov /*
34058a2b000SEvgeniy Ivanov * Reposition within file
34158a2b000SEvgeniy Ivanov */
34258a2b000SEvgeniy Ivanov __compactcall off_t
dosfs_seek(struct open_file * fd,off_t offset,int whence)34358a2b000SEvgeniy Ivanov dosfs_seek(struct open_file *fd, off_t offset, int whence)
34458a2b000SEvgeniy Ivanov {
34558a2b000SEvgeniy Ivanov off_t off;
34658a2b000SEvgeniy Ivanov u_int size;
34758a2b000SEvgeniy Ivanov DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
34858a2b000SEvgeniy Ivanov
34958a2b000SEvgeniy Ivanov size = getulong(f->de.deFileSize);
35058a2b000SEvgeniy Ivanov switch (whence) {
35158a2b000SEvgeniy Ivanov case SEEK_SET:
35258a2b000SEvgeniy Ivanov off = 0;
35358a2b000SEvgeniy Ivanov break;
35458a2b000SEvgeniy Ivanov case SEEK_CUR:
35558a2b000SEvgeniy Ivanov off = f->offset;
35658a2b000SEvgeniy Ivanov break;
35758a2b000SEvgeniy Ivanov case SEEK_END:
35858a2b000SEvgeniy Ivanov off = size;
35958a2b000SEvgeniy Ivanov break;
36058a2b000SEvgeniy Ivanov default:
36158a2b000SEvgeniy Ivanov return -1;
36258a2b000SEvgeniy Ivanov }
36358a2b000SEvgeniy Ivanov off += offset;
36458a2b000SEvgeniy Ivanov if (off < 0 || off > size)
36558a2b000SEvgeniy Ivanov return -1;
36658a2b000SEvgeniy Ivanov f->offset = (u_int) off;
36758a2b000SEvgeniy Ivanov f->c = 0;
36858a2b000SEvgeniy Ivanov return off;
36958a2b000SEvgeniy Ivanov }
37058a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
37158a2b000SEvgeniy Ivanov
37258a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_CLOSE
37358a2b000SEvgeniy Ivanov /*
37458a2b000SEvgeniy Ivanov * Close open file
37558a2b000SEvgeniy Ivanov */
37658a2b000SEvgeniy Ivanov __compactcall int
dosfs_close(struct open_file * fd)37758a2b000SEvgeniy Ivanov dosfs_close(struct open_file *fd)
37858a2b000SEvgeniy Ivanov {
37958a2b000SEvgeniy Ivanov DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
38058a2b000SEvgeniy Ivanov DOS_FS *fs = f->fs;
38158a2b000SEvgeniy Ivanov
38258a2b000SEvgeniy Ivanov f->fs->links--;
38358a2b000SEvgeniy Ivanov dealloc(f, sizeof(DOS_FILE));
38458a2b000SEvgeniy Ivanov dos_unmount(fs);
38558a2b000SEvgeniy Ivanov return 0;
38658a2b000SEvgeniy Ivanov }
38758a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_CLOSE */
38858a2b000SEvgeniy Ivanov
38958a2b000SEvgeniy Ivanov /*
39058a2b000SEvgeniy Ivanov * Return some stat information on a file.
39158a2b000SEvgeniy Ivanov */
39258a2b000SEvgeniy Ivanov __compactcall int
dosfs_stat(struct open_file * fd,struct stat * sb)39358a2b000SEvgeniy Ivanov dosfs_stat(struct open_file *fd, struct stat *sb)
39458a2b000SEvgeniy Ivanov {
39558a2b000SEvgeniy Ivanov DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
39658a2b000SEvgeniy Ivanov
39758a2b000SEvgeniy Ivanov /* only important stuff */
39858a2b000SEvgeniy Ivanov sb->st_mode = (f->de.deAttributes & ATTR_DIRECTORY) ?
39958a2b000SEvgeniy Ivanov (S_IFDIR | 0555) : (S_IFREG | 0444);
40058a2b000SEvgeniy Ivanov sb->st_nlink = 1;
40158a2b000SEvgeniy Ivanov sb->st_uid = 0;
40258a2b000SEvgeniy Ivanov sb->st_gid = 0;
40358a2b000SEvgeniy Ivanov if ((sb->st_size = fsize(f->fs, &f->de)) == -1)
40458a2b000SEvgeniy Ivanov return EINVAL;
40558a2b000SEvgeniy Ivanov return 0;
40658a2b000SEvgeniy Ivanov }
40758a2b000SEvgeniy Ivanov
40858a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
409*0a6a1f1dSLionel Sambuc #include "ls.h"
41058a2b000SEvgeniy Ivanov __compactcall void
dosfs_ls(struct open_file * f,const char * pattern)411*0a6a1f1dSLionel Sambuc dosfs_ls(struct open_file *f, const char *pattern)
41258a2b000SEvgeniy Ivanov {
413*0a6a1f1dSLionel Sambuc lsunsup("dosfs");
41458a2b000SEvgeniy Ivanov }
415*0a6a1f1dSLionel Sambuc
416*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
417*0a6a1f1dSLionel Sambuc __compactcall void
dosfs_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)418*0a6a1f1dSLionel Sambuc dosfs_load_mods(struct open_file *f, const char *pattern,
419*0a6a1f1dSLionel Sambuc void (*funcp)(char *), char *path)
420*0a6a1f1dSLionel Sambuc {
421*0a6a1f1dSLionel Sambuc load_modsunsup("dosfs");
422*0a6a1f1dSLionel Sambuc }
423*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
42458a2b000SEvgeniy Ivanov #endif
42558a2b000SEvgeniy Ivanov
42658a2b000SEvgeniy Ivanov /*
42758a2b000SEvgeniy Ivanov * Parse DOS boot sector
42858a2b000SEvgeniy Ivanov */
42958a2b000SEvgeniy Ivanov static int
parsebs(DOS_FS * fs,DOS_BS * bs)43058a2b000SEvgeniy Ivanov parsebs(DOS_FS *fs, DOS_BS *bs)
43158a2b000SEvgeniy Ivanov {
43258a2b000SEvgeniy Ivanov u_int sc;
43358a2b000SEvgeniy Ivanov
43458a2b000SEvgeniy Ivanov if ((bs->jmp[0] != 0x69 &&
43558a2b000SEvgeniy Ivanov bs->jmp[0] != 0xe9 &&
43658a2b000SEvgeniy Ivanov (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) ||
43758a2b000SEvgeniy Ivanov bs->bpb.bpbMedia < 0xf0)
43858a2b000SEvgeniy Ivanov return EINVAL;
43958a2b000SEvgeniy Ivanov if (getushort(bs->bpb.bpbBytesPerSec) != SECSIZ)
44058a2b000SEvgeniy Ivanov return EINVAL;
44158a2b000SEvgeniy Ivanov if (!(fs->spc = bs->bpb.bpbSecPerClust) || fs->spc & (fs->spc - 1))
44258a2b000SEvgeniy Ivanov return EINVAL;
44358a2b000SEvgeniy Ivanov fs->bsize = secbyt(fs->spc);
44458a2b000SEvgeniy Ivanov fs->bshift = ffs(fs->bsize) - 1;
44558a2b000SEvgeniy Ivanov if ((fs->spf = getushort(bs->bpb.bpbFATsecs))) {
44658a2b000SEvgeniy Ivanov if (bs->bpb.bpbFATs != 2)
44758a2b000SEvgeniy Ivanov return EINVAL;
44858a2b000SEvgeniy Ivanov if (!(fs->dirents = getushort(bs->bpb.bpbRootDirEnts)))
44958a2b000SEvgeniy Ivanov return EINVAL;
45058a2b000SEvgeniy Ivanov } else {
45158a2b000SEvgeniy Ivanov if (!(fs->spf = getulong(bs->bpb.bpbBigFATsecs)))
45258a2b000SEvgeniy Ivanov return EINVAL;
45358a2b000SEvgeniy Ivanov if (!bs->bpb.bpbFATs || bs->bpb.bpbFATs > 16)
45458a2b000SEvgeniy Ivanov return EINVAL;
45558a2b000SEvgeniy Ivanov if ((fs->rdcl = getulong(bs->bpb.bpbRootClust)) < LOCLUS)
45658a2b000SEvgeniy Ivanov return EINVAL;
45758a2b000SEvgeniy Ivanov }
45858a2b000SEvgeniy Ivanov if (!(fs->lsnfat = getushort(bs->bpb.bpbResSectors)))
45958a2b000SEvgeniy Ivanov return EINVAL;
46058a2b000SEvgeniy Ivanov fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.bpbFATs;
46158a2b000SEvgeniy Ivanov fs->lsndta = fs->lsndir + entsec(fs->dirents);
46258a2b000SEvgeniy Ivanov if (!(sc = getushort(bs->bpb.bpbSectors)) &&
46358a2b000SEvgeniy Ivanov !(sc = getulong(bs->bpb.bpbHugeSectors)))
46458a2b000SEvgeniy Ivanov return EINVAL;
46558a2b000SEvgeniy Ivanov if (fs->lsndta > sc)
46658a2b000SEvgeniy Ivanov return EINVAL;
46758a2b000SEvgeniy Ivanov if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS)
46858a2b000SEvgeniy Ivanov return EINVAL;
46958a2b000SEvgeniy Ivanov fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32;
47058a2b000SEvgeniy Ivanov sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1;
47158a2b000SEvgeniy Ivanov if (fs->xclus > sc)
47258a2b000SEvgeniy Ivanov fs->xclus = sc;
47358a2b000SEvgeniy Ivanov return 0;
47458a2b000SEvgeniy Ivanov }
47558a2b000SEvgeniy Ivanov
47658a2b000SEvgeniy Ivanov /*
47758a2b000SEvgeniy Ivanov * Return directory entry from path
47858a2b000SEvgeniy Ivanov */
47958a2b000SEvgeniy Ivanov static int
namede(DOS_FS * fs,const char * path,const struct direntry ** dep)48058a2b000SEvgeniy Ivanov namede(DOS_FS *fs, const char *path, const struct direntry **dep)
48158a2b000SEvgeniy Ivanov {
48258a2b000SEvgeniy Ivanov char name[256];
48358a2b000SEvgeniy Ivanov const struct direntry *de;
48458a2b000SEvgeniy Ivanov char *s;
48558a2b000SEvgeniy Ivanov size_t n;
48658a2b000SEvgeniy Ivanov int err;
48758a2b000SEvgeniy Ivanov
48858a2b000SEvgeniy Ivanov err = 0;
48958a2b000SEvgeniy Ivanov de = dot;
49058a2b000SEvgeniy Ivanov if (*path == '/')
49158a2b000SEvgeniy Ivanov path++;
49258a2b000SEvgeniy Ivanov while (*path) {
49358a2b000SEvgeniy Ivanov if (!(s = strchr(path, '/')))
49458a2b000SEvgeniy Ivanov s = strchr(path, 0);
49558a2b000SEvgeniy Ivanov if ((n = s - path) > 255)
49658a2b000SEvgeniy Ivanov return ENAMETOOLONG;
49758a2b000SEvgeniy Ivanov memcpy(name, path, n);
49858a2b000SEvgeniy Ivanov name[n] = 0;
49958a2b000SEvgeniy Ivanov path = s;
50058a2b000SEvgeniy Ivanov if (!(de->deAttributes & ATTR_DIRECTORY))
50158a2b000SEvgeniy Ivanov return ENOTDIR;
50258a2b000SEvgeniy Ivanov if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de)))
50358a2b000SEvgeniy Ivanov return err;
50458a2b000SEvgeniy Ivanov if (*path == '/')
50558a2b000SEvgeniy Ivanov path++;
50658a2b000SEvgeniy Ivanov }
50758a2b000SEvgeniy Ivanov *dep = de;
50858a2b000SEvgeniy Ivanov return 0;
50958a2b000SEvgeniy Ivanov }
51058a2b000SEvgeniy Ivanov
51158a2b000SEvgeniy Ivanov /*
51258a2b000SEvgeniy Ivanov * Lookup path segment
51358a2b000SEvgeniy Ivanov */
51458a2b000SEvgeniy Ivanov static int
lookup(DOS_FS * fs,u_int clus,const char * name,const struct direntry ** dep)51558a2b000SEvgeniy Ivanov lookup(DOS_FS *fs, u_int clus, const char *name, const struct direntry **dep)
51658a2b000SEvgeniy Ivanov {
51758a2b000SEvgeniy Ivanov static DOS_DIR *dir = NULL;
51858a2b000SEvgeniy Ivanov u_char lfn[261];
51958a2b000SEvgeniy Ivanov u_char sfn[13];
52058a2b000SEvgeniy Ivanov u_int nsec, lsec, xdn, chk, sec, ent, x;
52158a2b000SEvgeniy Ivanov int err = 0, ok, i;
52258a2b000SEvgeniy Ivanov
52358a2b000SEvgeniy Ivanov if (!clus)
52458a2b000SEvgeniy Ivanov for (ent = 0; ent < 2; ent++)
52558a2b000SEvgeniy Ivanov if (!strcasecmp(name, dotstr[ent])) {
52658a2b000SEvgeniy Ivanov *dep = dot + ent;
52758a2b000SEvgeniy Ivanov return 0;
52858a2b000SEvgeniy Ivanov }
52958a2b000SEvgeniy Ivanov
53058a2b000SEvgeniy Ivanov if (dir == NULL) {
53158a2b000SEvgeniy Ivanov dir = alloc(sizeof(DOS_DIR) * DEPSEC);
53258a2b000SEvgeniy Ivanov if (dir == NULL)
53358a2b000SEvgeniy Ivanov return ENOMEM;
53458a2b000SEvgeniy Ivanov }
53558a2b000SEvgeniy Ivanov
53658a2b000SEvgeniy Ivanov if (!clus && fs->fatsz == 32)
53758a2b000SEvgeniy Ivanov clus = fs->rdcl;
53858a2b000SEvgeniy Ivanov nsec = !clus ? entsec(fs->dirents) : fs->spc;
53958a2b000SEvgeniy Ivanov lsec = 0;
54058a2b000SEvgeniy Ivanov xdn = chk = 0;
54158a2b000SEvgeniy Ivanov for (;;) {
54258a2b000SEvgeniy Ivanov if (!clus && !lsec)
54358a2b000SEvgeniy Ivanov lsec = fs->lsndir;
54458a2b000SEvgeniy Ivanov else if (okclus(fs, clus))
54558a2b000SEvgeniy Ivanov lsec = blklsn(fs, clus);
54658a2b000SEvgeniy Ivanov else {
54758a2b000SEvgeniy Ivanov err = EINVAL;
54858a2b000SEvgeniy Ivanov goto out;
54958a2b000SEvgeniy Ivanov }
55058a2b000SEvgeniy Ivanov for (sec = 0; sec < nsec; sec++) {
55158a2b000SEvgeniy Ivanov if ((err = ioget(fs->fd, lsec + sec, dir, 1)))
55258a2b000SEvgeniy Ivanov goto out;
55358a2b000SEvgeniy Ivanov for (ent = 0; ent < DEPSEC; ent++) {
55458a2b000SEvgeniy Ivanov if (!*dir[ent].de.deName) {
55558a2b000SEvgeniy Ivanov err = ENOENT;
55658a2b000SEvgeniy Ivanov goto out;
55758a2b000SEvgeniy Ivanov }
55858a2b000SEvgeniy Ivanov if (*dir[ent].de.deName != 0xe5) {
55958a2b000SEvgeniy Ivanov if (dir[ent].de.deAttributes ==
56058a2b000SEvgeniy Ivanov ATTR_WIN95) {
56158a2b000SEvgeniy Ivanov x = dir[ent].xde.weCnt;
56258a2b000SEvgeniy Ivanov if (x & WIN_LAST ||
56358a2b000SEvgeniy Ivanov (x + 1 == xdn &&
56458a2b000SEvgeniy Ivanov dir[ent].xde.weChksum ==
56558a2b000SEvgeniy Ivanov chk)) {
56658a2b000SEvgeniy Ivanov if (x & WIN_LAST) {
56758a2b000SEvgeniy Ivanov chk = dir[ent].xde.weChksum;
56858a2b000SEvgeniy Ivanov x &= WIN_CNT;
56958a2b000SEvgeniy Ivanov }
57058a2b000SEvgeniy Ivanov if (x >= 1 && x <= 20) {
57158a2b000SEvgeniy Ivanov cp_xdnm(lfn, &dir[ent].xde);
57258a2b000SEvgeniy Ivanov xdn = x;
57358a2b000SEvgeniy Ivanov continue;
57458a2b000SEvgeniy Ivanov }
57558a2b000SEvgeniy Ivanov }
57658a2b000SEvgeniy Ivanov } else if (!(dir[ent].de.deAttributes &
57758a2b000SEvgeniy Ivanov ATTR_VOLUME)) {
57858a2b000SEvgeniy Ivanov if ((ok = xdn == 1)) {
57958a2b000SEvgeniy Ivanov for (x = 0, i = 0;
58058a2b000SEvgeniy Ivanov i < 11; i++)
58158a2b000SEvgeniy Ivanov x = ((((x & 1) << 7) | (x >> 1)) +
58284d9c625SLionel Sambuc msdos_dirchar(&dir[ent].de,i)) & 0xff;
58358a2b000SEvgeniy Ivanov ok = chk == x &&
58458a2b000SEvgeniy Ivanov !strcasecmp(name, (const char *)lfn);
58558a2b000SEvgeniy Ivanov }
58658a2b000SEvgeniy Ivanov if (!ok) {
58758a2b000SEvgeniy Ivanov cp_sfn(sfn, &dir[ent].de);
58858a2b000SEvgeniy Ivanov ok = !strcasecmp(name, (const char *)sfn);
58958a2b000SEvgeniy Ivanov }
59058a2b000SEvgeniy Ivanov if (ok) {
59158a2b000SEvgeniy Ivanov *dep = &dir[ent].de;
59258a2b000SEvgeniy Ivanov goto out2;
59358a2b000SEvgeniy Ivanov }
59458a2b000SEvgeniy Ivanov }
59558a2b000SEvgeniy Ivanov }
59658a2b000SEvgeniy Ivanov xdn = 0;
59758a2b000SEvgeniy Ivanov }
59858a2b000SEvgeniy Ivanov }
59958a2b000SEvgeniy Ivanov if (!clus)
60058a2b000SEvgeniy Ivanov break;
60158a2b000SEvgeniy Ivanov if ((err = fatget(fs, &clus)))
60258a2b000SEvgeniy Ivanov goto out;
60358a2b000SEvgeniy Ivanov if (fatend(fs->fatsz, clus))
60458a2b000SEvgeniy Ivanov break;
60558a2b000SEvgeniy Ivanov }
60658a2b000SEvgeniy Ivanov err = ENOENT;
60758a2b000SEvgeniy Ivanov out:
60858a2b000SEvgeniy Ivanov dealloc(dir, sizeof(DOS_DIR) * DEPSEC);
60958a2b000SEvgeniy Ivanov dir = NULL;
61058a2b000SEvgeniy Ivanov out2:
61158a2b000SEvgeniy Ivanov return err;
61258a2b000SEvgeniy Ivanov }
61358a2b000SEvgeniy Ivanov
61458a2b000SEvgeniy Ivanov /*
61558a2b000SEvgeniy Ivanov * Copy name from extended directory entry
61658a2b000SEvgeniy Ivanov */
61758a2b000SEvgeniy Ivanov static void
cp_xdnm(u_char * lfn,struct winentry * xde)61858a2b000SEvgeniy Ivanov cp_xdnm(u_char *lfn, struct winentry *xde)
61958a2b000SEvgeniy Ivanov {
62058a2b000SEvgeniy Ivanov static const struct {
62158a2b000SEvgeniy Ivanov u_int off;
62258a2b000SEvgeniy Ivanov u_int dim;
62358a2b000SEvgeniy Ivanov } ix[3] = {
62458a2b000SEvgeniy Ivanov { offsetof(struct winentry, wePart1),
62558a2b000SEvgeniy Ivanov sizeof(xde->wePart1) / 2 },
62658a2b000SEvgeniy Ivanov { offsetof(struct winentry, wePart2),
62758a2b000SEvgeniy Ivanov sizeof(xde->wePart2) / 2 },
62858a2b000SEvgeniy Ivanov { offsetof(struct winentry, wePart3),
62958a2b000SEvgeniy Ivanov sizeof(xde->wePart3) / 2 }
63058a2b000SEvgeniy Ivanov };
63158a2b000SEvgeniy Ivanov u_char *p;
63258a2b000SEvgeniy Ivanov u_int n, x, c;
63358a2b000SEvgeniy Ivanov
63458a2b000SEvgeniy Ivanov lfn += 13 * ((xde->weCnt & WIN_CNT) - 1);
63558a2b000SEvgeniy Ivanov for (n = 0; n < 3; n++)
63658a2b000SEvgeniy Ivanov for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x;
63758a2b000SEvgeniy Ivanov p += 2, x--) {
63858a2b000SEvgeniy Ivanov if ((c = getushort(p)) && (c < 32 || c > 127))
63958a2b000SEvgeniy Ivanov c = '?';
64058a2b000SEvgeniy Ivanov if (!(*lfn++ = c))
64158a2b000SEvgeniy Ivanov return;
64258a2b000SEvgeniy Ivanov }
64358a2b000SEvgeniy Ivanov if (xde->weCnt & WIN_LAST)
64458a2b000SEvgeniy Ivanov *lfn = 0;
64558a2b000SEvgeniy Ivanov }
64658a2b000SEvgeniy Ivanov
64758a2b000SEvgeniy Ivanov /*
64858a2b000SEvgeniy Ivanov * Copy short filename
64958a2b000SEvgeniy Ivanov */
65058a2b000SEvgeniy Ivanov static void
cp_sfn(u_char * sfn,struct direntry * de)65158a2b000SEvgeniy Ivanov cp_sfn(u_char *sfn, struct direntry *de)
65258a2b000SEvgeniy Ivanov {
65358a2b000SEvgeniy Ivanov u_char *p;
65458a2b000SEvgeniy Ivanov int j, i;
65558a2b000SEvgeniy Ivanov
65658a2b000SEvgeniy Ivanov p = sfn;
65758a2b000SEvgeniy Ivanov if (*de->deName != ' ') {
65858a2b000SEvgeniy Ivanov for (j = 7; de->deName[j] == ' '; j--);
65958a2b000SEvgeniy Ivanov for (i = 0; i <= j; i++)
66058a2b000SEvgeniy Ivanov *p++ = de->deName[i];
66158a2b000SEvgeniy Ivanov if (*de->deExtension != ' ') {
66258a2b000SEvgeniy Ivanov *p++ = '.';
66358a2b000SEvgeniy Ivanov for (j = 2; de->deExtension[j] == ' '; j--);
66458a2b000SEvgeniy Ivanov for (i = 0; i <= j; i++)
66558a2b000SEvgeniy Ivanov *p++ = de->deExtension[i];
66658a2b000SEvgeniy Ivanov }
66758a2b000SEvgeniy Ivanov }
66858a2b000SEvgeniy Ivanov *p = 0;
66958a2b000SEvgeniy Ivanov if (*sfn == 5)
67058a2b000SEvgeniy Ivanov *sfn = 0xe5;
67158a2b000SEvgeniy Ivanov }
67258a2b000SEvgeniy Ivanov
67358a2b000SEvgeniy Ivanov /*
67458a2b000SEvgeniy Ivanov * Return size of file in bytes
67558a2b000SEvgeniy Ivanov */
67658a2b000SEvgeniy Ivanov static off_t
fsize(DOS_FS * fs,struct direntry * de)67758a2b000SEvgeniy Ivanov fsize(DOS_FS *fs, struct direntry *de)
67858a2b000SEvgeniy Ivanov {
67958a2b000SEvgeniy Ivanov u_long size;
68058a2b000SEvgeniy Ivanov u_int c;
68158a2b000SEvgeniy Ivanov int n;
68258a2b000SEvgeniy Ivanov
68358a2b000SEvgeniy Ivanov if (!(size = getulong(de->deFileSize)) &&
68458a2b000SEvgeniy Ivanov de->deAttributes & ATTR_DIRECTORY) {
68558a2b000SEvgeniy Ivanov if (!(c = getushort(de->deStartCluster))) {
68658a2b000SEvgeniy Ivanov size = fs->dirents * sizeof(struct direntry);
68758a2b000SEvgeniy Ivanov } else {
68858a2b000SEvgeniy Ivanov if ((n = fatcnt(fs, c)) == -1)
68958a2b000SEvgeniy Ivanov return n;
69058a2b000SEvgeniy Ivanov size = blkbyt(fs, n);
69158a2b000SEvgeniy Ivanov }
69258a2b000SEvgeniy Ivanov }
69358a2b000SEvgeniy Ivanov return size;
69458a2b000SEvgeniy Ivanov }
69558a2b000SEvgeniy Ivanov
69658a2b000SEvgeniy Ivanov /*
69758a2b000SEvgeniy Ivanov * Count number of clusters in chain
69858a2b000SEvgeniy Ivanov */
69958a2b000SEvgeniy Ivanov static int
fatcnt(DOS_FS * fs,u_int c)70058a2b000SEvgeniy Ivanov fatcnt(DOS_FS *fs, u_int c)
70158a2b000SEvgeniy Ivanov {
70258a2b000SEvgeniy Ivanov int n;
70358a2b000SEvgeniy Ivanov
70458a2b000SEvgeniy Ivanov for (n = 0; okclus(fs, c); n++)
70558a2b000SEvgeniy Ivanov if (fatget(fs, &c))
70658a2b000SEvgeniy Ivanov return -1;
70758a2b000SEvgeniy Ivanov return fatend(fs->fatsz, c) ? n : -1;
70858a2b000SEvgeniy Ivanov }
70958a2b000SEvgeniy Ivanov
71058a2b000SEvgeniy Ivanov /*
71158a2b000SEvgeniy Ivanov * Get next cluster in cluster chain
71258a2b000SEvgeniy Ivanov */
71358a2b000SEvgeniy Ivanov static int
fatget(DOS_FS * fs,u_int * c)71458a2b000SEvgeniy Ivanov fatget(DOS_FS *fs, u_int *c)
71558a2b000SEvgeniy Ivanov {
71658a2b000SEvgeniy Ivanov u_char buf[4];
71758a2b000SEvgeniy Ivanov u_int x;
71858a2b000SEvgeniy Ivanov int err;
71958a2b000SEvgeniy Ivanov
72058a2b000SEvgeniy Ivanov err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf,
72158a2b000SEvgeniy Ivanov fs->fatsz != 32 ? 2 : 4);
72258a2b000SEvgeniy Ivanov if (err)
72358a2b000SEvgeniy Ivanov return err;
72458a2b000SEvgeniy Ivanov x = fs->fatsz != 32 ? getushort(buf) : getulong(buf);
72558a2b000SEvgeniy Ivanov *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x;
72658a2b000SEvgeniy Ivanov return 0;
72758a2b000SEvgeniy Ivanov }
72858a2b000SEvgeniy Ivanov
72958a2b000SEvgeniy Ivanov /*
73058a2b000SEvgeniy Ivanov * Is cluster an end-of-chain marker?
73158a2b000SEvgeniy Ivanov */
73258a2b000SEvgeniy Ivanov static int
fatend(u_int sz,u_int c)73358a2b000SEvgeniy Ivanov fatend(u_int sz, u_int c)
73458a2b000SEvgeniy Ivanov {
73558a2b000SEvgeniy Ivanov return c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7);
73658a2b000SEvgeniy Ivanov }
73758a2b000SEvgeniy Ivanov
73858a2b000SEvgeniy Ivanov /*
73958a2b000SEvgeniy Ivanov * Offset-based I/O primitive
74058a2b000SEvgeniy Ivanov */
74158a2b000SEvgeniy Ivanov static int
ioread(DOS_FS * fs,u_int offset,void * buf,u_int nbyte)74258a2b000SEvgeniy Ivanov ioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte)
74358a2b000SEvgeniy Ivanov {
74458a2b000SEvgeniy Ivanov char *s;
74558a2b000SEvgeniy Ivanov u_int off, n;
74658a2b000SEvgeniy Ivanov int err;
74758a2b000SEvgeniy Ivanov
74858a2b000SEvgeniy Ivanov s = buf;
74958a2b000SEvgeniy Ivanov if ((off = offset & (SECSIZ - 1))) {
75058a2b000SEvgeniy Ivanov offset -= off;
75158a2b000SEvgeniy Ivanov if ((err = iobuf(fs, bytsec(offset))))
75258a2b000SEvgeniy Ivanov return err;
75358a2b000SEvgeniy Ivanov offset += SECSIZ;
75458a2b000SEvgeniy Ivanov if ((n = SECSIZ - off) > nbyte)
75558a2b000SEvgeniy Ivanov n = nbyte;
75658a2b000SEvgeniy Ivanov memcpy(s, fs->buf + off, n);
75758a2b000SEvgeniy Ivanov s += n;
75858a2b000SEvgeniy Ivanov nbyte -= n;
75958a2b000SEvgeniy Ivanov }
76058a2b000SEvgeniy Ivanov n = nbyte & (SECSIZ - 1);
76158a2b000SEvgeniy Ivanov if (nbyte -= n) {
76258a2b000SEvgeniy Ivanov if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte))))
76358a2b000SEvgeniy Ivanov return err;
76458a2b000SEvgeniy Ivanov offset += nbyte;
76558a2b000SEvgeniy Ivanov s += nbyte;
76658a2b000SEvgeniy Ivanov }
76758a2b000SEvgeniy Ivanov if (n) {
76858a2b000SEvgeniy Ivanov if ((err = iobuf(fs, bytsec(offset))))
76958a2b000SEvgeniy Ivanov return err;
77058a2b000SEvgeniy Ivanov memcpy(s, fs->buf, n);
77158a2b000SEvgeniy Ivanov }
77258a2b000SEvgeniy Ivanov return 0;
77358a2b000SEvgeniy Ivanov }
77458a2b000SEvgeniy Ivanov
77558a2b000SEvgeniy Ivanov /*
77658a2b000SEvgeniy Ivanov * Buffered sector-based I/O primitive
77758a2b000SEvgeniy Ivanov */
77858a2b000SEvgeniy Ivanov static int
iobuf(DOS_FS * fs,u_int lsec)77958a2b000SEvgeniy Ivanov iobuf(DOS_FS *fs, u_int lsec)
78058a2b000SEvgeniy Ivanov {
78158a2b000SEvgeniy Ivanov int err;
78258a2b000SEvgeniy Ivanov
78358a2b000SEvgeniy Ivanov if (fs->bufsec != lsec) {
78458a2b000SEvgeniy Ivanov if ((err = ioget(fs->fd, lsec, fs->buf, 1)))
78558a2b000SEvgeniy Ivanov return err;
78658a2b000SEvgeniy Ivanov fs->bufsec = lsec;
78758a2b000SEvgeniy Ivanov }
78858a2b000SEvgeniy Ivanov return 0;
78958a2b000SEvgeniy Ivanov }
79058a2b000SEvgeniy Ivanov
79158a2b000SEvgeniy Ivanov /*
79258a2b000SEvgeniy Ivanov * Sector-based I/O primitive
79358a2b000SEvgeniy Ivanov */
79458a2b000SEvgeniy Ivanov static int
ioget(struct open_file * fd,u_int lsec,void * buf,u_int nsec)79558a2b000SEvgeniy Ivanov ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec)
79658a2b000SEvgeniy Ivanov {
79758a2b000SEvgeniy Ivanov size_t rsize;
79858a2b000SEvgeniy Ivanov int err;
79958a2b000SEvgeniy Ivanov
80058a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_TWIDDLE
80158a2b000SEvgeniy Ivanov twiddle();
80258a2b000SEvgeniy Ivanov #endif
80358a2b000SEvgeniy Ivanov err = DEV_STRATEGY(fd->f_dev)(fd->f_devdata, F_READ, lsec,
80458a2b000SEvgeniy Ivanov secbyt(nsec), buf, &rsize);
80558a2b000SEvgeniy Ivanov return err;
80658a2b000SEvgeniy Ivanov }
807