summaryrefslogtreecommitdiffstats
path: root/usr.sbin/makefs/ffs
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/makefs/ffs')
-rw-r--r--usr.sbin/makefs/ffs/Makefile.inc9
-rw-r--r--usr.sbin/makefs/ffs/buf.c222
-rw-r--r--usr.sbin/makefs/ffs/buf.h67
-rw-r--r--usr.sbin/makefs/ffs/ffs_alloc.c681
-rw-r--r--usr.sbin/makefs/ffs/ffs_balloc.c578
-rw-r--r--usr.sbin/makefs/ffs/ffs_bswap.c260
-rw-r--r--usr.sbin/makefs/ffs/ffs_extern.h77
-rw-r--r--usr.sbin/makefs/ffs/ffs_subr.c193
-rw-r--r--usr.sbin/makefs/ffs/mkfs.c839
-rw-r--r--usr.sbin/makefs/ffs/newfs_extern.h36
-rw-r--r--usr.sbin/makefs/ffs/ufs_bmap.c140
-rw-r--r--usr.sbin/makefs/ffs/ufs_bswap.h90
-rw-r--r--usr.sbin/makefs/ffs/ufs_inode.h97
13 files changed, 3289 insertions, 0 deletions
diff --git a/usr.sbin/makefs/ffs/Makefile.inc b/usr.sbin/makefs/ffs/Makefile.inc
new file mode 100644
index 0000000..d681c4e
--- /dev/null
+++ b/usr.sbin/makefs/ffs/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/ffs ${.CURDIR}/../../sys/ufs/ffs
+
+CFLAGS+= -I${.CURDIR}/../../sys/ufs/ffs
+
+SRCS+= ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c ufs_bmap.c
+SRCS+= buf.c mkfs.c
diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c
new file mode 100644
index 0000000..06538f5
--- /dev/null
+++ b/usr.sbin/makefs/ffs/buf.c
@@ -0,0 +1,222 @@
+/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Luke Mewburn for Wasabi Systems, Inc.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "makefs.h"
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include "ffs/buf.h"
+#include "ffs/ufs_inode.h"
+
+extern int sectorsize; /* XXX: from ffs.c & mkfs.c */
+
+TAILQ_HEAD(buftailhead,buf) buftail;
+
+int
+bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp)
+{
+ off_t offset;
+ ssize_t rv;
+
+ assert (fs != NULL);
+ assert (bpp != NULL);
+
+ if (debug & DEBUG_BUF_BREAD)
+ printf("bread: fs %p blkno %lld size %d\n",
+ fs, (long long)blkno, size);
+ *bpp = getblk(fd, fs, blkno, size);
+ offset = (*bpp)->b_blkno * sectorsize; /* XXX */
+ if (debug & DEBUG_BUF_BREAD)
+ printf("bread: bp %p blkno %lld offset %lld bcount %ld\n",
+ (*bpp), (long long)(*bpp)->b_blkno, (long long) offset,
+ (*bpp)->b_bcount);
+ if (lseek((*bpp)->b_fd, offset, SEEK_SET) == -1)
+ err(1, "bread: lseek %lld (%lld)",
+ (long long)(*bpp)->b_blkno, (long long)offset);
+ rv = read((*bpp)->b_fd, (*bpp)->b_data, (*bpp)->b_bcount);
+ if (debug & DEBUG_BUF_BREAD)
+ printf("bread: read %ld (%lld) returned %d\n",
+ (*bpp)->b_bcount, (long long)offset, (int)rv);
+ if (rv == -1) /* read error */
+ err(1, "bread: read %ld (%lld) returned %d",
+ (*bpp)->b_bcount, (long long)offset, (int)rv);
+ else if (rv != (*bpp)->b_bcount) /* short read */
+ err(1, "bread: read %ld (%lld) returned %d",
+ (*bpp)->b_bcount, (long long)offset, (int)rv);
+ else
+ return (0);
+}
+
+void
+brelse(struct buf *bp)
+{
+
+ assert (bp != NULL);
+ assert (bp->b_data != NULL);
+
+ if (bp->b_lblkno < 0) {
+ /*
+ * XXX don't remove any buffers with negative logical block
+ * numbers (lblkno), so that we retain the mapping
+ * of negative lblkno -> real blkno that ffs_balloc()
+ * sets up.
+ *
+ * if we instead released these buffers, and implemented
+ * ufs_strategy() (and ufs_bmaparray()) and called those
+ * from bread() and bwrite() to convert the lblkno to
+ * a real blkno, we'd add a lot more code & complexity
+ * and reading off disk, for little gain, because this
+ * simple hack works for our purpose.
+ */
+ bp->b_bcount = 0;
+ return;
+ }
+
+ TAILQ_REMOVE(&buftail, bp, b_tailq);
+ free(bp->b_data);
+ free(bp);
+}
+
+int
+bwrite(struct buf *bp)
+{
+ off_t offset;
+ ssize_t rv;
+
+ assert (bp != NULL);
+ offset = bp->b_blkno * sectorsize; /* XXX */
+ if (debug & DEBUG_BUF_BWRITE)
+ printf("bwrite: bp %p blkno %lld offset %lld bcount %ld\n",
+ bp, (long long)bp->b_blkno, (long long) offset,
+ bp->b_bcount);
+ if (lseek(bp->b_fd, offset, SEEK_SET) == -1)
+ return (errno);
+ rv = write(bp->b_fd, bp->b_data, bp->b_bcount);
+ if (debug & DEBUG_BUF_BWRITE)
+ printf("bwrite: write %ld (offset %lld) returned %lld\n",
+ bp->b_bcount, (long long)offset, (long long)rv);
+ if (rv == bp->b_bcount)
+ return (0);
+ else if (rv == -1) /* write error */
+ return (errno);
+ else /* short write ? */
+ return (EAGAIN);
+}
+
+void
+bcleanup(void)
+{
+ struct buf *bp;
+
+ /*
+ * XXX this really shouldn't be necessary, but i'm curious to
+ * know why there's still some buffers lying around that
+ * aren't brelse()d
+ */
+
+ if (TAILQ_EMPTY(&buftail))
+ return;
+
+ printf("bcleanup: unflushed buffers:\n");
+ TAILQ_FOREACH(bp, &buftail, b_tailq) {
+ printf("\tlblkno %10lld blkno %10lld count %6ld bufsize %6ld\n",
+ (long long)bp->b_lblkno, (long long)bp->b_blkno,
+ bp->b_bcount, bp->b_bufsize);
+ }
+ printf("bcleanup: done\n");
+}
+
+struct buf *
+getblk(int fd, struct fs *fs, daddr_t blkno, int size)
+{
+ static int buftailinitted;
+ struct buf *bp;
+ void *n;
+
+ assert (fs != NULL);
+ if (debug & DEBUG_BUF_GETBLK)
+ printf("getblk: fs %p blkno %lld size %d\n", fs,
+ (long long)blkno, size);
+
+ bp = NULL;
+ if (!buftailinitted) {
+ if (debug & DEBUG_BUF_GETBLK)
+ printf("getblk: initialising tailq\n");
+ TAILQ_INIT(&buftail);
+ buftailinitted = 1;
+ } else {
+ TAILQ_FOREACH(bp, &buftail, b_tailq) {
+ if (bp->b_lblkno != blkno)
+ continue;
+ break;
+ }
+ }
+ if (bp == NULL) {
+ if ((bp = calloc(1, sizeof(struct buf))) == NULL)
+ err(1, "getblk: calloc");
+
+ bp->b_bufsize = 0;
+ bp->b_blkno = bp->b_lblkno = blkno;
+ bp->b_fd = fd;
+ bp->b_fs = fs;
+ bp->b_data = NULL;
+ TAILQ_INSERT_HEAD(&buftail, bp, b_tailq);
+ }
+ bp->b_bcount = size;
+ if (bp->b_data == NULL || bp->b_bcount > bp->b_bufsize) {
+ n = realloc(bp->b_data, size);
+ if (n == NULL)
+ err(1, "getblk: realloc b_data %ld", bp->b_bcount);
+ bp->b_data = n;
+ bp->b_bufsize = size;
+ }
+
+ return (bp);
+}
diff --git a/usr.sbin/makefs/ffs/buf.h b/usr.sbin/makefs/ffs/buf.h
new file mode 100644
index 0000000..02c6713
--- /dev/null
+++ b/usr.sbin/makefs/ffs/buf.h
@@ -0,0 +1,67 @@
+/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Luke Mewburn for Wasabi Systems, Inc.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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$
+ */
+
+#ifndef _FFS_BUF_H
+#define _FFS_BUF_H
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+struct buf {
+ void * b_data;
+ long b_bufsize;
+ long b_bcount;
+ daddr_t b_blkno;
+ daddr_t b_lblkno;
+ int b_fd;
+ struct fs * b_fs;
+
+ TAILQ_ENTRY(buf) b_tailq;
+};
+
+void bcleanup(void);
+int bread(int, struct fs *, daddr_t, int, struct buf **);
+void brelse(struct buf *);
+int bwrite(struct buf *);
+struct buf * getblk(int, struct fs *, daddr_t, int);
+
+#define bdwrite(bp) bwrite(bp)
+#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount)
+
+#endif /* _FFS_BUF_H */
diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c
new file mode 100644
index 0000000..afab869
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ffs_alloc.c
@@ -0,0 +1,681 @@
+/* $NetBSD: ffs_alloc.c,v 1.14 2004/06/20 22:20:18 jmc Exp $ */
+/* From: NetBSD: ffs_alloc.c,v 1.50 2001/09/06 02:16:01 lukem Exp */
+
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. 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.
+ * 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.
+ *
+ * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <stdint.h>
+
+#include "makefs.h"
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include "ffs/ufs_bswap.h"
+#include "ffs/buf.h"
+#include "ffs/ufs_inode.h"
+#include "ffs/ffs_extern.h"
+
+static int scanc(u_int, const u_char *, const u_char *, int);
+
+static daddr_t ffs_alloccg(struct inode *, int, daddr_t, int);
+static daddr_t ffs_alloccgblk(struct inode *, struct buf *, daddr_t);
+static daddr_t ffs_hashalloc(struct inode *, int, daddr_t, int,
+ daddr_t (*)(struct inode *, int, daddr_t, int));
+static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int);
+
+/*
+ * Allocate a block in the file system.
+ *
+ * The size of the requested block is given, which must be some
+ * multiple of fs_fsize and <= fs_bsize.
+ * A preference may be optionally specified. If a preference is given
+ * the following hierarchy is used to allocate a block:
+ * 1) allocate the requested block.
+ * 2) allocate a rotationally optimal block in the same cylinder.
+ * 3) allocate a block in the same cylinder group.
+ * 4) quadradically rehash into other cylinder groups, until an
+ * available block is located.
+ * If no block preference is given the following hierarchy is used
+ * to allocate a block:
+ * 1) allocate a block in the cylinder group that contains the
+ * inode for the file.
+ * 2) quadradically rehash into other cylinder groups, until an
+ * available block is located.
+ */
+int
+ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size,
+ daddr_t *bnp)
+{
+ struct fs *fs = ip->i_fs;
+ daddr_t bno;
+ int cg;
+
+ *bnp = 0;
+ if (size > fs->fs_bsize || fragoff(fs, size) != 0) {
+ errx(1, "ffs_alloc: bad size: bsize %d size %d",
+ fs->fs_bsize, size);
+ }
+ if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
+ goto nospace;
+ if (bpref >= fs->fs_size)
+ bpref = 0;
+ if (bpref == 0)
+ cg = ino_to_cg(fs, ip->i_number);
+ else
+ cg = dtog(fs, bpref);
+ bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg);
+ if (bno > 0) {
+ if (ip->i_fs->fs_magic == FS_UFS1_MAGIC)
+ ip->i_ffs1_blocks += size / DEV_BSIZE;
+ else
+ ip->i_ffs2_blocks += size / DEV_BSIZE;
+ *bnp = bno;
+ return (0);
+ }
+nospace:
+ return (ENOSPC);
+}
+
+/*
+ * Select the desired position for the next block in a file. The file is
+ * logically divided into sections. The first section is composed of the
+ * direct blocks. Each additional section contains fs_maxbpg blocks.
+ *
+ * If no blocks have been allocated in the first section, the policy is to
+ * request a block in the same cylinder group as the inode that describes
+ * the file. If no blocks have been allocated in any other section, the
+ * policy is to place the section in a cylinder group with a greater than
+ * average number of free blocks. An appropriate cylinder group is found
+ * by using a rotor that sweeps the cylinder groups. When a new group of
+ * blocks is needed, the sweep begins in the cylinder group following the
+ * cylinder group from which the previous allocation was made. The sweep
+ * continues until a cylinder group with greater than the average number
+ * of free blocks is found. If the allocation is for the first block in an
+ * indirect block, the information on the previous allocation is unavailable;
+ * here a best guess is made based upon the logical block number being
+ * allocated.
+ *
+ * If a section is already partially allocated, the policy is to
+ * contiguously allocate fs_maxcontig blocks. The end of one of these
+ * contiguous blocks and the beginning of the next is physically separated
+ * so that the disk head will be in transit between them for at least
+ * fs_rotdelay milliseconds. This is to allow time for the processor to
+ * schedule another I/O transfer.
+ */
+/* XXX ondisk32 */
+daddr_t
+ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
+{
+ struct fs *fs;
+ int cg;
+ int avgbfree, startcg;
+
+ fs = ip->i_fs;
+ if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
+ if (lbn < NDADDR + NINDIR(fs)) {
+ cg = ino_to_cg(fs, ip->i_number);
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ }
+ /*
+ * Find a cylinder with greater than average number of
+ * unused data blocks.
+ */
+ if (indx == 0 || bap[indx - 1] == 0)
+ startcg =
+ ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
+ else
+ startcg = dtog(fs,
+ ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
+ startcg %= fs->fs_ncg;
+ avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
+ for (cg = startcg; cg < fs->fs_ncg; cg++)
+ if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ for (cg = 0; cg <= startcg; cg++)
+ if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ return (0);
+ }
+ /*
+ * We just always try to lay things out contiguously.
+ */
+ return ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
+}
+
+daddr_t
+ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
+{
+ struct fs *fs;
+ int cg;
+ int avgbfree, startcg;
+
+ fs = ip->i_fs;
+ if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
+ if (lbn < NDADDR + NINDIR(fs)) {
+ cg = ino_to_cg(fs, ip->i_number);
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ }
+ /*
+ * Find a cylinder with greater than average number of
+ * unused data blocks.
+ */
+ if (indx == 0 || bap[indx - 1] == 0)
+ startcg =
+ ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
+ else
+ startcg = dtog(fs,
+ ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
+ startcg %= fs->fs_ncg;
+ avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
+ for (cg = startcg; cg < fs->fs_ncg; cg++)
+ if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ }
+ for (cg = 0; cg < startcg; cg++)
+ if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+ return (fs->fs_fpg * cg + fs->fs_frag);
+ }
+ return (0);
+ }
+ /*
+ * We just always try to lay things out contiguously.
+ */
+ return ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
+}
+
+/*
+ * Implement the cylinder overflow algorithm.
+ *
+ * The policy implemented by this algorithm is:
+ * 1) allocate the block in its requested cylinder group.
+ * 2) quadradically rehash on the cylinder group number.
+ * 3) brute force search for a free block.
+ *
+ * `size': size for data blocks, mode for inodes
+ */
+/*VARARGS5*/
+static daddr_t
+ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size,
+ daddr_t (*allocator)(struct inode *, int, daddr_t, int))
+{
+ struct fs *fs;
+ daddr_t result;
+ int i, icg = cg;
+
+ fs = ip->i_fs;
+ /*
+ * 1: preferred cylinder group
+ */
+ result = (*allocator)(ip, cg, pref, size);
+ if (result)
+ return (result);
+ /*
+ * 2: quadratic rehash
+ */
+ for (i = 1; i < fs->fs_ncg; i *= 2) {
+ cg += i;
+ if (cg >= fs->fs_ncg)
+ cg -= fs->fs_ncg;
+ result = (*allocator)(ip, cg, 0, size);
+ if (result)
+ return (result);
+ }
+ /*
+ * 3: brute force search
+ * Note that we start at i == 2, since 0 was checked initially,
+ * and 1 is always checked in the quadratic rehash.
+ */
+ cg = (icg + 2) % fs->fs_ncg;
+ for (i = 2; i < fs->fs_ncg; i++) {
+ result = (*allocator)(ip, cg, 0, size);
+ if (result)
+ return (result);
+ cg++;
+ if (cg == fs->fs_ncg)
+ cg = 0;
+ }
+ return (0);
+}
+
+/*
+ * Determine whether a block can be allocated.
+ *
+ * Check to see if a block of the appropriate size is available,
+ * and if it is, allocate it.
+ */
+static daddr_t
+ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
+{
+ struct cg *cgp;
+ struct buf *bp;
+ daddr_t bno, blkno;
+ int error, frags, allocsiz, i;
+ struct fs *fs = ip->i_fs;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
+ return (0);
+ error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
+ (int)fs->fs_cgsize, &bp);
+ if (error) {
+ brelse(bp);
+ return (0);
+ }
+ cgp = (struct cg *)bp->b_data;
+ if (!cg_chkmagic_swap(cgp, needswap) ||
+ (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
+ brelse(bp);
+ return (0);
+ }
+ if (size == fs->fs_bsize) {
+ bno = ffs_alloccgblk(ip, bp, bpref);
+ bdwrite(bp);
+ return (bno);
+ }
+ /*
+ * check to see if any fragments are already available
+ * allocsiz is the size which will be allocated, hacking
+ * it down to a smaller size if necessary
+ */
+ frags = numfrags(fs, size);
+ for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
+ if (cgp->cg_frsum[allocsiz] != 0)
+ break;
+ if (allocsiz == fs->fs_frag) {
+ /*
+ * no fragments were available, so a block will be
+ * allocated, and hacked up
+ */
+ if (cgp->cg_cs.cs_nbfree == 0) {
+ brelse(bp);
+ return (0);
+ }
+ bno = ffs_alloccgblk(ip, bp, bpref);
+ bpref = dtogd(fs, bno);
+ for (i = frags; i < fs->fs_frag; i++)
+ setbit(cg_blksfree_swap(cgp, needswap), bpref + i);
+ i = fs->fs_frag - frags;
+ ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
+ fs->fs_cstotal.cs_nffree += i;
+ fs->fs_cs(fs, cg).cs_nffree += i;
+ fs->fs_fmod = 1;
+ ufs_add32(cgp->cg_frsum[i], 1, needswap);
+ bdwrite(bp);
+ return (bno);
+ }
+ bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
+ for (i = 0; i < frags; i++)
+ clrbit(cg_blksfree_swap(cgp, needswap), bno + i);
+ ufs_add32(cgp->cg_cs.cs_nffree, -frags, needswap);
+ fs->fs_cstotal.cs_nffree -= frags;
+ fs->fs_cs(fs, cg).cs_nffree -= frags;
+ fs->fs_fmod = 1;
+ ufs_add32(cgp->cg_frsum[allocsiz], -1, needswap);
+ if (frags != allocsiz)
+ ufs_add32(cgp->cg_frsum[allocsiz - frags], 1, needswap);
+ blkno = cg * fs->fs_fpg + bno;
+ bdwrite(bp);
+ return blkno;
+}
+
+/*
+ * Allocate a block in a cylinder group.
+ *
+ * This algorithm implements the following policy:
+ * 1) allocate the requested block.
+ * 2) allocate a rotationally optimal block in the same cylinder.
+ * 3) allocate the next available block on the block rotor for the
+ * specified cylinder group.
+ * Note that this routine only allocates fs_bsize blocks; these
+ * blocks may be fragmented by the routine that allocates them.
+ */
+static daddr_t
+ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
+{
+ struct cg *cgp;
+ daddr_t blkno;
+ int32_t bno;
+ struct fs *fs = ip->i_fs;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+ u_int8_t *blksfree_swap;
+
+ cgp = (struct cg *)bp->b_data;
+ blksfree_swap = cg_blksfree_swap(cgp, needswap);
+ if (bpref == 0 || (uint32_t)dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
+ bpref = ufs_rw32(cgp->cg_rotor, needswap);
+ } else {
+ bpref = blknum(fs, bpref);
+ bno = dtogd(fs, bpref);
+ /*
+ * if the requested block is available, use it
+ */
+ if (ffs_isblock(fs, blksfree_swap, fragstoblks(fs, bno)))
+ goto gotit;
+ }
+ /*
+ * Take the next available one in this cylinder group.
+ */
+ bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
+ if (bno < 0)
+ return (0);
+ cgp->cg_rotor = ufs_rw32(bno, needswap);
+gotit:
+ blkno = fragstoblks(fs, bno);
+ ffs_clrblock(fs, blksfree_swap, (long)blkno);
+ ffs_clusteracct(fs, cgp, blkno, -1);
+ ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
+ fs->fs_cstotal.cs_nbfree--;
+ fs->fs_cs(fs, ufs_rw32(cgp->cg_cgx, needswap)).cs_nbfree--;
+ fs->fs_fmod = 1;
+ blkno = ufs_rw32(cgp->cg_cgx, needswap) * fs->fs_fpg + bno;
+ return (blkno);
+}
+
+/*
+ * Free a block or fragment.
+ *
+ * The specified block or fragment is placed back in the
+ * free map. If a fragment is deallocated, a possible
+ * block reassembly is checked.
+ */
+void
+ffs_blkfree(struct inode *ip, daddr_t bno, long size)
+{
+ struct cg *cgp;
+ struct buf *bp;
+ int32_t fragno, cgbno;
+ int i, error, cg, blk, frags, bbase;
+ struct fs *fs = ip->i_fs;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ if (size > fs->fs_bsize || fragoff(fs, size) != 0 ||
+ fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
+ errx(1, "blkfree: bad size: bno %lld bsize %d size %ld",
+ (long long)bno, fs->fs_bsize, size);
+ }
+ cg = dtog(fs, bno);
+ if (bno >= fs->fs_size) {
+ warnx("bad block %lld, ino %ju", (long long)bno,
+ (uintmax_t)ip->i_number);
+ return;
+ }
+ error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
+ (int)fs->fs_cgsize, &bp);
+ if (error) {
+ brelse(bp);
+ return;
+ }
+ cgp = (struct cg *)bp->b_data;
+ if (!cg_chkmagic_swap(cgp, needswap)) {
+ brelse(bp);
+ return;
+ }
+ cgbno = dtogd(fs, bno);
+ if (size == fs->fs_bsize) {
+ fragno = fragstoblks(fs, cgbno);
+ if (!ffs_isfreeblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) {
+ errx(1, "blkfree: freeing free block %lld",
+ (long long)bno);
+ }
+ ffs_setblock(fs, cg_blksfree_swap(cgp, needswap), fragno);
+ ffs_clusteracct(fs, cgp, fragno, 1);
+ ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
+ fs->fs_cstotal.cs_nbfree++;
+ fs->fs_cs(fs, cg).cs_nbfree++;
+ } else {
+ bbase = cgbno - fragnum(fs, cgbno);
+ /*
+ * decrement the counts associated with the old frags
+ */
+ blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase);
+ ffs_fragacct_swap(fs, blk, cgp->cg_frsum, -1, needswap);
+ /*
+ * deallocate the fragment
+ */
+ frags = numfrags(fs, size);
+ for (i = 0; i < frags; i++) {
+ if (isset(cg_blksfree_swap(cgp, needswap), cgbno + i)) {
+ errx(1, "blkfree: freeing free frag: block %lld",
+ (long long)(cgbno + i));
+ }
+ setbit(cg_blksfree_swap(cgp, needswap), cgbno + i);
+ }
+ ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
+ fs->fs_cstotal.cs_nffree += i;
+ fs->fs_cs(fs, cg).cs_nffree += i;
+ /*
+ * add back in counts associated with the new frags
+ */
+ blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase);
+ ffs_fragacct_swap(fs, blk, cgp->cg_frsum, 1, needswap);
+ /*
+ * if a complete block has been reassembled, account for it
+ */
+ fragno = fragstoblks(fs, bbase);
+ if (ffs_isblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) {
+ ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap);
+ fs->fs_cstotal.cs_nffree -= fs->fs_frag;
+ fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
+ ffs_clusteracct(fs, cgp, fragno, 1);
+ ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
+ fs->fs_cstotal.cs_nbfree++;
+ fs->fs_cs(fs, cg).cs_nbfree++;
+ }
+ }
+ fs->fs_fmod = 1;
+ bdwrite(bp);
+}
+
+
+static int
+scanc(u_int size, const u_char *cp, const u_char table[], int mask)
+{
+ const u_char *end = &cp[size];
+
+ while (cp < end && (table[*cp] & mask) == 0)
+ cp++;
+ return (end - cp);
+}
+
+/*
+ * Find a block of the specified size in the specified cylinder group.
+ *
+ * It is a panic if a request is made to find a block if none are
+ * available.
+ */
+static int32_t
+ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz)
+{
+ int32_t bno;
+ int start, len, loc, i;
+ int blk, field, subfield, pos;
+ int ostart, olen;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ /*
+ * find the fragment by searching through the free block
+ * map for an appropriate bit pattern
+ */
+ if (bpref)
+ start = dtogd(fs, bpref) / NBBY;
+ else
+ start = ufs_rw32(cgp->cg_frotor, needswap) / NBBY;
+ len = howmany(fs->fs_fpg, NBBY) - start;
+ ostart = start;
+ olen = len;
+ loc = scanc((u_int)len,
+ (const u_char *)&cg_blksfree_swap(cgp, needswap)[start],
+ (const u_char *)fragtbl[fs->fs_frag],
+ (1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
+ if (loc == 0) {
+ len = start + 1;
+ start = 0;
+ loc = scanc((u_int)len,
+ (const u_char *)&cg_blksfree_swap(cgp, needswap)[0],
+ (const u_char *)fragtbl[fs->fs_frag],
+ (1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
+ if (loc == 0) {
+ errx(1,
+ "ffs_alloccg: map corrupted: start %d len %d offset %d %ld",
+ ostart, olen,
+ ufs_rw32(cgp->cg_freeoff, needswap),
+ (long)cg_blksfree_swap(cgp, needswap) - (long)cgp);
+ /* NOTREACHED */
+ }
+ }
+ bno = (start + len - loc) * NBBY;
+ cgp->cg_frotor = ufs_rw32(bno, needswap);
+ /*
+ * found the byte in the map
+ * sift through the bits to find the selected frag
+ */
+ for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
+ blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bno);
+ blk <<= 1;
+ field = around[allocsiz];
+ subfield = inside[allocsiz];
+ for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
+ if ((blk & field) == subfield)
+ return (bno + pos);
+ field <<= 1;
+ subfield <<= 1;
+ }
+ }
+ errx(1, "ffs_alloccg: block not in map: bno %lld", (long long)bno);
+ return (-1);
+}
+
+/*
+ * Update the cluster map because of an allocation or free.
+ *
+ * Cnt == 1 means free; cnt == -1 means allocating.
+ */
+void
+ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
+{
+ int32_t *sump;
+ int32_t *lp;
+ u_char *freemapp, *mapp;
+ int i, start, end, forw, back, map, bit;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ if (fs->fs_contigsumsize <= 0)
+ return;
+ freemapp = cg_clustersfree_swap(cgp, needswap);
+ sump = cg_clustersum_swap(cgp, needswap);
+ /*
+ * Allocate or clear the actual block.
+ */
+ if (cnt > 0)
+ setbit(freemapp, blkno);
+ else
+ clrbit(freemapp, blkno);
+ /*
+ * Find the size of the cluster going forward.
+ */
+ start = blkno + 1;
+ end = start + fs->fs_contigsumsize;
+ if ((unsigned)end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
+ end = ufs_rw32(cgp->cg_nclusterblks, needswap);
+ mapp = &freemapp[start / NBBY];
+ map = *mapp++;
+ bit = 1 << (start % NBBY);
+ for (i = start; i < end; i++) {
+ if ((map & bit) == 0)
+ break;
+ if ((i & (NBBY - 1)) != (NBBY - 1)) {
+ bit <<= 1;
+ } else {
+ map = *mapp++;
+ bit = 1;
+ }
+ }
+ forw = i - start;
+ /*
+ * Find the size of the cluster going backward.
+ */
+ start = blkno - 1;
+ end = start - fs->fs_contigsumsize;
+ if (end < 0)
+ end = -1;
+ mapp = &freemapp[start / NBBY];
+ map = *mapp--;
+ bit = 1 << (start % NBBY);
+ for (i = start; i > end; i--) {
+ if ((map & bit) == 0)
+ break;
+ if ((i & (NBBY - 1)) != 0) {
+ bit >>= 1;
+ } else {
+ map = *mapp--;
+ bit = 1 << (NBBY - 1);
+ }
+ }
+ back = start - i;
+ /*
+ * Account for old cluster and the possibly new forward and
+ * back clusters.
+ */
+ i = back + forw + 1;
+ if (i > fs->fs_contigsumsize)
+ i = fs->fs_contigsumsize;
+ ufs_add32(sump[i], cnt, needswap);
+ if (back > 0)
+ ufs_add32(sump[back], -cnt, needswap);
+ if (forw > 0)
+ ufs_add32(sump[forw], -cnt, needswap);
+
+ /*
+ * Update cluster summary information.
+ */
+ lp = &sump[fs->fs_contigsumsize];
+ for (i = fs->fs_contigsumsize; i > 0; i--)
+ if (ufs_rw32(*lp--, needswap) > 0)
+ break;
+ fs->fs_maxcluster[ufs_rw32(cgp->cg_cgx, needswap)] = i;
+}
diff --git a/usr.sbin/makefs/ffs/ffs_balloc.c b/usr.sbin/makefs/ffs/ffs_balloc.c
new file mode 100644
index 0000000..0a048ad
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ffs_balloc.c
@@ -0,0 +1,578 @@
+/* $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */
+/* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. 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.
+ * 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.
+ *
+ * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "makefs.h"
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include "ffs/ufs_bswap.h"
+#include "ffs/buf.h"
+#include "ffs/ufs_inode.h"
+#include "ffs/ffs_extern.h"
+
+static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
+static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
+
+/*
+ * Balloc defines the structure of file system storage
+ * by allocating the physical blocks on a device given
+ * the inode and the logical block number in a file.
+ *
+ * Assume: flags == B_SYNC | B_CLRBUF
+ */
+
+int
+ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+{
+ if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
+ return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
+ else
+ return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
+}
+
+static int
+ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+{
+ daddr_t lbn, lastlbn;
+ int size;
+ int32_t nb;
+ struct buf *bp, *nbp;
+ struct fs *fs = ip->i_fs;
+ struct indir indirs[NIADDR + 2];
+ daddr_t newb, pref;
+ int32_t *bap;
+ int osize, nsize, num, i, error;
+ int32_t *allocblk, allociblk[NIADDR + 1];
+ int32_t *allocib;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ lbn = lblkno(fs, offset);
+ size = blkoff(fs, offset) + bufsize;
+ if (bpp != NULL) {
+ *bpp = NULL;
+ }
+
+ assert(size <= fs->fs_bsize);
+ if (lbn < 0)
+ return (EFBIG);
+
+ /*
+ * If the next write will extend the file into a new block,
+ * and the file is currently composed of a fragment
+ * this fragment has to be extended to be a full block.
+ */
+
+ lastlbn = lblkno(fs, ip->i_ffs1_size);
+ if (lastlbn < NDADDR && lastlbn < lbn) {
+ nb = lastlbn;
+ osize = blksize(fs, ip, nb);
+ if (osize < fs->fs_bsize && osize > 0) {
+ warnx("need to ffs_realloccg; not supported!");
+ abort();
+ }
+ }
+
+ /*
+ * The first NDADDR blocks are direct blocks
+ */
+
+ if (lbn < NDADDR) {
+ nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
+ if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
+
+ /*
+ * The block is an already-allocated direct block
+ * and the file already extends past this block,
+ * thus this must be a whole block.
+ * Just read the block (if requested).
+ */
+
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn,
+ fs->fs_bsize, bpp);
+ if (error) {
+ brelse(*bpp);
+ return (error);
+ }
+ }
+ return (0);
+ }
+ if (nb != 0) {
+
+ /*
+ * Consider need to reallocate a fragment.
+ */
+
+ osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
+ nsize = fragroundup(fs, size);
+ if (nsize <= osize) {
+
+ /*
+ * The existing block is already
+ * at least as big as we want.
+ * Just read the block (if requested).
+ */
+
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn,
+ osize, bpp);
+ if (error) {
+ brelse(*bpp);
+ return (error);
+ }
+ }
+ return 0;
+ } else {
+ warnx("need to ffs_realloccg; not supported!");
+ abort();
+ }
+ } else {
+
+ /*
+ * the block was not previously allocated,
+ * allocate a new block or fragment.
+ */
+
+ if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
+ nsize = fragroundup(fs, size);
+ else
+ nsize = fs->fs_bsize;
+ error = ffs_alloc(ip, lbn,
+ ffs_blkpref_ufs1(ip, lbn, (int)lbn,
+ &ip->i_ffs1_db[0]),
+ nsize, &newb);
+ if (error)
+ return (error);
+ if (bpp != NULL) {
+ bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
+ bp->b_blkno = fsbtodb(fs, newb);
+ clrbuf(bp);
+ *bpp = bp;
+ }
+ }
+ ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
+ return (0);
+ }
+
+ /*
+ * Determine the number of levels of indirection.
+ */
+
+ pref = 0;
+ if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
+ return (error);
+
+ if (num < 1) {
+ warnx("ffs_balloc: ufs_getlbns returned indirect block");
+ abort();
+ }
+
+ /*
+ * Fetch the first indirect block allocating if necessary.
+ */
+
+ --num;
+ nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
+ allocib = NULL;
+ allocblk = allociblk;
+ if (nb == 0) {
+ pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error)
+ return error;
+ nb = newb;
+ *allocblk++ = nb;
+ bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
+ bp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(bp);
+ /*
+ * Write synchronously so that indirect blocks
+ * never point at garbage.
+ */
+ if ((error = bwrite(bp)) != 0)
+ return error;
+ allocib = &ip->i_ffs1_ib[indirs[0].in_off];
+ *allocib = ufs_rw32((int32_t)nb, needswap);
+ }
+
+ /*
+ * Fetch through the indirect blocks, allocating as necessary.
+ */
+
+ for (i = 1;;) {
+ error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
+ fs->fs_bsize, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ bap = (int32_t *)bp->b_data;
+ nb = ufs_rw32(bap[indirs[i].in_off], needswap);
+ if (i == num)
+ break;
+ i++;
+ if (nb != 0) {
+ brelse(bp);
+ continue;
+ }
+ if (pref == 0)
+ pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ nb = newb;
+ *allocblk++ = nb;
+ nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
+ fs->fs_bsize);
+ nbp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(nbp);
+ /*
+ * Write synchronously so that indirect blocks
+ * never point at garbage.
+ */
+
+ if ((error = bwrite(nbp)) != 0) {
+ brelse(bp);
+ return error;
+ }
+ bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
+
+ bwrite(bp);
+ }
+
+ /*
+ * Get the data block, allocating if necessary.
+ */
+
+ if (nb == 0) {
+ pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ nb = newb;
+ *allocblk++ = nb;
+ if (bpp != NULL) {
+ nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
+ nbp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(nbp);
+ *bpp = nbp;
+ }
+ bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
+
+ /*
+ * If required, write synchronously, otherwise use
+ * delayed write.
+ */
+ bwrite(bp);
+ return (0);
+ }
+ brelse(bp);
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
+ if (error) {
+ brelse(nbp);
+ return error;
+ }
+ *bpp = nbp;
+ }
+ return (0);
+}
+
+static int
+ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+{
+ daddr_t lbn, lastlbn;
+ int size;
+ struct buf *bp, *nbp;
+ struct fs *fs = ip->i_fs;
+ struct indir indirs[NIADDR + 2];
+ daddr_t newb, pref, nb;
+ int64_t *bap;
+ int osize, nsize, num, i, error;
+ int64_t *allocblk, allociblk[NIADDR + 1];
+ int64_t *allocib;
+ const int needswap = UFS_FSNEEDSWAP(fs);
+
+ lbn = lblkno(fs, offset);
+ size = blkoff(fs, offset) + bufsize;
+ if (bpp != NULL) {
+ *bpp = NULL;
+ }
+
+ assert(size <= fs->fs_bsize);
+ if (lbn < 0)
+ return (EFBIG);
+
+ /*
+ * If the next write will extend the file into a new block,
+ * and the file is currently composed of a fragment
+ * this fragment has to be extended to be a full block.
+ */
+
+ lastlbn = lblkno(fs, ip->i_ffs2_size);
+ if (lastlbn < NDADDR && lastlbn < lbn) {
+ nb = lastlbn;
+ osize = blksize(fs, ip, nb);
+ if (osize < fs->fs_bsize && osize > 0) {
+ warnx("need to ffs_realloccg; not supported!");
+ abort();
+ }
+ }
+
+ /*
+ * The first NDADDR blocks are direct blocks
+ */
+
+ if (lbn < NDADDR) {
+ nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
+ if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
+
+ /*
+ * The block is an already-allocated direct block
+ * and the file already extends past this block,
+ * thus this must be a whole block.
+ * Just read the block (if requested).
+ */
+
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn,
+ fs->fs_bsize, bpp);
+ if (error) {
+ brelse(*bpp);
+ return (error);
+ }
+ }
+ return (0);
+ }
+ if (nb != 0) {
+
+ /*
+ * Consider need to reallocate a fragment.
+ */
+
+ osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
+ nsize = fragroundup(fs, size);
+ if (nsize <= osize) {
+
+ /*
+ * The existing block is already
+ * at least as big as we want.
+ * Just read the block (if requested).
+ */
+
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn,
+ osize, bpp);
+ if (error) {
+ brelse(*bpp);
+ return (error);
+ }
+ }
+ return 0;
+ } else {
+ warnx("need to ffs_realloccg; not supported!");
+ abort();
+ }
+ } else {
+
+ /*
+ * the block was not previously allocated,
+ * allocate a new block or fragment.
+ */
+
+ if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
+ nsize = fragroundup(fs, size);
+ else
+ nsize = fs->fs_bsize;
+ error = ffs_alloc(ip, lbn,
+ ffs_blkpref_ufs2(ip, lbn, (int)lbn,
+ &ip->i_ffs2_db[0]),
+ nsize, &newb);
+ if (error)
+ return (error);
+ if (bpp != NULL) {
+ bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
+ bp->b_blkno = fsbtodb(fs, newb);
+ clrbuf(bp);
+ *bpp = bp;
+ }
+ }
+ ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
+ return (0);
+ }
+
+ /*
+ * Determine the number of levels of indirection.
+ */
+
+ pref = 0;
+ if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
+ return (error);
+
+ if (num < 1) {
+ warnx("ffs_balloc: ufs_getlbns returned indirect block");
+ abort();
+ }
+
+ /*
+ * Fetch the first indirect block allocating if necessary.
+ */
+
+ --num;
+ nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
+ allocib = NULL;
+ allocblk = allociblk;
+ if (nb == 0) {
+ pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error)
+ return error;
+ nb = newb;
+ *allocblk++ = nb;
+ bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
+ bp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(bp);
+ /*
+ * Write synchronously so that indirect blocks
+ * never point at garbage.
+ */
+ if ((error = bwrite(bp)) != 0)
+ return error;
+ allocib = &ip->i_ffs2_ib[indirs[0].in_off];
+ *allocib = ufs_rw64(nb, needswap);
+ }
+
+ /*
+ * Fetch through the indirect blocks, allocating as necessary.
+ */
+
+ for (i = 1;;) {
+ error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
+ fs->fs_bsize, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ bap = (int64_t *)bp->b_data;
+ nb = ufs_rw64(bap[indirs[i].in_off], needswap);
+ if (i == num)
+ break;
+ i++;
+ if (nb != 0) {
+ brelse(bp);
+ continue;
+ }
+ if (pref == 0)
+ pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ nb = newb;
+ *allocblk++ = nb;
+ nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
+ fs->fs_bsize);
+ nbp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(nbp);
+ /*
+ * Write synchronously so that indirect blocks
+ * never point at garbage.
+ */
+
+ if ((error = bwrite(nbp)) != 0) {
+ brelse(bp);
+ return error;
+ }
+ bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
+
+ bwrite(bp);
+ }
+
+ /*
+ * Get the data block, allocating if necessary.
+ */
+
+ if (nb == 0) {
+ pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
+ error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ nb = newb;
+ *allocblk++ = nb;
+ if (bpp != NULL) {
+ nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
+ nbp->b_blkno = fsbtodb(fs, nb);
+ clrbuf(nbp);
+ *bpp = nbp;
+ }
+ bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
+
+ /*
+ * If required, write synchronously, otherwise use
+ * delayed write.
+ */
+ bwrite(bp);
+ return (0);
+ }
+ brelse(bp);
+ if (bpp != NULL) {
+ error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
+ if (error) {
+ brelse(nbp);
+ return error;
+ }
+ *bpp = nbp;
+ }
+ return (0);
+}
diff --git a/usr.sbin/makefs/ffs/ffs_bswap.c b/usr.sbin/makefs/ffs/ffs_bswap.c
new file mode 100644
index 0000000..e62eb19
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ffs_bswap.c
@@ -0,0 +1,260 @@
+/* $NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken Exp $ */
+
+/*
+ * Copyright (c) 1998 Manuel Bouyer.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#endif
+
+#include <ufs/ufs/dinode.h>
+#include "ffs/ufs_bswap.h"
+#include <ufs/ffs/fs.h>
+
+#if !defined(_KERNEL)
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define panic(x) printf("%s\n", (x)), abort()
+#endif
+
+#define fs_old_postbloff fs_spare5[0]
+#define fs_old_rotbloff fs_spare5[1]
+#define fs_old_postbl_start fs_maxbsize
+#define fs_old_headswitch fs_id[0]
+#define fs_old_trkseek fs_id[1]
+#define fs_old_csmask fs_spare1[0]
+#define fs_old_csshift fs_spare1[1]
+
+#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
+#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
+
+void ffs_csum_swap(struct csum *o, struct csum *n, int size);
+void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n);
+
+void
+ffs_sb_swap(struct fs *o, struct fs *n)
+{
+ size_t i;
+ u_int32_t *o32, *n32;
+
+ /*
+ * In order to avoid a lot of lines, as the first N fields (52)
+ * of the superblock up to fs_fmod are u_int32_t, we just loop
+ * here to convert them.
+ */
+ o32 = (u_int32_t *)o;
+ n32 = (u_int32_t *)n;
+ for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++)
+ n32[i] = bswap32(o32[i]);
+
+ n->fs_swuid = bswap64(o->fs_swuid);
+ n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */
+ n->fs_old_cpc = bswap32(o->fs_old_cpc);
+
+ /* These fields overlap with a possible location for the
+ * historic FS_DYNAMICPOSTBLFMT postbl table, and with the
+ * first half of the historic FS_42POSTBLFMT postbl table.
+ */
+ n->fs_maxbsize = bswap32(o->fs_maxbsize);
+ n->fs_sblockloc = bswap64(o->fs_sblockloc);
+ ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal);
+ n->fs_time = bswap64(o->fs_time);
+ n->fs_size = bswap64(o->fs_size);
+ n->fs_dsize = bswap64(o->fs_dsize);
+ n->fs_csaddr = bswap64(o->fs_csaddr);
+ n->fs_pendingblocks = bswap64(o->fs_pendingblocks);
+ n->fs_pendinginodes = bswap32(o->fs_pendinginodes);
+
+ /* These fields overlap with the second half of the
+ * historic FS_42POSTBLFMT postbl table
+ */
+ for (i = 0; i < FSMAXSNAP; i++)
+ n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]);
+ n->fs_avgfilesize = bswap32(o->fs_avgfilesize);
+ n->fs_avgfpdir = bswap32(o->fs_avgfpdir);
+ /* fs_sparecon[28] - ignore for now */
+ n->fs_flags = bswap32(o->fs_flags);
+ n->fs_contigsumsize = bswap32(o->fs_contigsumsize);
+ n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen);
+ n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt);
+ n->fs_maxfilesize = bswap64(o->fs_maxfilesize);
+ n->fs_qbmask = bswap64(o->fs_qbmask);
+ n->fs_qfmask = bswap64(o->fs_qfmask);
+ n->fs_state = bswap32(o->fs_state);
+ n->fs_old_postblformat = bswap32(o->fs_old_postblformat);
+ n->fs_old_nrpos = bswap32(o->fs_old_nrpos);
+ n->fs_old_postbloff = bswap32(o->fs_old_postbloff);
+ n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff);
+
+ n->fs_magic = bswap32(o->fs_magic);
+}
+
+void
+ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n)
+{
+
+ n->di_mode = bswap16(o->di_mode);
+ n->di_nlink = bswap16(o->di_nlink);
+ n->di_size = bswap64(o->di_size);
+ n->di_atime = bswap32(o->di_atime);
+ n->di_atimensec = bswap32(o->di_atimensec);
+ n->di_mtime = bswap32(o->di_mtime);
+ n->di_mtimensec = bswap32(o->di_mtimensec);
+ n->di_ctime = bswap32(o->di_ctime);
+ n->di_ctimensec = bswap32(o->di_ctimensec);
+ memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t));
+ n->di_flags = bswap32(o->di_flags);
+ n->di_blocks = bswap32(o->di_blocks);
+ n->di_gen = bswap32(o->di_gen);
+ n->di_uid = bswap32(o->di_uid);
+ n->di_gid = bswap32(o->di_gid);
+}
+
+void
+ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n)
+{
+ n->di_mode = bswap16(o->di_mode);
+ n->di_nlink = bswap16(o->di_nlink);
+ n->di_uid = bswap32(o->di_uid);
+ n->di_gid = bswap32(o->di_gid);
+ n->di_blksize = bswap32(o->di_blksize);
+ n->di_size = bswap64(o->di_size);
+ n->di_blocks = bswap64(o->di_blocks);
+ n->di_atime = bswap64(o->di_atime);
+ n->di_atimensec = bswap32(o->di_atimensec);
+ n->di_mtime = bswap64(o->di_mtime);
+ n->di_mtimensec = bswap32(o->di_mtimensec);
+ n->di_ctime = bswap64(o->di_ctime);
+ n->di_ctimensec = bswap32(o->di_ctimensec);
+ n->di_birthtime = bswap64(o->di_ctime);
+ n->di_birthnsec = bswap32(o->di_ctimensec);
+ n->di_gen = bswap32(o->di_gen);
+ n->di_kernflags = bswap32(o->di_kernflags);
+ n->di_flags = bswap32(o->di_flags);
+ n->di_extsize = bswap32(o->di_extsize);
+ memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8);
+}
+
+void
+ffs_csum_swap(struct csum *o, struct csum *n, int size)
+{
+ size_t i;
+ u_int32_t *oint, *nint;
+
+ oint = (u_int32_t*)o;
+ nint = (u_int32_t*)n;
+
+ for (i = 0; i < size / sizeof(u_int32_t); i++)
+ nint[i] = bswap32(oint[i]);
+}
+
+void
+ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n)
+{
+ n->cs_ndir = bswap64(o->cs_ndir);
+ n->cs_nbfree = bswap64(o->cs_nbfree);
+ n->cs_nifree = bswap64(o->cs_nifree);
+ n->cs_nffree = bswap64(o->cs_nffree);
+}
+
+/*
+ * Note that ffs_cg_swap may be called with o == n.
+ */
+void
+ffs_cg_swap(struct cg *o, struct cg *n, struct fs *fs)
+{
+ int i;
+ u_int32_t *n32, *o32;
+ u_int16_t *n16, *o16;
+ int32_t btotoff, boff, clustersumoff;
+
+ n->cg_firstfield = bswap32(o->cg_firstfield);
+ n->cg_magic = bswap32(o->cg_magic);
+ n->cg_old_time = bswap32(o->cg_old_time);
+ n->cg_cgx = bswap32(o->cg_cgx);
+ n->cg_old_ncyl = bswap16(o->cg_old_ncyl);
+ n->cg_old_niblk = bswap16(o->cg_old_niblk);
+ n->cg_ndblk = bswap32(o->cg_ndblk);
+ n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir);
+ n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree);
+ n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree);
+ n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree);
+ n->cg_rotor = bswap32(o->cg_rotor);
+ n->cg_frotor = bswap32(o->cg_frotor);
+ n->cg_irotor = bswap32(o->cg_irotor);
+ for (i = 0; i < MAXFRAG; i++)
+ n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
+
+ n->cg_old_btotoff = bswap32(o->cg_old_btotoff);
+ n->cg_old_boff = bswap32(o->cg_old_boff);
+ n->cg_iusedoff = bswap32(o->cg_iusedoff);
+ n->cg_freeoff = bswap32(o->cg_freeoff);
+ n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff);
+ n->cg_clustersumoff = bswap32(o->cg_clustersumoff);
+ n->cg_clusteroff = bswap32(o->cg_clusteroff);
+ n->cg_nclusterblks = bswap32(o->cg_nclusterblks);
+ n->cg_niblk = bswap32(o->cg_niblk);
+ n->cg_initediblk = bswap32(o->cg_initediblk);
+ n->cg_time = bswap64(o->cg_time);
+
+ if (fs->fs_magic == FS_UFS2_MAGIC)
+ return;
+
+ if (n->cg_magic == CG_MAGIC) {
+ btotoff = n->cg_old_btotoff;
+ boff = n->cg_old_boff;
+ clustersumoff = n->cg_clustersumoff;
+ } else {
+ btotoff = bswap32(n->cg_old_btotoff);
+ boff = bswap32(n->cg_old_boff);
+ clustersumoff = bswap32(n->cg_clustersumoff);
+ }
+ n32 = (u_int32_t *)((u_int8_t *)n + btotoff);
+ o32 = (u_int32_t *)((u_int8_t *)o + btotoff);
+ n16 = (u_int16_t *)((u_int8_t *)n + boff);
+ o16 = (u_int16_t *)((u_int8_t *)o + boff);
+
+ for (i = 0; i < fs->fs_old_cpg; i++)
+ n32[i] = bswap32(o32[i]);
+
+ for (i = 0; i < fs->fs_old_cpg * fs->fs_old_nrpos; i++)
+ n16[i] = bswap16(o16[i]);
+
+ n32 = (u_int32_t *)((u_int8_t *)n + clustersumoff);
+ o32 = (u_int32_t *)((u_int8_t *)o + clustersumoff);
+ for (i = 1; i < fs->fs_contigsumsize + 1; i++)
+ n32[i] = bswap32(o32[i]);
+}
diff --git a/usr.sbin/makefs/ffs/ffs_extern.h b/usr.sbin/makefs/ffs/ffs_extern.h
new file mode 100644
index 0000000..7755823
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ffs_extern.h
@@ -0,0 +1,77 @@
+/* $NetBSD: ffs_extern.h,v 1.6 2003/08/07 11:25:33 agc Exp $ */
+/* From: NetBSD: ffs_extern.h,v 1.19 2001/08/17 02:18:48 lukem Exp */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. 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.
+ * 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.
+ *
+ * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95
+ * $FreeBSD$
+ */
+
+#include "ffs/buf.h"
+
+struct inode;
+
+/*
+ * Structure used to pass around logical block paths generated by
+ * ufs_getlbns and used by truncate and bmap code.
+ */
+struct indir {
+ daddr_t in_lbn; /* Logical block number. */
+ int in_off; /* Offset in buffer. */
+};
+
+ /* ffs.c */
+_Noreturn void panic(const char *, ...) __printflike(1, 2);
+
+ /* ffs_alloc.c */
+int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *);
+daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int32_t *);
+daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int64_t *);
+void ffs_blkfree(struct inode *, daddr_t, long);
+void ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
+
+ /* ffs_balloc.c */
+int ffs_balloc(struct inode *, off_t, int, struct buf **);
+
+ /* ffs_bswap.c */
+void ffs_sb_swap(struct fs*, struct fs *);
+void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *);
+void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);
+void ffs_csum_swap(struct csum *, struct csum *, int);
+void ffs_cg_swap(struct cg *, struct cg *, struct fs *);
+
+ /* ffs_subr.c */
+void ffs_fragacct(struct fs *, int, int32_t[], int, int);
+int ffs_isblock(struct fs *, u_char *, int32_t);
+int ffs_isfreeblock(struct fs *, u_char *, int32_t);
+void ffs_clrblock(struct fs *, u_char *, int32_t);
+void ffs_setblock(struct fs *, u_char *, int32_t);
+
+ /* ufs_bmap.c */
+int ufs_getlbns(struct inode *, daddr_t, struct indir *, int *);
diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c
new file mode 100644
index 0000000..b55174d
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ffs_subr.c
@@ -0,0 +1,193 @@
+/* $NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. 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.
+ * 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.
+ *
+ * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#include "ffs/ffs_extern.h"
+#include "ffs/ufs_bswap.h"
+
+/*
+ * Update the frsum fields to reflect addition or deletion
+ * of some frags.
+ */
+void
+ffs_fragacct_swap(struct fs *fs, int fragmap, int32_t fraglist[], int cnt, int needswap)
+{
+ int inblk;
+ int field, subfield;
+ int siz, pos;
+
+ inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
+ fragmap <<= 1;
+ for (siz = 1; siz < fs->fs_frag; siz++) {
+ if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0)
+ continue;
+ field = around[siz];
+ subfield = inside[siz];
+ for (pos = siz; pos <= fs->fs_frag; pos++) {
+ if ((fragmap & field) == subfield) {
+ fraglist[siz] = ufs_rw32(
+ ufs_rw32(fraglist[siz], needswap) + cnt,
+ needswap);
+ pos += siz;
+ field <<= siz;
+ subfield <<= siz;
+ }
+ field <<= 1;
+ subfield <<= 1;
+ }
+ }
+}
+
+/*
+ * block operations
+ *
+ * check if a block is available
+ * returns true if all the corresponding bits in the free map are 1
+ * returns false if any corresponding bit in the free map is 0
+ */
+int
+ffs_isblock(fs, cp, h)
+ struct fs *fs;
+ u_char *cp;
+ int32_t h;
+{
+ u_char mask;
+
+ switch ((int)fs->fs_fragshift) {
+ case 3:
+ return (cp[h] == 0xff);
+ case 2:
+ mask = 0x0f << ((h & 0x1) << 2);
+ return ((cp[h >> 1] & mask) == mask);
+ case 1:
+ mask = 0x03 << ((h & 0x3) << 1);
+ return ((cp[h >> 2] & mask) == mask);
+ case 0:
+ mask = 0x01 << (h & 0x7);
+ return ((cp[h >> 3] & mask) == mask);
+ default:
+ panic("ffs_isblock: unknown fs_fragshift %d",
+ (int)fs->fs_fragshift);
+ }
+}
+
+/*
+ * check if a block is completely allocated
+ * returns true if all the corresponding bits in the free map are 0
+ * returns false if any corresponding bit in the free map is 1
+ */
+int
+ffs_isfreeblock(fs, cp, h)
+ struct fs *fs;
+ u_char *cp;
+ int32_t h;
+{
+
+ switch ((int)fs->fs_fragshift) {
+ case 3:
+ return (cp[h] == 0);
+ case 2:
+ return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
+ case 1:
+ return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
+ case 0:
+ return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
+ default:
+ panic("ffs_isfreeblock: unknown fs_fragshift %d",
+ (int)fs->fs_fragshift);
+ }
+}
+
+/*
+ * take a block out of the map
+ */
+void
+ffs_clrblock(fs, cp, h)
+ struct fs *fs;
+ u_char *cp;
+ int32_t h;
+{
+
+ switch ((int)fs->fs_fragshift) {
+ case 3:
+ cp[h] = 0;
+ return;
+ case 2:
+ cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
+ return;
+ case 1:
+ cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
+ return;
+ case 0:
+ cp[h >> 3] &= ~(0x01 << (h & 0x7));
+ return;
+ default:
+ panic("ffs_clrblock: unknown fs_fragshift %d",
+ (int)fs->fs_fragshift);
+ }
+}
+
+/*
+ * put a block into the map
+ */
+void
+ffs_setblock(fs, cp, h)
+ struct fs *fs;
+ u_char *cp;
+ int32_t h;
+{
+
+ switch ((int)fs->fs_fragshift) {
+ case 3:
+ cp[h] = 0xff;
+ return;
+ case 2:
+ cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
+ return;
+ case 1:
+ cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
+ return;
+ case 0:
+ cp[h >> 3] |= (0x01 << (h & 0x7));
+ return;
+ default:
+ panic("ffs_setblock: unknown fs_fragshift %d",
+ (int)fs->fs_fragshift);
+ }
+}
diff --git a/usr.sbin/makefs/ffs/mkfs.c b/usr.sbin/makefs/ffs/mkfs.c
new file mode 100644
index 0000000..b1bdd09
--- /dev/null
+++ b/usr.sbin/makefs/ffs/mkfs.c
@@ -0,0 +1,839 @@
+/* $NetBSD: mkfs.c,v 1.20 2004/06/24 22:30:13 lukem Exp $ */
+
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1980, 1989, 1993
+ * The Regents of the University of California. 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "makefs.h"
+#include "ffs.h"
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include "ffs/ufs_bswap.h"
+#include "ffs/ufs_inode.h"
+#include "ffs/ffs_extern.h"
+#include "ffs/newfs_extern.h"
+
+#ifndef BBSIZE
+#define BBSIZE 8192 /* size of boot area, with label */
+#endif
+
+static void initcg(int, time_t, const fsinfo_t *);
+static int ilog2(int);
+
+static int count_digits(int);
+
+/*
+ * make file system for cylinder-group style file systems
+ */
+#define UMASK 0755
+#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
+
+union {
+ struct fs fs;
+ char pad[SBLOCKSIZE];
+} fsun;
+#define sblock fsun.fs
+struct csum *fscs;
+
+union {
+ struct cg cg;
+ char pad[FFS_MAXBSIZE];
+} cgun;
+#define acg cgun.cg
+
+char *iobuf;
+int iobufsize;
+
+char writebuf[FFS_MAXBSIZE];
+
+static int Oflag; /* format as an 4.3BSD file system */
+static int64_t fssize; /* file system size */
+static int sectorsize; /* bytes/sector */
+static int fsize; /* fragment size */
+static int bsize; /* block size */
+static int maxbsize; /* maximum clustering */
+static int maxblkspercg;
+static int minfree; /* free space threshold */
+static int opt; /* optimization preference (space or time) */
+static int density; /* number of bytes per inode */
+static int maxcontig; /* max contiguous blocks to allocate */
+static int maxbpg; /* maximum blocks per file in a cyl group */
+static int bbsize; /* boot block size */
+static int sbsize; /* superblock size */
+static int avgfilesize; /* expected average file size */
+static int avgfpdir; /* expected number of files per directory */
+
+struct fs *
+ffs_mkfs(const char *fsys, const fsinfo_t *fsopts)
+{
+ int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg;
+ int32_t cylno, i, csfrags;
+ long long sizepb;
+ void *space;
+ int size, blks;
+ int nprintcols, printcolwidth;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
+
+ Oflag = ffs_opts->version;
+ fssize = fsopts->size / fsopts->sectorsize;
+ sectorsize = fsopts->sectorsize;
+ fsize = ffs_opts->fsize;
+ bsize = ffs_opts->bsize;
+ maxbsize = ffs_opts->maxbsize;
+ maxblkspercg = ffs_opts->maxblkspercg;
+ minfree = ffs_opts->minfree;
+ opt = ffs_opts->optimization;
+ density = ffs_opts->density;
+ maxcontig = ffs_opts->maxcontig;
+ maxbpg = ffs_opts->maxbpg;
+ avgfilesize = ffs_opts->avgfilesize;
+ avgfpdir = ffs_opts->avgfpdir;
+ bbsize = BBSIZE;
+ sbsize = SBLOCKSIZE;
+
+ strlcpy(sblock.fs_volname, ffs_opts->label, sizeof(sblock.fs_volname));
+
+ if (Oflag == 0) {
+ sblock.fs_old_inodefmt = FS_42INODEFMT;
+ sblock.fs_maxsymlinklen = 0;
+ sblock.fs_old_flags = 0;
+ } else {
+ sblock.fs_old_inodefmt = FS_44INODEFMT;
+ sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 :
+ MAXSYMLINKLEN_UFS2);
+ sblock.fs_old_flags = FS_FLAGS_UPDATED;
+ sblock.fs_flags = 0;
+ }
+ /*
+ * Validate the given file system size.
+ * Verify that its last block can actually be accessed.
+ * Convert to file system fragment sized units.
+ */
+ if (fssize <= 0) {
+ printf("preposterous size %lld\n", (long long)fssize);
+ exit(13);
+ }
+ ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts);
+
+ /*
+ * collect and verify the filesystem density info
+ */
+ sblock.fs_avgfilesize = avgfilesize;
+ sblock.fs_avgfpdir = avgfpdir;
+ if (sblock.fs_avgfilesize <= 0)
+ printf("illegal expected average file size %d\n",
+ sblock.fs_avgfilesize), exit(14);
+ if (sblock.fs_avgfpdir <= 0)
+ printf("illegal expected number of files per directory %d\n",
+ sblock.fs_avgfpdir), exit(15);
+ /*
+ * collect and verify the block and fragment sizes
+ */
+ sblock.fs_bsize = bsize;
+ sblock.fs_fsize = fsize;
+ if (!POWEROF2(sblock.fs_bsize)) {
+ printf("block size must be a power of 2, not %d\n",
+ sblock.fs_bsize);
+ exit(16);
+ }
+ if (!POWEROF2(sblock.fs_fsize)) {
+ printf("fragment size must be a power of 2, not %d\n",
+ sblock.fs_fsize);
+ exit(17);
+ }
+ if (sblock.fs_fsize < sectorsize) {
+ printf("fragment size %d is too small, minimum is %d\n",
+ sblock.fs_fsize, sectorsize);
+ exit(18);
+ }
+ if (sblock.fs_bsize < MINBSIZE) {
+ printf("block size %d is too small, minimum is %d\n",
+ sblock.fs_bsize, MINBSIZE);
+ exit(19);
+ }
+ if (sblock.fs_bsize > FFS_MAXBSIZE) {
+ printf("block size %d is too large, maximum is %d\n",
+ sblock.fs_bsize, FFS_MAXBSIZE);
+ exit(19);
+ }
+ if (sblock.fs_bsize < sblock.fs_fsize) {
+ printf("block size (%d) cannot be smaller than fragment size (%d)\n",
+ sblock.fs_bsize, sblock.fs_fsize);
+ exit(20);
+ }
+
+ if (maxbsize < bsize || !POWEROF2(maxbsize)) {
+ sblock.fs_maxbsize = sblock.fs_bsize;
+ printf("Extent size set to %d\n", sblock.fs_maxbsize);
+ } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) {
+ sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize;
+ printf("Extent size reduced to %d\n", sblock.fs_maxbsize);
+ } else {
+ sblock.fs_maxbsize = maxbsize;
+ }
+ sblock.fs_maxcontig = maxcontig;
+ if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) {
+ sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize;
+ printf("Maxcontig raised to %d\n", sblock.fs_maxbsize);
+ }
+
+ if (sblock.fs_maxcontig > 1)
+ sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG);
+
+ sblock.fs_bmask = ~(sblock.fs_bsize - 1);
+ sblock.fs_fmask = ~(sblock.fs_fsize - 1);
+ sblock.fs_qbmask = ~sblock.fs_bmask;
+ sblock.fs_qfmask = ~sblock.fs_fmask;
+ for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
+ sblock.fs_bshift++;
+ for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
+ sblock.fs_fshift++;
+ sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
+ for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
+ sblock.fs_fragshift++;
+ if (sblock.fs_frag > MAXFRAG) {
+ printf("fragment size %d is too small, "
+ "minimum with block size %d is %d\n",
+ sblock.fs_fsize, sblock.fs_bsize,
+ sblock.fs_bsize / MAXFRAG);
+ exit(21);
+ }
+ sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
+ sblock.fs_size = sblock.fs_providersize = fssize =
+ dbtofsb(&sblock, fssize);
+
+ if (Oflag <= 1) {
+ sblock.fs_magic = FS_UFS1_MAGIC;
+ sblock.fs_sblockloc = SBLOCK_UFS1;
+ sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t);
+ sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
+ sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
+ sizeof (ufs1_daddr_t));
+ sblock.fs_old_inodefmt = FS_44INODEFMT;
+ sblock.fs_old_cgoffset = 0;
+ sblock.fs_old_cgmask = 0xffffffff;
+ sblock.fs_old_size = sblock.fs_size;
+ sblock.fs_old_rotdelay = 0;
+ sblock.fs_old_rps = 60;
+ sblock.fs_old_nspf = sblock.fs_fsize / sectorsize;
+ sblock.fs_old_cpg = 1;
+ sblock.fs_old_interleave = 1;
+ sblock.fs_old_trackskew = 0;
+ sblock.fs_old_cpc = 0;
+ sblock.fs_old_postblformat = 1;
+ sblock.fs_old_nrpos = 1;
+ } else {
+ sblock.fs_magic = FS_UFS2_MAGIC;
+ sblock.fs_sblockloc = SBLOCK_UFS2;
+ sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t);
+ sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
+ sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) *
+ sizeof (ufs2_daddr_t));
+ }
+
+ sblock.fs_sblkno =
+ roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize),
+ sblock.fs_frag);
+ sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
+ roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag));
+ sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
+ sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
+ for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
+ sizepb *= NINDIR(&sblock);
+ sblock.fs_maxfilesize += sizepb;
+ }
+
+ /*
+ * Calculate the number of blocks to put into each cylinder group.
+ *
+ * This algorithm selects the number of blocks per cylinder
+ * group. The first goal is to have at least enough data blocks
+ * in each cylinder group to meet the density requirement. Once
+ * this goal is achieved we try to expand to have at least
+ * 1 cylinder group. Once this goal is achieved, we pack as
+ * many blocks into each cylinder group map as will fit.
+ *
+ * We start by calculating the smallest number of blocks that we
+ * can put into each cylinder group. If this is too big, we reduce
+ * the density until it fits.
+ */
+ origdensity = density;
+ for (;;) {
+ fragsperinode = MAX(numfrags(&sblock, density), 1);
+ minfpg = fragsperinode * INOPB(&sblock);
+ if (minfpg > sblock.fs_size)
+ minfpg = sblock.fs_size;
+ sblock.fs_ipg = INOPB(&sblock);
+ sblock.fs_fpg = roundup(sblock.fs_iblkno +
+ sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
+ if (sblock.fs_fpg < minfpg)
+ sblock.fs_fpg = minfpg;
+ sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
+ INOPB(&sblock));
+ sblock.fs_fpg = roundup(sblock.fs_iblkno +
+ sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
+ if (sblock.fs_fpg < minfpg)
+ sblock.fs_fpg = minfpg;
+ sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
+ INOPB(&sblock));
+ if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
+ break;
+ density -= sblock.fs_fsize;
+ }
+ if (density != origdensity)
+ printf("density reduced from %d to %d\n", origdensity, density);
+
+ if (maxblkspercg <= 0 || maxblkspercg >= fssize)
+ maxblkspercg = fssize - 1;
+ /*
+ * Start packing more blocks into the cylinder group until
+ * it cannot grow any larger, the number of cylinder groups
+ * drops below 1, or we reach the size requested.
+ */
+ for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) {
+ sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
+ INOPB(&sblock));
+ if (sblock.fs_size / sblock.fs_fpg < 1)
+ break;
+ if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
+ continue;
+ if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize)
+ break;
+ sblock.fs_fpg -= sblock.fs_frag;
+ sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
+ INOPB(&sblock));
+ break;
+ }
+ /*
+ * Check to be sure that the last cylinder group has enough blocks
+ * to be viable. If it is too small, reduce the number of blocks
+ * per cylinder group which will have the effect of moving more
+ * blocks into the last cylinder group.
+ */
+ optimalfpg = sblock.fs_fpg;
+ for (;;) {
+ sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
+ lastminfpg = roundup(sblock.fs_iblkno +
+ sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
+ if (sblock.fs_size < lastminfpg) {
+ printf("Filesystem size %lld < minimum size of %d\n",
+ (long long)sblock.fs_size, lastminfpg);
+ exit(28);
+ }
+ if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
+ sblock.fs_size % sblock.fs_fpg == 0)
+ break;
+ sblock.fs_fpg -= sblock.fs_frag;
+ sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
+ INOPB(&sblock));
+ }
+ if (optimalfpg != sblock.fs_fpg)
+ printf("Reduced frags per cylinder group from %d to %d %s\n",
+ optimalfpg, sblock.fs_fpg, "to enlarge last cyl group");
+ sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
+ sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
+ if (Oflag <= 1) {
+ sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf;
+ sblock.fs_old_nsect = sblock.fs_old_spc;
+ sblock.fs_old_npsect = sblock.fs_old_spc;
+ sblock.fs_old_ncyl = sblock.fs_ncg;
+ }
+
+ /*
+ * fill in remaining fields of the super block
+ */
+ sblock.fs_csaddr = cgdmin(&sblock, 0);
+ sblock.fs_cssize =
+ fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
+
+ /*
+ * Setup memory for temporary in-core cylgroup summaries.
+ * Cribbed from ffs_mountfs().
+ */
+ size = sblock.fs_cssize;
+ blks = howmany(size, sblock.fs_fsize);
+ if (sblock.fs_contigsumsize > 0)
+ size += sblock.fs_ncg * sizeof(int32_t);
+ if ((space = (char *)calloc(1, size)) == NULL)
+ err(1, "memory allocation error for cg summaries");
+ sblock.fs_csp = space;
+ space = (char *)space + sblock.fs_cssize;
+ if (sblock.fs_contigsumsize > 0) {
+ int32_t *lp;
+
+ sblock.fs_maxcluster = lp = space;
+ for (i = 0; i < sblock.fs_ncg; i++)
+ *lp++ = sblock.fs_contigsumsize;
+ }
+
+ sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
+ if (sblock.fs_sbsize > SBLOCKSIZE)
+ sblock.fs_sbsize = SBLOCKSIZE;
+ sblock.fs_minfree = minfree;
+ sblock.fs_maxcontig = maxcontig;
+ sblock.fs_maxbpg = maxbpg;
+ sblock.fs_optim = opt;
+ sblock.fs_cgrotor = 0;
+ sblock.fs_pendingblocks = 0;
+ sblock.fs_pendinginodes = 0;
+ sblock.fs_cstotal.cs_ndir = 0;
+ sblock.fs_cstotal.cs_nbfree = 0;
+ sblock.fs_cstotal.cs_nifree = 0;
+ sblock.fs_cstotal.cs_nffree = 0;
+ sblock.fs_fmod = 0;
+ sblock.fs_ronly = 0;
+ sblock.fs_state = 0;
+ sblock.fs_clean = FS_ISCLEAN;
+ sblock.fs_ronly = 0;
+ sblock.fs_id[0] = start_time.tv_sec;
+ sblock.fs_id[1] = random();
+ sblock.fs_fsmnt[0] = '\0';
+ csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize);
+ sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno -
+ sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno);
+ sblock.fs_cstotal.cs_nbfree =
+ fragstoblks(&sblock, sblock.fs_dsize) -
+ howmany(csfrags, sblock.fs_frag);
+ sblock.fs_cstotal.cs_nffree =
+ fragnum(&sblock, sblock.fs_size) +
+ (fragnum(&sblock, csfrags) > 0 ?
+ sblock.fs_frag - fragnum(&sblock, csfrags) : 0);
+ sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO;
+ sblock.fs_cstotal.cs_ndir = 0;
+ sblock.fs_dsize -= csfrags;
+ sblock.fs_time = start_time.tv_sec;
+ if (Oflag <= 1) {
+ sblock.fs_old_time = start_time.tv_sec;
+ sblock.fs_old_dsize = sblock.fs_dsize;
+ sblock.fs_old_csaddr = sblock.fs_csaddr;
+ sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
+ sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
+ sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
+ sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
+ }
+ /*
+ * Dump out summary information about file system.
+ */
+#define B2MBFACTOR (1 / (1024.0 * 1024.0))
+ printf("%s: %.1fMB (%lld sectors) block size %d, "
+ "fragment size %d\n",
+ fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
+ (long long)fsbtodb(&sblock, sblock.fs_size),
+ sblock.fs_bsize, sblock.fs_fsize);
+ printf("\tusing %d cylinder groups of %.2fMB, %d blks, "
+ "%d inodes.\n",
+ sblock.fs_ncg,
+ (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
+ sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
+#undef B2MBFACTOR
+ /*
+ * Now determine how wide each column will be, and calculate how
+ * many columns will fit in a 76 char line. 76 is the width of the
+ * subwindows in sysinst.
+ */
+ printcolwidth = count_digits(
+ fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1)));
+ nprintcols = 76 / (printcolwidth + 2);
+
+ /*
+ * allocate space for superblock, cylinder group map, and
+ * two sets of inode blocks.
+ */
+ if (sblock.fs_bsize < SBLOCKSIZE)
+ iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize;
+ else
+ iobufsize = 4 * sblock.fs_bsize;
+ if ((iobuf = malloc(iobufsize)) == 0) {
+ printf("Cannot allocate I/O buffer\n");
+ exit(38);
+ }
+ memset(iobuf, 0, iobufsize);
+ /*
+ * Make a copy of the superblock into the buffer that we will be
+ * writing out in each cylinder group.
+ */
+ memcpy(writebuf, &sblock, sbsize);
+ if (fsopts->needswap)
+ ffs_sb_swap(&sblock, (struct fs*)writebuf);
+ memcpy(iobuf, writebuf, SBLOCKSIZE);
+
+ printf("super-block backups (for fsck -b #) at:");
+ for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
+ initcg(cylno, start_time.tv_sec, fsopts);
+ if (cylno % nprintcols == 0)
+ printf("\n");
+ printf(" %*lld,", printcolwidth,
+ (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno)));
+ fflush(stdout);
+ }
+ printf("\n");
+
+ /*
+ * Now construct the initial file system,
+ * then write out the super-block.
+ */
+ sblock.fs_time = start_time.tv_sec;
+ if (Oflag <= 1) {
+ sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
+ sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
+ sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
+ sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
+ }
+ if (fsopts->needswap)
+ sblock.fs_flags |= FS_SWAPPED;
+ ffs_write_superblock(&sblock, fsopts);
+ return (&sblock);
+}
+
+/*
+ * Write out the superblock and its duplicates,
+ * and the cylinder group summaries
+ */
+void
+ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts)
+{
+ int cylno, size, blks, i, saveflag;
+ void *space;
+ char *wrbuf;
+
+ saveflag = fs->fs_flags & FS_INTERNAL;
+ fs->fs_flags &= ~FS_INTERNAL;
+
+ memcpy(writebuf, &sblock, sbsize);
+ if (fsopts->needswap)
+ ffs_sb_swap(fs, (struct fs*)writebuf);
+ ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts);
+
+ /* Write out the duplicate super blocks */
+ for (cylno = 0; cylno < fs->fs_ncg; cylno++)
+ ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)),
+ sbsize, writebuf, fsopts);
+
+ /* Write out the cylinder group summaries */
+ size = fs->fs_cssize;
+ blks = howmany(size, fs->fs_fsize);
+ space = (void *)fs->fs_csp;
+ if ((wrbuf = malloc(size)) == NULL)
+ err(1, "ffs_write_superblock: malloc %d", size);
+ for (i = 0; i < blks; i+= fs->fs_frag) {
+ size = fs->fs_bsize;
+ if (i + fs->fs_frag > blks)
+ size = (blks - i) * fs->fs_fsize;
+ if (fsopts->needswap)
+ ffs_csum_swap((struct csum *)space,
+ (struct csum *)wrbuf, size);
+ else
+ memcpy(wrbuf, space, (u_int)size);
+ ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts);
+ space = (char *)space + size;
+ }
+ free(wrbuf);
+ fs->fs_flags |= saveflag;
+}
+
+/*
+ * Initialize a cylinder group.
+ */
+static void
+initcg(int cylno, time_t utime, const fsinfo_t *fsopts)
+{
+ daddr_t cbase, dmax;
+ int32_t i, j, d, dlower, dupper, blkno;
+ struct ufs1_dinode *dp1;
+ struct ufs2_dinode *dp2;
+ int start;
+
+ /*
+ * Determine block bounds for cylinder group.
+ * Allow space for super block summary information in first
+ * cylinder group.
+ */
+ cbase = cgbase(&sblock, cylno);
+ dmax = cbase + sblock.fs_fpg;
+ if (dmax > sblock.fs_size)
+ dmax = sblock.fs_size;
+ dlower = cgsblock(&sblock, cylno) - cbase;
+ dupper = cgdmin(&sblock, cylno) - cbase;
+ if (cylno == 0)
+ dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
+ memset(&acg, 0, sblock.fs_cgsize);
+ acg.cg_time = utime;
+ acg.cg_magic = CG_MAGIC;
+ acg.cg_cgx = cylno;
+ acg.cg_niblk = sblock.fs_ipg;
+ acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
+ sblock.fs_ipg : 2 * INOPB(&sblock);
+ acg.cg_ndblk = dmax - cbase;
+ if (sblock.fs_contigsumsize > 0)
+ acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift;
+ start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
+ if (Oflag == 2) {
+ acg.cg_iusedoff = start;
+ } else {
+ if (cylno == sblock.fs_ncg - 1)
+ acg.cg_old_ncyl = howmany(acg.cg_ndblk,
+ sblock.fs_fpg / sblock.fs_old_cpg);
+ else
+ acg.cg_old_ncyl = sblock.fs_old_cpg;
+ acg.cg_old_time = acg.cg_time;
+ acg.cg_time = 0;
+ acg.cg_old_niblk = acg.cg_niblk;
+ acg.cg_niblk = 0;
+ acg.cg_initediblk = 0;
+ acg.cg_old_btotoff = start;
+ acg.cg_old_boff = acg.cg_old_btotoff +
+ sblock.fs_old_cpg * sizeof(int32_t);
+ acg.cg_iusedoff = acg.cg_old_boff +
+ sblock.fs_old_cpg * sizeof(u_int16_t);
+ }
+ acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
+ if (sblock.fs_contigsumsize <= 0) {
+ acg.cg_nextfreeoff = acg.cg_freeoff +
+ howmany(sblock.fs_fpg, CHAR_BIT);
+ } else {
+ acg.cg_clustersumoff = acg.cg_freeoff +
+ howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t);
+ acg.cg_clustersumoff =
+ roundup(acg.cg_clustersumoff, sizeof(int32_t));
+ acg.cg_clusteroff = acg.cg_clustersumoff +
+ (sblock.fs_contigsumsize + 1) * sizeof(int32_t);
+ acg.cg_nextfreeoff = acg.cg_clusteroff +
+ howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
+ }
+ if (acg.cg_nextfreeoff > sblock.fs_cgsize) {
+ printf("Panic: cylinder group too big\n");
+ exit(37);
+ }
+ acg.cg_cs.cs_nifree += sblock.fs_ipg;
+ if (cylno == 0)
+ for (i = 0; i < ROOTINO; i++) {
+ setbit(cg_inosused_swap(&acg, 0), i);
+ acg.cg_cs.cs_nifree--;
+ }
+ if (cylno > 0) {
+ /*
+ * In cylno 0, beginning space is reserved
+ * for boot and super blocks.
+ */
+ for (d = 0, blkno = 0; d < dlower;) {
+ ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno);
+ if (sblock.fs_contigsumsize > 0)
+ setbit(cg_clustersfree_swap(&acg, 0), blkno);
+ acg.cg_cs.cs_nbfree++;
+ d += sblock.fs_frag;
+ blkno++;
+ }
+ }
+ if ((i = (dupper & (sblock.fs_frag - 1))) != 0) {
+ acg.cg_frsum[sblock.fs_frag - i]++;
+ for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
+ setbit(cg_blksfree_swap(&acg, 0), dupper);
+ acg.cg_cs.cs_nffree++;
+ }
+ }
+ for (d = dupper, blkno = dupper >> sblock.fs_fragshift;
+ d + sblock.fs_frag <= acg.cg_ndblk; ) {
+ ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno);
+ if (sblock.fs_contigsumsize > 0)
+ setbit(cg_clustersfree_swap(&acg, 0), blkno);
+ acg.cg_cs.cs_nbfree++;
+ d += sblock.fs_frag;
+ blkno++;
+ }
+ if (d < acg.cg_ndblk) {
+ acg.cg_frsum[acg.cg_ndblk - d]++;
+ for (; d < acg.cg_ndblk; d++) {
+ setbit(cg_blksfree_swap(&acg, 0), d);
+ acg.cg_cs.cs_nffree++;
+ }
+ }
+ if (sblock.fs_contigsumsize > 0) {
+ int32_t *sump = cg_clustersum_swap(&acg, 0);
+ u_char *mapp = cg_clustersfree_swap(&acg, 0);
+ int map = *mapp++;
+ int bit = 1;
+ int run = 0;
+
+ for (i = 0; i < acg.cg_nclusterblks; i++) {
+ if ((map & bit) != 0) {
+ run++;
+ } else if (run != 0) {
+ if (run > sblock.fs_contigsumsize)
+ run = sblock.fs_contigsumsize;
+ sump[run]++;
+ run = 0;
+ }
+ if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
+ bit <<= 1;
+ } else {
+ map = *mapp++;
+ bit = 1;
+ }
+ }
+ if (run != 0) {
+ if (run > sblock.fs_contigsumsize)
+ run = sblock.fs_contigsumsize;
+ sump[run]++;
+ }
+ }
+ sblock.fs_cs(&sblock, cylno) = acg.cg_cs;
+ /*
+ * Write out the duplicate super block, the cylinder group map
+ * and two blocks worth of inodes in a single write.
+ */
+ start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE;
+ memcpy(&iobuf[start], &acg, sblock.fs_cgsize);
+ if (fsopts->needswap)
+ ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock);
+ start += sblock.fs_bsize;
+ dp1 = (struct ufs1_dinode *)(&iobuf[start]);
+ dp2 = (struct ufs2_dinode *)(&iobuf[start]);
+ for (i = 0; i < acg.cg_initediblk; i++) {
+ if (sblock.fs_magic == FS_UFS1_MAGIC) {
+ /* No need to swap, it'll stay random */
+ dp1->di_gen = random();
+ dp1++;
+ } else {
+ dp2->di_gen = random();
+ dp2++;
+ }
+ }
+ ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf,
+ fsopts);
+ /*
+ * For the old file system, we have to initialize all the inodes.
+ */
+ if (Oflag <= 1) {
+ for (i = 2 * sblock.fs_frag;
+ i < sblock.fs_ipg / INOPF(&sblock);
+ i += sblock.fs_frag) {
+ dp1 = (struct ufs1_dinode *)(&iobuf[start]);
+ for (j = 0; j < INOPB(&sblock); j++) {
+ dp1->di_gen = random();
+ dp1++;
+ }
+ ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
+ sblock.fs_bsize, &iobuf[start], fsopts);
+ }
+ }
+}
+
+/*
+ * read a block from the file system
+ */
+void
+ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
+{
+ int n;
+ off_t offset;
+
+ offset = bno;
+ offset *= fsopts->sectorsize;
+ if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
+ err(1, "ffs_rdfs: seek error for sector %lld: %s\n",
+ (long long)bno, strerror(errno));
+ n = read(fsopts->fd, bf, size);
+ if (n == -1) {
+ abort();
+ err(1, "ffs_rdfs: read error bno %lld size %d", (long long)bno,
+ size);
+ }
+ else if (n != size)
+ errx(1, "ffs_rdfs: read error for sector %lld: %s\n",
+ (long long)bno, strerror(errno));
+}
+
+/*
+ * write a block to the file system
+ */
+void
+ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts)
+{
+ int n;
+ off_t offset;
+
+ offset = bno;
+ offset *= fsopts->sectorsize;
+ if (lseek(fsopts->fd, offset, SEEK_SET) < 0)
+ err(1, "wtfs: seek error for sector %lld: %s\n",
+ (long long)bno, strerror(errno));
+ n = write(fsopts->fd, bf, size);
+ if (n == -1)
+ err(1, "wtfs: write error for sector %lld: %s\n",
+ (long long)bno, strerror(errno));
+ else if (n != size)
+ errx(1, "wtfs: write error for sector %lld: %s\n",
+ (long long)bno, strerror(errno));
+}
+
+
+/* Determine how many digits are needed to print a given integer */
+static int
+count_digits(int num)
+{
+ int ndig;
+
+ for(ndig = 1; num > 9; num /=10, ndig++);
+
+ return (ndig);
+}
+
+static int
+ilog2(int val)
+{
+ u_int n;
+
+ for (n = 0; n < sizeof(n) * CHAR_BIT; n++)
+ if (1 << n == val)
+ return (n);
+ errx(1, "ilog2: %d is not a power of 2\n", val);
+}
diff --git a/usr.sbin/makefs/ffs/newfs_extern.h b/usr.sbin/makefs/ffs/newfs_extern.h
new file mode 100644
index 0000000..a54c0e2
--- /dev/null
+++ b/usr.sbin/makefs/ffs/newfs_extern.h
@@ -0,0 +1,36 @@
+/* $NetBSD: newfs_extern.h,v 1.3 2009/10/21 01:07:47 snj Exp $ */
+/* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */
+
+/*
+ * Copyright (c) 1997 Christos Zoulas. 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 ``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 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$
+ */
+
+/* prototypes */
+struct fs *ffs_mkfs(const char *, const fsinfo_t *);
+void ffs_write_superblock(struct fs *, const fsinfo_t *);
+void ffs_rdfs(daddr_t, int, void *, const fsinfo_t *);
+void ffs_wtfs(daddr_t, int, void *, const fsinfo_t *);
+
+#define FFS_MAXBSIZE 65536
diff --git a/usr.sbin/makefs/ffs/ufs_bmap.c b/usr.sbin/makefs/ffs/ufs_bmap.c
new file mode 100644
index 0000000..b65b416
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ufs_bmap.c
@@ -0,0 +1,140 @@
+/* $NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $ */
+/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
+
+/*
+ * Copyright (c) 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ * @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <strings.h>
+
+#include "makefs.h"
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include "ffs/ufs_bswap.h"
+#include "ffs/ufs_inode.h"
+#include "ffs/ffs_extern.h"
+
+/*
+ * Create an array of logical block number/offset pairs which represent the
+ * path of indirect blocks required to access a data block. The first "pair"
+ * contains the logical block number of the appropriate single, double or
+ * triple indirect block and the offset into the inode indirect block array.
+ * Note, the logical block number of the inode single/double/triple indirect
+ * block appears twice in the array, once with the offset into the i_ffs_ib and
+ * once with the offset into the page itself.
+ */
+int
+ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
+{
+ daddr_t metalbn, realbn;
+ int64_t blockcnt;
+ int lbc;
+ int i, numlevels, off;
+ u_long lognindir;
+
+ lognindir = ffs(NINDIR(ip->i_fs)) - 1;
+ if (nump)
+ *nump = 0;
+ numlevels = 0;
+ realbn = bn;
+ if ((long)bn < 0)
+ bn = -(long)bn;
+
+ assert (bn >= NDADDR);
+
+ /*
+ * Determine the number of levels of indirection. After this loop
+ * is done, blockcnt indicates the number of data blocks possible
+ * at the given level of indirection, and NIADDR - i is the number
+ * of levels of indirection needed to locate the requested block.
+ */
+
+ bn -= NDADDR;
+ for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
+ if (i == 0)
+ return (EFBIG);
+
+ lbc += lognindir;
+ blockcnt = (int64_t)1 << lbc;
+
+ if (bn < blockcnt)
+ break;
+ }
+
+ /* Calculate the address of the first meta-block. */
+ if (realbn >= 0)
+ metalbn = -(realbn - bn + NIADDR - i);
+ else
+ metalbn = -(-realbn - bn + NIADDR - i);
+
+ /*
+ * At each iteration, off is the offset into the bap array which is
+ * an array of disk addresses at the current level of indirection.
+ * The logical block number and the offset in that block are stored
+ * into the argument array.
+ */
+ ap->in_lbn = metalbn;
+ ap->in_off = off = NIADDR - i;
+ ap++;
+ for (++numlevels; i <= NIADDR; i++) {
+ /* If searching for a meta-data block, quit when found. */
+ if (metalbn == realbn)
+ break;
+
+ lbc -= lognindir;
+ blockcnt = (int64_t)1 << lbc;
+ off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
+
+ ++numlevels;
+ ap->in_lbn = metalbn;
+ ap->in_off = off;
+ ++ap;
+
+ metalbn -= -1 + (off << lbc);
+ }
+ if (nump)
+ *nump = numlevels;
+ return (0);
+}
diff --git a/usr.sbin/makefs/ffs/ufs_bswap.h b/usr.sbin/makefs/ffs/ufs_bswap.h
new file mode 100644
index 0000000..6e7cc42
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ufs_bswap.h
@@ -0,0 +1,90 @@
+/* $NetBSD: ufs_bswap.h,v 1.13 2003/10/05 17:48:50 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1998 Manuel Bouyer.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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$
+ */
+
+#ifndef _UFS_UFS_BSWAP_H_
+#define _UFS_UFS_BSWAP_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_ffs.h"
+#endif
+
+#include <sys/endian.h>
+
+#include "makefs.h"
+
+/* Macros to access UFS flags */
+#ifdef FFS_EI
+#define UFS_MPNEEDSWAP(mp) (VFSTOUFS(mp)->um_flags & UFS_NEEDSWAP)
+#define UFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED)
+#define UFS_IPNEEDSWAP(ip) UFS_MPNEEDSWAP(ITOV(ip)->v_mount)
+#else
+#define UFS_MPNEEDSWAP(mp) (0)
+#define UFS_FSNEEDSWAP(fs) (0)
+#define UFS_IPNEEDSWAP(ip) (0)
+#endif
+
+#if !defined(_KERNEL) || defined(FFS_EI)
+/* inlines for access to swapped data */
+static __inline u_int16_t ufs_rw16 __P((u_int16_t, int));
+static __inline u_int32_t ufs_rw32 __P((u_int32_t, int));
+static __inline u_int64_t ufs_rw64 __P((u_int64_t, int));
+
+static __inline u_int16_t
+ufs_rw16(u_int16_t a, int ns)
+{
+ return ((ns) ? bswap16(a) : (a));
+}
+static __inline u_int32_t
+ufs_rw32(u_int32_t a, int ns)
+{
+ return ((ns) ? bswap32(a) : (a));
+}
+static __inline u_int64_t
+ufs_rw64(u_int64_t a, int ns)
+{
+ return ((ns) ? bswap64(a) : (a));
+}
+#else
+#define ufs_rw16(a, ns) ((uint16_t)(a))
+#define ufs_rw32(a, ns) ((uint32_t)(a))
+#define ufs_rw64(a, ns) ((uint64_t)(a))
+#endif
+
+#define ufs_add16(a, b, ns) \
+ (a) = ufs_rw16(ufs_rw16((a), (ns)) + (b), (ns))
+#define ufs_add32(a, b, ns) \
+ (a) = ufs_rw32(ufs_rw32((a), (ns)) + (b), (ns))
+#define ufs_add64(a, b, ns) \
+ (a) = ufs_rw64(ufs_rw64((a), (ns)) + (b), (ns))
+
+#endif /* !_UFS_UFS_BSWAP_H_ */
diff --git a/usr.sbin/makefs/ffs/ufs_inode.h b/usr.sbin/makefs/ffs/ufs_inode.h
new file mode 100644
index 0000000..8286f86
--- /dev/null
+++ b/usr.sbin/makefs/ffs/ufs_inode.h
@@ -0,0 +1,97 @@
+/* $NetBSD: ufs_inode.h,v 1.3 2003/08/07 11:25:34 agc Exp $ */
+/* From: NetBSD: inode.h,v 1.27 2001/12/18 10:57:23 fvdl Exp $ */
+
+/*
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ * @(#)inode.h 8.9 (Berkeley) 5/14/95
+ * $FreeBSD$
+ */
+
+union dinode {
+ struct ufs1_dinode ffs1_din;
+ struct ufs2_dinode ffs2_din;
+};
+
+struct inode {
+ ino_t i_number; /* The identity of the inode. */
+ struct fs *i_fs; /* File system */
+ union dinode i_din;
+ int i_fd; /* File descriptor */
+ uint64_t i_size;
+};
+
+#define i_ffs1_atime i_din.ffs1_din.di_atime
+#define i_ffs1_atimensec i_din.ffs1_din.di_atimensec
+#define i_ffs1_blocks i_din.ffs1_din.di_blocks
+#define i_ffs1_ctime i_din.ffs1_din.di_ctime
+#define i_ffs1_ctimensec i_din.ffs1_din.di_ctimensec
+#define i_ffs1_db i_din.ffs1_din.di_db
+#define i_ffs1_flags i_din.ffs1_din.di_flags
+#define i_ffs1_gen i_din.ffs1_din.di_gen
+#define i_ffs11_gid i_din.ffs1_din.di_gid
+#define i_ffs1_ib i_din.ffs1_din.di_ib
+#define i_ffs1_mode i_din.ffs1_din.di_mode
+#define i_ffs1_mtime i_din.ffs1_din.di_mtime
+#define i_ffs1_mtimensec i_din.ffs1_din.di_mtimensec
+#define i_ffs1_nlink i_din.ffs1_din.di_nlink
+#define i_ffs1_rdev i_din.ffs1_din.di_rdev
+#define i_ffs1_shortlink i_din.ffs1_din.db
+#define i_ffs1_size i_din.ffs1_din.di_size
+#define i_ffs1_uid i_din.ffs1_din.di_uid
+
+#define i_ffs2_atime i_din.ffs2_din.di_atime
+#define i_ffs2_atimensec i_din.ffs2_din.di_atimensec
+#define i_ffs2_blocks i_din.ffs2_din.di_blocks
+#define i_ffs2_ctime i_din.ffs2_din.di_ctime
+#define i_ffs2_ctimensec i_din.ffs2_din.di_ctimensec
+#define i_ffs2_birthtime i_din.ffs2_din.di_birthtime
+#define i_ffs2_birthnsec i_din.ffs2_din.di_birthnsec
+#define i_ffs2_db i_din.ffs2_din.di_db
+#define i_ffs2_flags i_din.ffs2_din.di_flags
+#define i_ffs2_gen i_din.ffs2_din.di_gen
+#define i_ffs21_gid i_din.ffs2_din.di_gid
+#define i_ffs2_ib i_din.ffs2_din.di_ib
+#define i_ffs2_mode i_din.ffs2_din.di_mode
+#define i_ffs2_mtime i_din.ffs2_din.di_mtime
+#define i_ffs2_mtimensec i_din.ffs2_din.di_mtimensec
+#define i_ffs2_nlink i_din.ffs2_din.di_nlink
+#define i_ffs2_rdev i_din.ffs2_din.di_rdev
+#define i_ffs2_shortlink i_din.ffs2_din.db
+#define i_ffs2_size i_din.ffs2_din.di_size
+#define i_ffs2_uid i_din.ffs2_din.di_uid
+
+#undef DIP
+#define DIP(ip, field) \
+ (((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) ? \
+ (ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
OpenPOWER on IntegriCloud