diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index dd248840789b..be8517d68348 100644 --- a/lib/libstand/Makefile +++ b/lib/libstand/Makefile @@ -104,7 +104,7 @@ SRCS+= adler32.c crc32.c infblock.c infcodes.c inffast.c inflate.c \ # io routines SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \ - fstat.c close.c lseek.c open.c read.c write.c + fstat.c close.c lseek.c open.c read.c write.c readdir.c # network routines SRCS+= arp.c ether.c in_cksum.c net.c udp.c netif.c rpc.c @@ -115,7 +115,7 @@ SRCS+= bootp.c rarp.c bootparam.c # boot filesystems SRCS+= ufs.c nfs.c cd9660.c tftp.c zipfs.c SRCS+= netif.c nfs.c -SRCS+= dosfs.c +SRCS+= dosfs.c ext2fs.c beforeinstall: ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/stand.h \ diff --git a/lib/libstand/cd9660.c b/lib/libstand/cd9660.c index 9b53d0605a22..621d30d4681e 100644 --- a/lib/libstand/cd9660.c +++ b/lib/libstand/cd9660.c @@ -51,16 +51,26 @@ static int cd9660_read(struct open_file *f, void *buf, size_t size, size_t *resi static int cd9660_write(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t cd9660_seek(struct open_file *f, off_t offset, int where); static int cd9660_stat(struct open_file *f, struct stat *sb); +static int cd9660_readdir(struct open_file *f, struct dirent *d); struct fs_ops cd9660_fsops = { - "cd9660", cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, cd9660_stat + "cd9660", + cd9660_open, + cd9660_close, + cd9660_read, + cd9660_write, + cd9660_seek, + cd9660_stat, + cd9660_readdir }; struct file { - int isdir; /* nonzero if file is directory */ - off_t off; /* Current offset within file */ - daddr_t bno; /* Starting block number */ - off_t size; /* Size of file */ + int f_isdir; /* nonzero if file is directory */ + off_t f_off; /* Current offset within file */ + daddr_t f_bno; /* Starting block number */ + off_t f_size; /* Size of file */ + daddr_t f_buf_blkno; /* block number of data block */ + char *f_buf; /* buffer for data block */ }; struct ptable_ent { @@ -217,10 +227,10 @@ cd9660_open(path, f) bzero(fp, sizeof(struct file)); f->f_fsdata = (void *)fp; - fp->isdir = (isonum_711(rec.flags) & 2) != 0; - fp->off = 0; - fp->bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - fp->size = isonum_733(rec.size); + fp->f_isdir = (isonum_711(rec.flags) & 2) != 0; + fp->f_off = 0; + fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + fp->f_size = isonum_733(rec.size); free(buf); return 0; @@ -246,154 +256,39 @@ cd9660_close(f) } static int -cd9660_readfile(f, start, size, resid) +buf_read_file(f, buf_p, size_p) struct open_file *f; - void *start; - size_t size; - size_t *resid; + char **buf_p; + size_t *size_p; { struct file *fp = (struct file *)f->f_fsdata; + daddr_t blkno; int rc = 0; - daddr_t bno; - char buf[ISO_DEFAULT_BLOCK_SIZE]; - char *dp; - size_t read, off; + size_t read; + + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; + + if (blkno != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); - while (size) { - if (fp->off < 0 || fp->off >= fp->size) - break; - bno = fp->off / ISO_DEFAULT_BLOCK_SIZE + fp->bno; - if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1) - || size < ISO_DEFAULT_BLOCK_SIZE) - dp = buf; - else - dp = start; twiddle(); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, dp, &read); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, fp->f_buf, &read); if (rc) - return rc; + return (rc); if (read != ISO_DEFAULT_BLOCK_SIZE) - return EIO; - if (dp == buf) { - off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1); - if (read > off + size) - read = off + size; - read -= off; - bcopy(buf + off, start, read); - start += read; - fp->off += read; - size -= read; - } else { - start += ISO_DEFAULT_BLOCK_SIZE; - fp->off += ISO_DEFAULT_BLOCK_SIZE; - size -= ISO_DEFAULT_BLOCK_SIZE; - } - } - if (resid) - *resid = size; - return rc; -} + return (EIO); -static int -cd9660_readdir(f, start, size, resid) - struct open_file *f; - void *start; - size_t size; - size_t *resid; -{ - struct file *fp = (struct file *)f->f_fsdata; - int rc = 0; - daddr_t bno, boff; - char buf[ISO_DEFAULT_BLOCK_SIZE]; - struct dirent *dp; - struct dirent *lastdp; - struct iso_directory_record *ep = 0; - size_t read, off, reclen, namelen; - - if (fp->off < 0 || fp->off >= fp->size) - return 0; - boff = fp->off / ISO_DEFAULT_BLOCK_SIZE; - bno = fp->bno; - off = fp->off; - - if (off % ISO_DEFAULT_BLOCK_SIZE) { - twiddle(); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, buf, &read); - if (rc) - return rc; - if (read != ISO_DEFAULT_BLOCK_SIZE) - return EIO; - boff++; - ep = (struct iso_directory_record *) - (buf + (off % ISO_DEFAULT_BLOCK_SIZE)); + fp->f_buf_blkno = blkno; } - lastdp = dp = (struct dirent *) start; - dp->d_fileno = 0; - dp->d_type = DT_UNKNOWN; - dp->d_namlen = 0; - while (size && off < fp->size) { - if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { - twiddle(); - rc = f->f_dev->dv_strategy - (f->f_devdata, F_READ, - cdb2devb(bno + boff), - ISO_DEFAULT_BLOCK_SIZE, - buf, &read); - if (rc) - break; - if (read != ISO_DEFAULT_BLOCK_SIZE) { - rc = EIO; - break; - } - boff++; - ep = (struct iso_directory_record *) buf; - } + *buf_p = fp->f_buf + fp->f_off; + *size_p = ISO_DEFAULT_BLOCK_SIZE - fp->f_off; - if (isonum_711(ep->length) == 0) { - /* skip to next block, if any */ - off = boff * ISO_DEFAULT_BLOCK_SIZE; - continue; - } - - namelen = isonum_711(ep->name_len); - if (namelen == 1 && ep->name[0] == 1) - namelen = 2; - reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; - reclen = (reclen + 3) & ~3; - if (reclen > size) - break; - - dp->d_fileno = isonum_733(ep->extent); - dp->d_reclen = reclen; - if (isonum_711(ep->flags) & 2) - dp->d_type = DT_DIR; - else - dp->d_type = DT_REG; - dp->d_namlen = namelen; - if (isonum_711(ep->name_len) == 1 && ep->name[0] == 0) - strcpy(dp->d_name, "."); - else if (isonum_711(ep->name_len) == 1 && ep->name[0] == 1) - strcpy(dp->d_name, ".."); - else - bcopy(ep->name, dp->d_name, dp->d_namlen); - dp->d_name[dp->d_namlen] = 0; - - lastdp = dp; - dp = (struct dirent *) ((char *) dp + dp->d_reclen); - size -= reclen; - ep = (struct iso_directory_record *) - ((char *) ep + isonum_711(ep->length)); - off += isonum_711(ep->length); - } - - fp->off = off; - lastdp->d_reclen += size; - if (resid) - *resid = 0; - return rc; + if (*size_p > fp->f_size - fp->f_off) + *size_p = fp->f_size - fp->f_off; + return (rc); } static int @@ -404,11 +299,81 @@ cd9660_read(f, start, size, resid) size_t *resid; { struct file *fp = (struct file *)f->f_fsdata; + char *buf, *addr; + size_t buf_size, csize; + int rc = 0; - if (fp->isdir) - return cd9660_readdir(f, start, size, resid); + addr = start; + while (size) { + if (fp->f_off < 0 || fp->f_off >= fp->f_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size > buf_size ? buf_size : size; + bcopy(buf, addr, csize); + + fp->f_off += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +static int +cd9660_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct iso_directory_record *ep; + size_t buf_size, reclen, namelen; + int error = 0; + char *buf; + +again: + if (fp->f_off >= fp->f_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + ep = (struct iso_directory_record *)buf; + + if (isonum_711(ep->length) == 0) { + daddr_t blkno; + + /* skip to next block, if any */ + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; + fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; + goto again; + } + + namelen = isonum_711(ep->name_len); + if (namelen == 1 && ep->name[0] == 1) + namelen = 2; + reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; + reclen = (reclen + 3) & ~3; + + d->d_fileno = isonum_733(ep->extent); + d->d_reclen = reclen; + if (isonum_711(ep->flags) & 2) + d->d_type = DT_DIR; else - return cd9660_readfile(f, start, size, resid); + d->d_type = DT_REG; + d->d_namlen = namelen; + + if (isonum_711(ep->name_len) == 1 && ep->name[0] == 0) + strcpy(d->d_name, "."); + else if (isonum_711(ep->name_len) == 1 && ep->name[0] == 1) + strcpy(d->d_name, ".."); + else + bcopy(ep->name, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = 0; + + fp->f_off += isonum_711(ep->length); + return (0); } static int @@ -431,18 +396,18 @@ cd9660_seek(f, offset, where) switch (where) { case SEEK_SET: - fp->off = offset; + fp->f_off = offset; break; case SEEK_CUR: - fp->off += offset; + fp->f_off += offset; break; case SEEK_END: - fp->off = fp->size - offset; + fp->f_off = fp->f_size - offset; break; default: return -1; } - return fp->off; + return fp->f_off; } static int @@ -454,11 +419,11 @@ cd9660_stat(f, sb) /* only important stuff */ sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; - if (fp->isdir) + if (fp->f_isdir) sb->st_mode |= S_IFDIR; else sb->st_mode |= S_IFREG; sb->st_uid = sb->st_gid = 0; - sb->st_size = fp->size; + sb->st_size = fp->f_size; return 0; } diff --git a/lib/libstand/dosfs.c b/lib/libstand/dosfs.c index 2910cb2de92e..3646a9ea7233 100644 --- a/lib/libstand/dosfs.c +++ b/lib/libstand/dosfs.c @@ -23,6 +23,8 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ */ /* @@ -46,7 +48,14 @@ static off_t dos_seek(struct open_file *fd, off_t offset, int whence); static int dos_stat(struct open_file *fd, struct stat *sb); struct fs_ops dosfs_fsops = { - "dosfs", dos_open, dos_close, dos_read, null_write, dos_seek, dos_stat + "dosfs", + dos_open, + dos_close, + dos_read, + null_write, + dos_seek, + dos_stat, + null_readdir }; #define SECSIZ 512 /* sector size */ diff --git a/lib/libstand/gzipfs.c b/lib/libstand/gzipfs.c index b0e30073cd7e..bcf0acea9205 100644 --- a/lib/libstand/gzipfs.c +++ b/lib/libstand/gzipfs.c @@ -56,7 +56,8 @@ struct fs_ops zipfs_fsops = { zf_read, null_write, zf_seek, - zf_stat + zf_stat, + null_readdir }; #if 0 diff --git a/lib/libstand/libstand.3 b/lib/libstand/libstand.3 index e38fbf78e53a..7d0c65ac4970 100644 --- a/lib/libstand/libstand.3 +++ b/lib/libstand/libstand.3 @@ -417,6 +417,8 @@ the consumer may supply other filesystems of their own: .Bl -hang -width "cd9660_fsops " .It ufs_fsops The BSD UFS. +.It ext2fs_fsops +Linux ext2fs filesystem. .It tftp_fsops File access via TFTP. .It nfs_fsops diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c index 7b0e783e617d..1206bb75d8f9 100644 --- a/lib/libstand/nfs.c +++ b/lib/libstand/nfs.c @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ /*- @@ -109,10 +110,16 @@ static off_t nfs_seek(struct open_file *f, off_t offset, int where); static int nfs_stat(struct open_file *f, struct stat *sb); struct fs_ops nfs_fsops = { - "nfs", nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat + "nfs", + nfs_open, + nfs_close, + nfs_read, + nfs_write, + nfs_seek, + nfs_stat, + null_readdir }; - /* * Fetch the root file handle (call mount daemon) * Return zero or error number. diff --git a/lib/libstand/nullfs.c b/lib/libstand/nullfs.c index 96e69d2fa905..0f77bd4c185c 100644 --- a/lib/libstand/nullfs.c +++ b/lib/libstand/nullfs.c @@ -104,3 +104,9 @@ int null_stat (struct open_file *f, struct stat *sb) errno = EIO; return -1; } + +int null_readdir(struct open_file *f, struct dirent *d) +{ + errno = EIO; + return -1; +} diff --git a/lib/libstand/readdir.c b/lib/libstand/readdir.c new file mode 100644 index 000000000000..f34dc881558f --- /dev/null +++ b/lib/libstand/readdir.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1999,2000 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include "stand.h" + +struct dirent * +readdirfd(int fd) +{ + static struct dirent dir; /* XXX not thread safe */ + struct open_file *f = &files[fd]; + + if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + errno = EBADF; + return (NULL); + } + if (f->f_flags & F_RAW) { + errno = EIO; + return (NULL); + } + errno = (f->f_ops->fo_readdir)(f, &dir); + if (errno) + return (NULL); + return (&dir); +} diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h index 23626a5635e1..5fd209d98e40 100644 --- a/lib/libstand/stand.h +++ b/lib/libstand/stand.h @@ -65,6 +65,7 @@ #include #include #include +#include #define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __FUNCTION__, __LINE__ , ##args) #define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __FUNCTION__, __LINE__ , ##args); getchar();} @@ -109,6 +110,7 @@ struct fs_ops { size_t size, size_t *resid); off_t (*fo_seek)(struct open_file *f, off_t offset, int where); int (*fo_stat)(struct open_file *f, struct stat *sb); + int (*fo_readdir)(struct open_file *f, struct dirent *d); }; /* @@ -120,6 +122,7 @@ extern struct fs_ops nfs_fsops; extern struct fs_ops cd9660_fsops; extern struct fs_ops zipfs_fsops; extern struct fs_ops dosfs_fsops; +extern struct fs_ops ext2fs_fsops; /* where values for lseek(2) */ #define SEEK_SET 0 /* set file offset to offset */ @@ -141,6 +144,11 @@ struct devsw { void (*dv_cleanup)(); }; +/* + * libstand-supplied device switch + */ +extern struct devsw netdev; + extern int errno; struct open_file { @@ -221,6 +229,7 @@ extern ssize_t read(int, void *, size_t); extern ssize_t write(int, void *, size_t); extern off_t lseek(int, off_t, int); extern int stat(const char *, struct stat *); +extern struct dirent *readdirfd(int); extern void srandom(u_long seed); extern u_long random(void); @@ -312,6 +321,8 @@ extern int null_read(struct open_file *f, void *buf, size_t size, size_t *resid) extern int null_write(struct open_file *f, void *buf, size_t size, size_t *resid); extern off_t null_seek(struct open_file *f, off_t offset, int where); extern int null_stat(struct open_file *f, struct stat *sb); +extern int null_readdir(struct open_file *f, struct dirent *d); + /* * Machine dependent functions and data, must be provided or stubbed by diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c index 63d32d95a798..e7f885d9071d 100644 --- a/lib/libstand/tftp.c +++ b/lib/libstand/tftp.c @@ -67,7 +67,14 @@ static off_t tftp_seek(struct open_file *f, off_t offset, int where); static int tftp_stat(struct open_file *f, struct stat *sb); struct fs_ops tftp_fsops = { - "tftp", tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek, tftp_stat + "tftp", + tftp_open, + tftp_close, + tftp_read, + tftp_write, + tftp_seek, + tftp_stat, + null_readdir }; extern struct in_addr servip; diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c index 8511422f162b..0db2393d9e13 100644 --- a/lib/libstand/ufs.c +++ b/lib/libstand/ufs.c @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ /* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ /*- @@ -83,9 +84,17 @@ static int ufs_close(struct open_file *f); static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t ufs_seek(struct open_file *f, off_t offset, int where); static int ufs_stat(struct open_file *f, struct stat *sb); +static int ufs_readdir(struct open_file *f, struct dirent *d); struct fs_ops ufs_fsops = { - "ufs", ufs_open, ufs_close, ufs_read, null_write, ufs_seek, ufs_stat + "ufs", + ufs_open, + ufs_close, + ufs_read, + null_write, + ufs_seek, + ufs_stat, + ufs_readdir }; /* @@ -686,6 +695,33 @@ ufs_stat(f, sb) return (0); } +static int +ufs_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp; + char *buf; + size_t buf_size; + int error; + + /* + * assume that a directory entry will not be split across blocks + */ +again: + if (fp->f_seekp >= fp->f_di.di_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + dp = (struct direct *)buf; + fp->f_seekp += dp->d_reclen; + if (dp->d_ino == (ino_t)0) + goto again; + d->d_type = dp->d_type; + strcpy(d->d_name, dp->d_name); + return (0); +} + #ifdef COMPAT_UFS /* * Sanity checks for old file systems. diff --git a/lib/libstand/zipfs.c b/lib/libstand/zipfs.c index b0e30073cd7e..bcf0acea9205 100644 --- a/lib/libstand/zipfs.c +++ b/lib/libstand/zipfs.c @@ -56,7 +56,8 @@ struct fs_ops zipfs_fsops = { zf_read, null_write, zf_seek, - zf_stat + zf_stat, + null_readdir }; #if 0