On Thu, Mar 11, 2021 at 08:40:46PM -0800, Mike Larkin wrote: > On Thu, Mar 11, 2021 at 06:11:03PM -0500, Dave Voutila wrote: > > tl;dr: tedu vmboot.{c,h}, ufs.c from vmd(8) to remove broken ability to > > exract and boot a kernel image from a raw or qcow2 disk image > > > > The following diff removes the ability to boot directly from a disk > > image containing a FFS filesystem. No new functionality is added. It's > > still possible to boot via a kernel image or with either disk or iso > > images via seabios. (PXE booting should still work via a kernel image, > > but I haven't tested it personally.) > > > > Why remove this? > > > > - since 6.7 switched to FFS2 as the default filesystem for new installs, > > the ability for vmd(8) to load a kernel and boot.conf from a disk > > image directly (without seabios) has been broken. tb@ apparently sent > > a diff to update support for FFS2 awhile back, but it never made it > > into the tree. > > > > - on 5th Jan 2021, new ramdisks for amd64 have started shipping gzip'd, > > breaking the ability to load the bsd.rd directly as a kernel image for > > a vmd(8) guest without first uncompressing the image > > > > Why not fix it? > > > > - using bios (via seabios) works > > > > - the FFS2 change happened ten months ago and afaict few if any have > > complained about the breakage, so I'm not sure the value in fixing > > it. vmctl(8) is still vague about supporting it per its man page and > > you still have to pass the disk image twice as a -b and -d arg if > > you're trying to avoid using seabios to boot an OpenBSD guest. > > > > - Josh Rickmar reported the gzip issue on bugs@ and provided patches to > > add in support for compressed ramdisks and kernel images. In doing so, > > we found the easiest way to add gzip kernel image support was to drop > > support for FFS images since they require a call to fmemopen(3) while > > all the other logic uses fopen(3)/fdopen(3) calls and a file > > descriptor. I think it would be easier to get his patches into vmd(8) > > if they don't have to account for extracting kernels from disk > > images. > > > > I can understand an argument to shy away from relying on seabios for > > booting, but given it's readily available via fw_update(1) and is part > > of the default behavior, I'd imagine most won't miss this feature. > > > > If people ARE using direct booting of raw/qcow2 images (without using > > seabios) please speak up and instead I can look into dusting off tb@'s > > old diff. > > > > reyk@ wrote that ffs module for vmd but since he has not stepped up to > maintain it after the ffs2 switch, I vote to remove it. If someone wants > to come back and fixup ffs2 support with the tb@ diff we can look at that > when said person steps up. > > ok mlarkin
Let's face it. It's unmaintained and now it's getting in the way of progress: - ffs2 doesn't work - sysupgrade doesn't work - nobody noticed or cared Here's the diff for ffs2 support if anyone needs it. Index: Makefile =================================================================== RCS file: /cvs/src/usr.sbin/vmd/Makefile,v retrieving revision 1.24 diff -u -p -r1.24 Makefile --- Makefile 23 Sep 2020 19:18:18 -0000 1.24 +++ Makefile 26 Jan 2021 20:59:22 -0000 @@ -5,7 +5,7 @@ PROG= vmd SRCS= vmd.c control.c log.c priv.c proc.c config.c vmm.c SRCS+= vm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c -SRCS+= ns8250.c i8253.c vmboot.c ufs.c disklabel.c dhcp.c packet.c +SRCS+= ns8250.c i8253.c vmboot.c ufs.c ufs2.c disklabel.c dhcp.c packet.c SRCS+= parse.y atomicio.c vioscsi.c vioraw.c vioqcow2.c fw_cfg.c CFLAGS+= -Wall -I${.CURDIR} Index: vmboot.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/vmboot.c,v retrieving revision 1.8 diff -u -p -r1.8 vmboot.c --- vmboot.c 10 Dec 2020 16:58:03 -0000 1.8 +++ vmboot.c 26 Jan 2021 20:59:22 -0000 @@ -225,9 +225,27 @@ vmboot_bootconf(char *conf, size_t size, /* - * For ufs.c + * For ufs.c and ufs2.c */ +struct fs_ops ffs_ops = { + .open = ufs_open, + .close = ufs_close, + .read = ufs_read, + .write = ufs_write, + .seek = ufs_seek, + .stat = ufs_stat, +}; + +struct fs_ops ffs2_ops = { + .open = ufs2_open, + .close = ufs2_close, + .read = ufs2_read, + .write = ufs2_write, + .seek = ufs2_seek, + .stat = ufs2_stat, +}; + struct devsw vmboot_devsw = { .dv_name = "vmboot", .dv_strategy = vmboot_strategy, @@ -358,10 +376,16 @@ vmboot_loadfile(struct open_file *f, cha *size = 0; - if ((ret = ufs_open(file, f)) != 0) - return (NULL); + if ((ret = f->f_ops->open(file, f)) != 0) { + if (f->f_ops == &ffs_ops || ret != EINVAL) + return (NULL); + + log_debug("%s: opening %s using ufs", __func__, file); + f->f_ops = &ffs_ops; + return (vmboot_loadfile(f, file, size)); + } - if ((ret = ufs_stat(f, &st)) != 0) { + if ((ret = f->f_ops->stat(f, &st)) != 0) { log_debug("%s: failed to stat %s", __func__, file); goto done; } @@ -371,7 +395,7 @@ vmboot_loadfile(struct open_file *f, cha goto done; } - if ((ret = ufs_read(f, buf, st.st_size, &rsize)) != 0) { + if ((ret = f->f_ops->read(f, buf, st.st_size, &rsize)) != 0) { log_debug("%s: failed to read %s", __func__, file); free(buf); goto done; @@ -380,7 +404,7 @@ vmboot_loadfile(struct open_file *f, cha *size = st.st_size; p = buf; done: - ufs_close(f); + f->f_ops->close(f); return (p); } @@ -428,6 +452,7 @@ vmboot_open(int kernel_fd, int *disk_fd, } vmboot_file.f_devdata = vmboot; + vmboot_file.f_ops = &ffs2_ops; if ((vmboot->vbp_partoff = vmboot_findopenbsd(&vmboot_file, 0, &dl)) == -1) { Index: vmboot.h =================================================================== RCS file: /cvs/src/usr.sbin/vmd/vmboot.h,v retrieving revision 1.3 diff -u -p -r1.3 vmboot.h --- vmboot.h 10 Dec 2020 16:58:03 -0000 1.3 +++ vmboot.h 26 Jan 2021 20:59:22 -0000 @@ -72,4 +72,13 @@ off_t ufs_seek(struct open_file *, off_t int ufs_stat(struct open_file *, struct stat *); int ufs_readdir(struct open_file *, char *); +int ufs2_open(char *, struct open_file *); +int ufs2_close(struct open_file *); +int ufs2_fchmod(struct open_file *, mode_t); +int ufs2_read(struct open_file *, void *, size_t, size_t *); +int ufs2_write(struct open_file *, void *, size_t, size_t *); +off_t ufs2_seek(struct open_file *, off_t offset, int); +int ufs2_stat(struct open_file *, struct stat *); +int ufs2_readdir(struct open_file *, char *); + #endif /* VMBOOT_H */ Index: ufs2.c =================================================================== RCS file: ufs2.c diff -N ufs2.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ufs2.c 26 Jan 2021 20:59:55 -0000 @@ -0,0 +1,772 @@ +/* $OpenBSD: ufs2.c,v 1.8 2019/08/03 15:22:17 deraadt Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or software.distribut...@cs.cmu.edu + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Stand-alone file reading package. + */ + +#include <sys/param.h> /* DEV_BSIZE MAXBSIZE */ +#include <sys/time.h> +#include <sys/stat.h> +#include <ufs/ffs/fs.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> + +#include <limits.h> + +#include "vmboot.h" + +/* Used in the kernel by libsa */ +#define alloc malloc +#define free(_p, _n) free(_p) +#define twiddle() do { } while(0) +#define NO_READDIR 1 + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + struct fs *f_fs; /* pointer to super-block */ + struct ufs2_dinode f_di; /* copy of on-disk inode */ + ufsino_t f_ino; /* our inode number */ + int f_nindir[NIADDR]; + /* number of blocks mapped by + indirect block at level i */ + char *f_blk[NIADDR]; /* buffer for indirect block at + level i */ + size_t f_blksize[NIADDR]; + /* size of buffer */ + daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ + daddr_t f_buf_blkno; /* block number of data block */ +}; + +static int read_inode(ufsino_t, struct open_file *); +static int chmod_inode(ufsino_t, struct open_file *, mode_t); +static int block_map(struct open_file *, daddr_t, daddr_t *); +static int buf_read_file(struct open_file *, char **, size_t *); +static int search_directory(char *, struct open_file *, ufsino_t *); +static int ufs2_close_internal(struct file *); +#ifdef COMPAT_UFS +static void ffs_oldfscompat(struct fs *); +#endif + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ufsino_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + + /* + * Read inode and save it. + */ + buf = alloc(fs->fs_bsize); + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize); + if (rc) + goto out; + if (rsize != (size_t)fs->fs_bsize) { + rc = EIO; + goto out; + } + + { + struct ufs2_dinode *dp; + + dp = (struct ufs2_dinode *)buf; + fp->f_di = dp[ino_to_fsbo(fs, inumber)]; + } + + /* + * Clear out the old buffers + */ + { + int level; + + for (level = 0; level < NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + fp->f_seekp = 0; + } +out: + free(buf, fs->fs_bsize); + return (rc); +} + +/* + * Read a new inode into a file structure. + */ +static int +chmod_inode(ufsino_t inumber, struct open_file *f, mode_t mode) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + + /* + * Read inode and save it. + */ + buf = alloc(fs->fs_bsize); + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize); + if (rc) + goto out; + if (rsize != (size_t)fs->fs_bsize) { + rc = EIO; + goto out; + } + + { + struct ufs2_dinode *dp; + + dp = &((struct ufs2_dinode *)buf)[ino_to_fsbo(fs, inumber)]; + dp->di_mode = mode; + } + + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, NULL); + +out: + free(buf, fs->fs_bsize); + return (rc); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + daddr_t ind_block_num, *ind_p; + struct fs *fs = fp->f_fs; + int level, idx, rc; + + /* + * Index structure of an inode: + * + * di_db[0..NDADDR-1] hold block numbers for blocks + * 0..NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * NDADDR .. NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * NDADDR + NINDIR(fs) .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < NDADDR) { + /* Direct block. */ + *disk_block_p = fp->f_di.di_db[file_block]; + return (0); + } + + file_block -= NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = fp->f_di.di_ib[level]; + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == NULL) + fp->f_blk[level] = + alloc(fs->fs_bsize); + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize, + fp->f_blk[level], &fp->f_blksize[level]); + if (rc) + return (rc); + if (fp->f_blksize[level] != (size_t)fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + ind_p = (daddr_t *)fp->f_blk[level]; + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else + idx = file_block; + + ind_block_num = ind_p[idx]; + } + + *disk_block_p = ind_block_num; + return (0); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + daddr_t file_block, disk_block; + size_t block_size; + long off; + int rc; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = dblksize(fs, &fp->f_di, (u_int64_t)file_block); + + if (file_block != fp->f_buf_blkno) { + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (fp->f_buf == NULL) + fp->f_buf = alloc(fs->fs_bsize); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + } + + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > fp->f_di.di_size - fp->f_seekp) + *size_p = fp->f_di.di_size - fp->f_seekp; + + return (0); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(char *name, struct open_file *f, ufsino_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + int namlen, length, rc; + struct direct *dp, *edp; + size_t buf_size; + char *buf; + + length = strlen(name); + + fp->f_seekp = 0; + while ((u_int64_t)fp->f_seekp < fp->f_di.di_size) { + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + return (rc); + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == 0) + goto next; +#if BYTE_ORDER == LITTLE_ENDIAN + if (fp->f_fs->fs_maxsymlinklen <= 0) + namlen = dp->d_type; + else +#endif + namlen = dp->d_namlen; + if (namlen == length && + !strcmp(name, dp->d_name)) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +/* + * Open a file. + */ +int +ufs2_open(char *path, struct open_file *f) +{ + char namebuf[PATH_MAX+1], *cp, *ncp, *buf = NULL; + ufsino_t inumber, parent_inumber; + int rc, c, nlinks = 0; + struct file *fp; + size_t buf_size; + struct fs *fs; + + /* allocate file system specific data structure */ + fp = alloc(sizeof(struct file)); + memset(fp, 0, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = alloc(SBSIZE); + fp->f_fs = fs; + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + SBLOCK_UFS2 / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size); + if (rc) + goto out; + + if (buf_size != SBSIZE || fs->fs_magic != FS_UFS2_MAGIC || + (u_int64_t)fs->fs_bsize > MAXBSIZE || + (u_int64_t)fs->fs_bsize < sizeof(struct fs)) { + rc = EINVAL; + goto out; + } +#ifdef COMPAT_UFS + ffs_oldfscompat(fs); +#endif + + /* + * Calculate indirect block levels. + */ + { + int mult; + int level; + + mult = 1; + for (level = 0; level < NIADDR; level++) { + mult *= NINDIR(fs); + fp->f_nindir[level] = mult; + } + } + + inumber = ROOTINO; + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + cp = path; + while (*cp) { + + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if ((fp->f_di.di_mode & IFMT) != IFDIR) { + rc = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > MAXNAMLEN) { + rc = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + rc = search_directory(ncp, f, &inumber); + *cp = c; + if (rc) + goto out; + + /* + * Open next component. + */ + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if ((fp->f_di.di_mode & IFMT) == IFLNK) { + u_int64_t link_len = fp->f_di.di_size; + size_t len; + + len = strlen(cp); + + if (link_len + len > PATH_MAX || + ++nlinks > SYMLOOP_MAX) { + rc = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + + if (link_len < (u_int64_t)fs->fs_maxsymlinklen) { + bcopy(fp->f_di.di_shortlink, namebuf, link_len); + } else { + /* + * Read file for symbolic link + */ + daddr_t disk_block; + fs = fp->f_fs; + + if (!buf) + buf = alloc(fs->fs_bsize); + rc = block_map(f, 0, &disk_block); + if (rc) + goto out; + + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsbtodb(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (rc) + goto out; + + bcopy(buf, namebuf, link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = ROOTINO; + + if ((rc = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + fp->f_ino = inumber; + rc = 0; +out: + if (buf) + free(buf, fs->fs_bsize); + if (rc) + (void)ufs2_close_internal(fp); + + return (rc); +} + +int +ufs2_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + f->f_fsdata = NULL; + if (fp == NULL) + return (0); + + return (ufs2_close_internal(fp)); +} + +static int +ufs2_close_internal(struct file *fp) +{ + int level; + + for (level = 0; level < NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level], fp->f_fs->fs_bsize); + } + if (fp->f_buf) + free(fp->f_buf, fp->f_fs->fs_bsize); + free(fp->f_fs, SBSIZE); + free(fp, sizeof(struct file)); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +int +ufs2_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + char *buf, *addr = start; + size_t csize, buf_size; + int rc = 0; + + while (size != 0) { + if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +/* + * Not implemented. + */ +int +ufs2_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + + return (EROFS); +} + +off_t +ufs2_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = fp->f_di.di_size - offset; + break; + default: + return (-1); + } + return (fp->f_seekp); +} + +int +ufs2_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = fp->f_di.di_mode; + sb->st_uid = fp->f_di.di_uid; + sb->st_gid = fp->f_di.di_gid; + sb->st_size = fp->f_di.di_size; + return (0); +} + +int +ufs2_fchmod(struct open_file *f, mode_t mode) +{ + struct file *fp = (struct file *)f->f_fsdata; + + return chmod_inode(fp->f_ino, f, mode); +} + +#ifndef NO_READDIR +int +ufs2_readdir(struct open_file *f, char *name) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp, *edp; + size_t buf_size; + int rc, namlen; + char *buf; + + if (name == NULL) + fp->f_seekp = 0; + else { + /* end of dir */ + if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size) { + *name = '\0'; + return -1; + } + + do { + if ((rc = buf_read_file(f, &buf, &buf_size)) != 0) + return rc; + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp && dp->d_ino == 0) + dp = (struct direct *)((char *)dp + dp->d_reclen); + fp->f_seekp += buf_size - + ((u_int8_t *)edp - (u_int8_t *)dp); + } while (dp >= edp); + +#if BYTE_ORDER == LITTLE_ENDIAN + if (fp->f_fs->fs_maxsymlinklen <= 0) + namlen = dp->d_type; + else +#endif + namlen = dp->d_namlen; + strncpy(name, dp->d_name, namlen + 1); + + fp->f_seekp += dp->d_reclen; + } + + return 0; +} +#endif + +#ifdef COMPAT_UFS +/* + * Sanity checks for old file systems. + * + * XXX - goes away some day. + */ +static void +ffs_oldfscompat(struct fs *fs) +{ + int i; + + fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ + fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + fs->fs_nrpos = 8; /* XXX */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + quad_t sizepb = fs->fs_bsize; /* XXX */ + /* XXX */ + fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ + for (i = 0; i < NIADDR; i++) { /* XXX */ + sizepb *= NINDIR(fs); /* XXX */ + fs->fs_maxfilesize += sizepb; /* XXX */ + } /* XXX */ + fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ + fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ + } /* XXX */ +} +#endif