ROOTFILES="`cat /.rootfiles`"
USRFILES="`cat /.usrfiles`"
+if [ -z "$FSTYPE" ]
+then FSTYPE=mfs
+fi
+
if [ "$TOTALMB" -lt 1 ]
then
echo "Are you really running from CD?"
then
if [ ! "$auto" = r ]
then echo "Creating /dev/$home for /home .."
- mkfs.mfs -B $blocksizebytes /dev/$home || exit
+ mkfs.$FSTYPE -B $blocksizebytes /dev/$home || exit
fi
else echo "Skipping /home"
fi
echo "Creating /dev/$usr for /usr .."
-mkfs.mfs -B $blocksizebytes /dev/$usr || exit
+mkfs.$FSTYPE -B $blocksizebytes /dev/$usr || exit
if [ "$nohome" = 0 ]
then
- fshome="/dev/$home /home mfs rw 0 2"
+ fshome="/dev/$home /home $FSTYPE rw 0 2"
else fshome=""
fi
# CD remnants that aren't for the installed system
rm /mnt/etc/issue /mnt/CD /mnt/.* 2>/dev/null
echo >/mnt/etc/fstab "/dev/$root / mfs rw 0 1
-/dev/$usr /usr mfs rw 0 2
+/dev/$usr /usr $FSTYPE rw 0 2
$fshome"
# National keyboard map.
#include <minix/types.h>
#endif
+#include <minix/u64.h>
+
+int minix_sizeup(char *name, u64_t *bytes);
+
struct partition {
u64_t base; /* byte offset to the partition start */
u64_t size; /* number of bytes in the partition */
uint16_t d_npartitions; /* number of partitions in following */
uint32_t d_bbsize; /* size of boot area at sn0, bytes */
uint32_t d_sbsize; /* max size of fs superblock, bytes */
+#ifndef __minix
struct partition { /* the partition table */
uint32_t p_size; /* number of sectors in partition */
uint32_t p_offset; /* starting sector */
#define p_cpg __partition_u1.cpg
#define p_sgs __partition_u1.sgs
} d_partitions[MAXPARTITIONS]; /* actually may be more */
+#endif
};
#if defined(__HAVE_OLD_DISKLABEL) && !HAVE_NBTOOL_CONFIG_H
#include <uuid.h>
+#ifdef __minix
+#include <paths.h>
+#include <fcntl.h>
+/* Fake a uuidgen() syscall */
+int uuidgen(struct uuid *store, int count)
+{
+ int rfd;
+
+ if((rfd = open(_PATH_RANDOM, O_RDONLY)) < 0) {
+ return -1;
+ }
+
+ while(count--) {
+ if(read(rfd, store++, sizeof(*store)) < sizeof(*store)) {
+ close(rfd);
+ return -1;
+ }
+ }
+
+ close(rfd);
+
+ return 0;
+}
+#endif
+
/*
* uuid_create() - create an UUID.
* See also:
strings.h stringlist.h struct.h sysexits.h tar.h time.h \
ttyent.h tzfile.h ucontext.h ulimit.h unistd.h util.h utime.h utmp.h \
utmpx.h uuid.h varargs.h vis.h wchar.h wctype.h wordexp.h
+
+INCS += ufs/chfs/chfs.h ufs/chfs/chfs_args.h ufs/chfs/chfs_inode.h \
+ ufs/chfs/chfs_pool.h ufs/chfs/debug.h ufs/chfs/ebh.h \
+ ufs/chfs/ebh_media.h ufs/chfs/ebh_misc.h ufs/chfs/media.h \
+ ufs/ext2fs/ext2fs.h ufs/ext2fs/ext2fs_dinode.h \
+ ufs/ext2fs/ext2fs_dir.h ufs/ext2fs/ext2fs_extern.h \
+ ufs/ffs/ffs_extern.h ufs/ffs/fs.h ufs/lfs/lfs.h \
+ ufs/lfs/lfs_extern.h ufs/mfs/mfs_extern.h ufs/mfs/mfsnode.h \
+ ufs/ufs/dinode.h ufs/ufs/dir.h ufs/ufs/dirhash.h \
+ ufs/ufs/extattr.h ufs/ufs/inode.h ufs/ufs/quota.h \
+ ufs/ufs/quota1.h ufs/ufs/quota2.h ufs/ufs/ufs_bswap.h \
+ ufs/ufs/ufs_extern.h ufs/ufs/ufs_quota.h ufs/ufs/ufs_wapbl.h \
+ ufs/ufs/ufsmount.h \
+
.else
INCS= a.out.h aio.h ar.h assert.h atomic.h \
bitstring.h bm.h cdbr.h cdbw.h complex.h cpio.h ctype.h \
--- /dev/null
+/* $NetBSD: chfs.h,v 1.4 2011/11/28 12:50:07 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2009 Tamas Toth <ttoth@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef __CHFS_H__
+#define __CHFS_H__
+
+#if 0
+#define DBG_MSG
+#define DBG_MSG_GC
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/cdefs.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/kmem.h>
+#include <sys/endian.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+#include <sys/kthread.h>
+#include <sys/rbtree.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/hash.h>
+#include <sys/module.h>
+#include <sys/dirent.h>
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dir.h>
+
+/* XXX shouldnt be defined here, but needed by chfs_inode.h */
+TAILQ_HEAD(chfs_dirent_list, chfs_dirent);
+
+#include "chfs_pool.h"
+#include "ebh.h"
+#include "media.h"
+#include "chfs_inode.h"
+
+#ifndef MOUNT_CHFS
+#define MOUNT_CHFS "chfs"
+#endif
+
+#define CHFS_ROOTINO ROOTINO /* ROOTINO == 2 */
+
+enum {
+ VNO_STATE_UNCHECKED, /* CRC checks not yet done */
+ VNO_STATE_CHECKING, /* CRC checks in progress */
+ VNO_STATE_PRESENT, /* In core */
+ VNO_STATE_CHECKEDABSENT,/* Checked, cleared again */
+ VNO_STATE_GC, /* GCing a 'pristine' node */
+ VNO_STATE_READING, /* In read_inode() */
+ VNO_STATE_CLEARING /* In clear_inode() */
+};
+
+#define VNODECACHE_SIZE 128
+
+#define MAX_READ_FREE(chmp) (((chmp)->chm_ebh)->eb_size / 8)
+/* an eraseblock will be clean if its dirty size is smaller than this */
+#define MAX_DIRTY_TO_CLEAN 255
+#define VERY_DIRTY(chmp, size) ((size) >= (((chmp)->chm_ebh)->eb_size / 2))
+
+#define CHFS_PAD(x) (((x)+3)&~3)
+
+enum {
+ CHFS_NODE_OK = 0,
+ CHFS_NODE_BADMAGIC,
+ CHFS_NODE_BADCRC,
+ CHFS_NODE_BADNAMECRC
+};
+
+enum {
+ CHFS_BLK_STATE_FREE = 100,
+ CHFS_BLK_STATE_CLEAN,
+ CHFS_BLK_STATE_PARTDIRTY,
+ CHFS_BLK_STATE_ALLDIRTY
+};
+
+extern struct pool chfs_inode_pool;
+extern const struct genfs_ops chfs_genfsops;
+
+/**
+ * struct chfs_node_ref - a reference to a node
+ * @lnr: logical identifier of the eraseblock where the node is
+ * @offset: offset int hte eraseblock where the node starts
+ * @next: used at data and dirent nodes, it points to the next data node which
+ * belongs to the same vnode
+ */
+struct chfs_node_ref
+{
+ struct chfs_node_ref *nref_next;
+ uint32_t nref_lnr;
+ uint32_t nref_offset;
+};
+
+/* Constants for allocating node refs */
+#define REFS_BLOCK_LEN (255/sizeof(struct chfs_node_ref))
+#define REF_EMPTY_NODE (UINT_MAX)
+#define REF_LINK_TO_NEXT (UINT_MAX - 1)
+
+enum {
+ CHFS_NORMAL_NODE_MASK,
+ CHFS_UNCHECKED_NODE_MASK,
+ CHFS_OBSOLETE_NODE_MASK,
+ CHFS_PRISTINE_NODE_MASK
+};
+
+#define CHFS_REF_FLAGS(ref) ((ref)->nref_offset & 3)
+#define CHFS_REF_OBSOLETE(ref) (((ref)->nref_offset & 3) == CHFS_OBSOLETE_NODE_MASK)
+#define CHFS_MARK_REF_NORMAL(ref) \
+ do { \
+ (ref)->nref_offset = CHFS_GET_OFS((ref)->nref_offset) | CHFS_NORMAL_NODE_MASK; \
+ } while(0)
+
+#define CHFS_GET_OFS(ofs) (ofs & ~ 3)
+
+static inline struct chfs_node_ref *
+node_next(struct chfs_node_ref *nref)
+{
+ //dbg("node next: %u : %u\n", nref->nref_lnr, nref->nref_offset);
+ nref++;
+ //dbg("nref++: %u : %u\n", nref->nref_lnr, nref->nref_offset);
+
+ if (nref->nref_lnr == REF_LINK_TO_NEXT) {
+ //dbg("link to next\n");
+ nref = nref->nref_next;
+ if (!nref)
+ return nref;
+ }
+
+ if (nref->nref_lnr == REF_EMPTY_NODE) {
+ //dbg("empty\n");
+ return NULL;
+ }
+
+ return nref;
+}
+
+/**
+ * struct chfs_dirent - full representation of a directory entry
+ */
+struct chfs_dirent
+{
+ struct chfs_node_ref *nref;
+// struct chfs_dirent *next;
+ TAILQ_ENTRY(chfs_dirent) fds;
+ uint64_t version;
+ ino_t vno;
+ uint32_t nhash;
+ enum vtype type;
+ uint8_t nsize;
+ uint8_t name[0];
+
+ /* used by chfs_alloc_dirent and free counterpart */
+// size_t alloc_size;
+};
+
+struct chfs_tmp_dnode {
+ struct chfs_full_dnode *node;
+ uint64_t version;
+ uint32_t data_crc;
+ //uint32_t partial_crc;
+ //uint16_t csize;
+ uint16_t overlapped;
+ struct chfs_tmp_dnode *next;
+};
+
+struct chfs_tmp_dnode_info {
+ struct rb_node rb_node;
+ struct chfs_tmp_dnode *tmpnode;
+};
+
+struct chfs_readinode_info {
+ struct rb_tree tdi_root;
+ struct chfs_tmp_dnode_info *mdata_tn;
+ uint64_t highest_version;
+ struct chfs_node_ref *latest_ref;
+};
+
+struct chfs_full_dnode {
+ struct chfs_node_ref *nref;
+ uint64_t ofs;
+ uint32_t size;
+ uint32_t frags;
+};
+
+struct chfs_node_frag {
+ struct rb_node rb_node;
+ struct chfs_full_dnode *node;
+ uint32_t size;
+ uint64_t ofs;
+};
+
+static inline struct chfs_node_frag *
+frag_first(struct rb_tree *tree)
+{
+ struct chfs_node_frag *frag;
+
+ frag = (struct chfs_node_frag *)RB_TREE_MIN(tree);
+
+ return frag;
+}
+
+static inline struct chfs_node_frag *
+frag_last(struct rb_tree *tree)
+{
+ struct chfs_node_frag *frag;
+
+ frag = (struct chfs_node_frag *)RB_TREE_MAX(tree);
+
+ return frag;
+}
+
+#define frag_next(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_RIGHT)
+#define frag_prev(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_LEFT)
+
+
+/* XXX hack
+ #ifndef CHFS_FRAG_TREE
+ #define CHFS_FRAG_TREE
+ RB_HEAD(chfs_frag_tree, chfs_node_frag);
+ #endif
+*/
+
+/* for prototypes, properly defined in chfs_inode.h */
+//struct chfs_inode_ext;
+
+/**
+ * struct chfs_vnode_cache - in memory representation of a vnode
+ * @v: pointer to the vnode info node
+ * @dnode: pointer to the list of data nodes
+ * @dirents: pointer to the list of directory entries
+ * @vno_version: used only during scan, holds the current version number of
+ * chfs_flash_vnode
+ * @scan_dirents: used only during scan, holds the full representation of
+ * directory entries of this vnode
+ * @pvno: parent vnode number
+ * @nlink: number of links to this vnode
+ */
+struct chfs_vnode_cache {
+// struct chfs_dirent *scan_dirents;
+ void *p;
+ struct chfs_dirent_list scan_dirents;
+
+ struct chfs_node_ref *v;
+ struct chfs_node_ref *dnode;
+ struct chfs_node_ref *dirents;
+
+ uint64_t *vno_version;
+ uint64_t highest_version;
+
+ uint8_t flags;
+ uint16_t state;
+ ino_t vno;
+ ino_t pvno;
+ struct chfs_vnode_cache* next;
+ uint32_t nlink;
+};
+
+struct chfs_eraseblock
+{
+ uint32_t lnr;
+
+ TAILQ_ENTRY(chfs_eraseblock) queue;
+ //uint32_t bad_count;
+ uint32_t unchecked_size;
+ uint32_t used_size;
+ uint32_t dirty_size;
+ uint32_t free_size;
+ uint32_t wasted_size;
+
+ struct chfs_node_ref *first_node;
+ struct chfs_node_ref *last_node;
+
+ /* Next block to be garbage collected */
+ struct chfs_node_ref *gc_node;
+};
+
+TAILQ_HEAD(chfs_eraseblock_queue, chfs_eraseblock);
+
+#define ALLOC_NORMAL 0
+#define ALLOC_DELETION 1
+#define ALLOC_GC 2
+
+struct garbage_collector_thread {
+ lwp_t *gcth_thread;
+ kcondvar_t gcth_wakeup;
+ bool gcth_running;
+};
+
+#define CHFS_MP_FLAG_SCANNING 2
+#define CHFS_MP_FLAG_BUILDING 4
+
+/**
+ * struct chfs_mount - CHFS main descriptor structure
+ * @ebh: eraseblock handler
+ * @fl_index: index of flash device in the flash layer
+ * @fs_version: filesystem version descriptor
+ * @gbl_version: global version number
+ * @max_vno: max vnode id
+ * @chm_lock_mountfields:
+ * @vnocache_hash: hash table of vnode caches
+ * @vnocache_lock:
+ * @blocks: array of eraseblocks on flash
+ * @chm_root: used to protect all fields
+ * @free_size: free size on the flash
+ * @dirty_size: dirtied size on flash
+ * @unchecked_size: size of unchecked data on flash
+ * @free_queue: queue of free eraseblocks
+ * @clean_queue: queue of clean eraseblocks
+ * @dirty_queue: queue of dirty eraseblocks
+ * @very_dirty_queue: queue of very dirty eraseblocks
+ * @erase_pending_queue: queue of eraseblocks waiting for erasing
+ * @erasable_pending_wbuf_queue: queue of eraseblocks waiting for erasing and
+ * have data to write to them
+ * @nextblock: next eraseblock to write to
+ * @nr_free_blocks: number of free blocks on the free_queue
+ * @nr_erasable_blocks: number of blocks that can be erased and are on the
+ * erasable_queue
+ */
+struct chfs_mount {
+ struct mount *chm_fsmp;
+ struct chfs_ebh *chm_ebh;
+ int chm_fs_version;
+ uint64_t chm_gbl_version;
+ ino_t chm_max_vno;
+ ino_t chm_checked_vno;
+ unsigned int chm_flags;
+
+ /* chm_lock_mountfields:
+ * Used to protect all the following fields. */
+ kmutex_t chm_lock_mountfields;
+
+ struct chfs_vnode_cache **chm_vnocache_hash;
+ /* chm_lock_vnocache:
+ * Used to protect the vnode cache.
+ * If you have to lock chm_lock_mountfields and also chm_lock_vnocache,
+ * you must lock chm_lock_mountfields first. */
+ kmutex_t chm_lock_vnocache;
+
+ struct chfs_eraseblock *chm_blocks;
+
+ struct chfs_node *chm_root;
+
+ uint32_t chm_free_size;
+ uint32_t chm_dirty_size;
+ uint32_t chm_unchecked_size;
+ uint32_t chm_used_size;
+ uint32_t chm_wasted_size;
+ /* chm_lock_sizes:
+ * Used to protect the (free, used, etc.) sizes of the FS
+ * (and also the sizes of each eraseblock).
+ * If you have to lock chm_lock_mountfields and also chm_lock_sizes,
+ * you must lock chm_lock_mountfields first. */
+ kmutex_t chm_lock_sizes;
+
+ struct chfs_eraseblock_queue chm_free_queue;
+ struct chfs_eraseblock_queue chm_clean_queue;
+ struct chfs_eraseblock_queue chm_dirty_queue;
+ struct chfs_eraseblock_queue chm_very_dirty_queue;
+ struct chfs_eraseblock_queue chm_erasable_pending_wbuf_queue;
+ struct chfs_eraseblock_queue chm_erase_pending_queue;
+
+ uint8_t chm_resv_blocks_deletion;
+ uint8_t chm_resv_blocks_write;
+ uint8_t chm_resv_blocks_gctrigger;
+ uint8_t chm_resv_blocks_gcmerge;
+ uint8_t chm_nospc_dirty;
+
+ uint8_t chm_vdirty_blocks_gctrigger;
+
+ struct chfs_eraseblock *chm_nextblock;
+
+ struct garbage_collector_thread chm_gc_thread;
+ struct chfs_eraseblock *chm_gcblock;
+
+ int chm_nr_free_blocks;
+ int chm_nr_erasable_blocks;
+
+ int32_t chm_fs_bmask;
+ int32_t chm_fs_bsize;
+ int32_t chm_fs_qbmask;
+ int32_t chm_fs_bshift;
+ int32_t chm_fs_fmask;
+ int64_t chm_fs_qfmask;
+
+ /* TODO will we use these? */
+ unsigned int chm_pages_max;
+ unsigned int chm_pages_used;
+ unsigned int chm_nodes_max;
+ unsigned int chm_nodes_cnt;
+ struct chfs_pool chm_dirent_pool;
+ struct chfs_pool chm_node_pool;
+ struct chfs_str_pool chm_str_pool;
+ /**/
+
+ size_t chm_wbuf_pagesize;
+ unsigned char* chm_wbuf;
+ size_t chm_wbuf_ofs;
+ size_t chm_wbuf_len;
+ /* chm_lock_wbuf:
+ * Used to protect the write buffer.
+ * If you have to lock chm_lock_mountfields and also chm_lock_wbuf,
+ * you must lock chm_lock_mountfields first. */
+ krwlock_t chm_lock_wbuf;
+};
+
+/*
+ * TODO we should move here all of these from the bottom of the file
+ * Macros/functions to convert from generic data structures to chfs
+ * specific ones.
+ */
+
+#define CHFS_OFFSET_DOT 0
+#define CHFS_OFFSET_DOTDOT 1
+#define CHFS_OFFSET_EOF 2
+#define CHFS_OFFSET_FIRST 3
+
+
+/*---------------------------------------------------------------------------*/
+
+/* chfs_build.c */
+void chfs_calc_trigger_levels(struct chfs_mount *);
+int chfs_build_filesystem(struct chfs_mount *);
+void chfs_build_set_vnodecache_nlink(struct chfs_mount *,
+ struct chfs_vnode_cache *);
+void chfs_build_remove_unlinked_vnode(struct chfs_mount *,
+ struct chfs_vnode_cache *, struct chfs_dirent_list *);
+
+/* chfs_scan.c */
+int chfs_scan_eraseblock(struct chfs_mount *, struct chfs_eraseblock *);
+struct chfs_vnode_cache *chfs_scan_make_vnode_cache(struct chfs_mount *,
+ ino_t);
+int chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *);
+int chfs_scan_check_vnode(struct chfs_mount *,
+ struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_mark_dirent_obsolete(struct chfs_mount *,
+ struct chfs_vnode_cache *, struct chfs_dirent *);
+void chfs_add_fd_to_list(struct chfs_mount *,
+ struct chfs_dirent *, struct chfs_vnode_cache *);
+int chfs_scan_check_dirent_node(struct chfs_mount *,
+ struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_check_data_node(struct chfs_mount *,
+ struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_classify_cheb(struct chfs_mount *,
+ struct chfs_eraseblock *);
+
+/* chfs_nodeops.c */
+int chfs_update_eb_dirty(struct chfs_mount *,
+ struct chfs_eraseblock *, uint32_t);
+void chfs_add_node_to_list(struct chfs_mount *, struct chfs_vnode_cache *,
+ struct chfs_node_ref *, struct chfs_node_ref **);
+void chfs_add_fd_to_inode(struct chfs_mount *,
+ struct chfs_inode *, struct chfs_dirent *);
+void chfs_add_vnode_ref_to_vc(struct chfs_mount *, struct chfs_vnode_cache *,
+ struct chfs_node_ref *);
+struct chfs_node_ref* chfs_nref_next(struct chfs_node_ref *);
+int chfs_nref_len(struct chfs_mount *,
+ struct chfs_eraseblock *, struct chfs_node_ref *);
+int chfs_close_eraseblock(struct chfs_mount *,
+ struct chfs_eraseblock *);
+int chfs_reserve_space_normal(struct chfs_mount *, uint32_t, int);
+int chfs_reserve_space_gc(struct chfs_mount *, uint32_t);
+int chfs_reserve_space(struct chfs_mount *, uint32_t);
+void chfs_mark_node_obsolete(struct chfs_mount *, struct chfs_node_ref *);
+
+static inline struct chfs_vnode_cache *
+chfs_nref_to_vc(struct chfs_node_ref *nref)
+{
+ while (nref->nref_next) {
+ nref = nref->nref_next;
+ //dbg("lnr: %u, ofs: %u\n", nref->nref_lnr, nref->nref_offset);
+ //dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
+ //dbg("scan_dirents: %p\n", ((struct chfs_vnode_cache *)(nref))->scan_dirents);
+ if (nref->nref_lnr == REF_LINK_TO_NEXT) {
+ dbg("Link to next!\n");
+ } else if (nref->nref_lnr == REF_EMPTY_NODE) {
+ dbg("Empty!\n");
+ }
+ }
+ //dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
+
+ //dbg("NREF_TO_VC: GET IT\n");
+ //dbg("nref_next: %p, lnr: %u, ofs: %u\n", nref->nref_next, nref->nref_lnr, nref->nref_offset);
+ struct chfs_vnode_cache *vc = (struct chfs_vnode_cache *) nref;
+ dbg("vno: %ju, pvno: %ju, hv: %ju, nlink: %u\n", (intmax_t )vc->vno,
+ (intmax_t )vc->pvno, (intmax_t )vc->highest_version, vc->nlink);
+ //return ((struct chfs_vnode_cache *)nref);
+ return vc;
+}
+
+
+/* chfs_malloc.c */
+int chfs_alloc_pool_caches(void);
+void chfs_destroy_pool_caches(void);
+struct chfs_vnode_cache* chfs_vnode_cache_alloc(ino_t);
+void chfs_vnode_cache_free(struct chfs_vnode_cache *);
+struct chfs_node_ref* chfs_alloc_node_ref(
+ struct chfs_eraseblock *);
+void chfs_free_node_refs(struct chfs_eraseblock *);
+struct chfs_dirent* chfs_alloc_dirent(int);
+void chfs_free_dirent(struct chfs_dirent *);
+struct chfs_flash_vnode* chfs_alloc_flash_vnode(void);
+void chfs_free_flash_vnode(struct chfs_flash_vnode *);
+struct chfs_flash_dirent_node* chfs_alloc_flash_dirent(void);
+void chfs_free_flash_dirent(struct chfs_flash_dirent_node *);
+struct chfs_flash_data_node* chfs_alloc_flash_dnode(void);
+void chfs_free_flash_dnode(struct chfs_flash_data_node *);
+struct chfs_node_frag* chfs_alloc_node_frag(void);
+void chfs_free_node_frag(struct chfs_node_frag *);
+struct chfs_node_ref* chfs_alloc_refblock(void);
+void chfs_free_refblock(struct chfs_node_ref *);
+struct chfs_full_dnode* chfs_alloc_full_dnode(void);
+void chfs_free_full_dnode(struct chfs_full_dnode *);
+struct chfs_tmp_dnode * chfs_alloc_tmp_dnode(void);
+void chfs_free_tmp_dnode(struct chfs_tmp_dnode *);
+struct chfs_tmp_dnode_info * chfs_alloc_tmp_dnode_info(void);
+void chfs_free_tmp_dnode_info(struct chfs_tmp_dnode_info *);
+
+/* chfs_readinode.c */
+int chfs_read_inode(struct chfs_mount *, struct chfs_inode *);
+int chfs_read_inode_internal(struct chfs_mount *, struct chfs_inode *);
+void chfs_kill_fragtree(struct rb_tree *);
+uint32_t chfs_truncate_fragtree(struct chfs_mount *,
+ struct rb_tree *, uint32_t);
+int chfs_add_full_dnode_to_inode(struct chfs_mount *,
+ struct chfs_inode *,
+ struct chfs_full_dnode *);
+int chfs_read_data(struct chfs_mount*, struct vnode *,
+ struct buf *);
+
+/* chfs_erase.c */
+int chfs_remap_leb(struct chfs_mount *);
+
+/* chfs_ihash.c */
+void chfs_ihashinit(void);
+void chfs_ihashreinit(void);
+void chfs_ihashdone(void);
+struct vnode *chfs_ihashlookup(dev_t, ino_t);
+struct vnode *chfs_ihashget(dev_t, ino_t, int);
+void chfs_ihashins(struct chfs_inode *);
+void chfs_ihashrem(struct chfs_inode *);
+
+extern kmutex_t chfs_ihash_lock;
+extern kmutex_t chfs_hashlock;
+
+/* chfs_gc.c */
+void chfs_gc_trigger(struct chfs_mount *);
+int chfs_gc_thread_should_wake(struct chfs_mount *);
+void chfs_gc_thread(void *);
+void chfs_gc_thread_start(struct chfs_mount *);
+void chfs_gc_thread_stop(struct chfs_mount *);
+int chfs_gcollect_pass(struct chfs_mount *);
+
+/* chfs_vfsops.c*/
+int chfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+int chfs_mountfs(struct vnode *, struct mount *);
+
+/* chfs_vnops.c */
+extern int (**chfs_vnodeop_p)(void *);
+extern int (**chfs_specop_p)(void *);
+extern int (**chfs_fifoop_p)(void *);
+int chfs_lookup(void *);
+int chfs_create(void *);
+int chfs_mknod(void *);
+int chfs_open(void *);
+int chfs_close(void *);
+int chfs_access(void *);
+int chfs_getattr(void *);
+int chfs_setattr(void *);
+int chfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t);
+int chfs_chmod(struct vnode *, int, kauth_cred_t);
+int chfs_read(void *);
+int chfs_write(void *);
+int chfs_fsync(void *);
+int chfs_remove(void *);
+int chfs_link(void *);
+int chfs_rename(void *);
+int chfs_mkdir(void *);
+int chfs_rmdir(void *);
+int chfs_symlink(void *);
+int chfs_readdir(void *);
+int chfs_readlink(void *);
+int chfs_inactive(void *);
+int chfs_reclaim(void *);
+int chfs_advlock(void *);
+int chfs_strategy(void *);
+int chfs_bmap(void *);
+
+/* chfs_vnode.c */
+struct vnode *chfs_vnode_lookup(struct chfs_mount *, ino_t);
+int chfs_readvnode(struct mount *, ino_t, struct vnode **);
+int chfs_readdirent(struct mount *, struct chfs_node_ref *,
+ struct chfs_inode *);
+int chfs_makeinode(int, struct vnode *, struct vnode **,
+ struct componentname *, int );
+void chfs_set_vnode_size(struct vnode *, size_t);
+void chfs_change_size_free(struct chfs_mount *,
+ struct chfs_eraseblock *, int);
+void chfs_change_size_dirty(struct chfs_mount *,
+ struct chfs_eraseblock *, int);
+void chfs_change_size_unchecked(struct chfs_mount *,
+ struct chfs_eraseblock *, int);
+void chfs_change_size_used(struct chfs_mount *,
+ struct chfs_eraseblock *, int);
+void chfs_change_size_wasted(struct chfs_mount *,
+ struct chfs_eraseblock *, int);
+
+/* chfs_vnode_cache.c */
+struct chfs_vnode_cache **chfs_vnocache_hash_init(void);
+void chfs_vnocache_hash_destroy(struct chfs_vnode_cache **);
+void chfs_vnode_cache_set_state(struct chfs_mount *,
+ struct chfs_vnode_cache *, int);
+struct chfs_vnode_cache* chfs_vnode_cache_get(struct chfs_mount *, ino_t);
+void chfs_vnode_cache_add(struct chfs_mount *, struct chfs_vnode_cache *);
+void chfs_vnode_cache_remove(struct chfs_mount *, struct chfs_vnode_cache *);
+
+/* chfs_wbuf.c */
+int chfs_write_wbuf(struct chfs_mount*,
+ const struct iovec *, long, off_t, size_t *);
+int chfs_flush_pending_wbuf(struct chfs_mount *);
+
+/* chfs_write.c */
+int chfs_write_flash_vnode(struct chfs_mount *, struct chfs_inode *, int);
+int chfs_write_flash_dirent(struct chfs_mount *, struct chfs_inode *,
+ struct chfs_inode *, struct chfs_dirent *, ino_t, int);
+int chfs_write_flash_dnode(struct chfs_mount *, struct vnode *,
+ struct buf *, struct chfs_full_dnode *);
+int chfs_do_link(struct chfs_inode *,
+ struct chfs_inode *, const char *, int, enum vtype);
+int chfs_do_unlink(struct chfs_inode *,
+ struct chfs_inode *, const char *, int);
+
+/* chfs_subr.c */
+size_t chfs_mem_info(bool);
+struct chfs_dirent * chfs_dir_lookup(struct chfs_inode *,
+ struct componentname *);
+int chfs_filldir (struct uio *, ino_t, const char *, int, enum vtype);
+int chfs_chsize(struct vnode *, u_quad_t, kauth_cred_t);
+int chfs_chflags(struct vnode *, int, kauth_cred_t);
+void chfs_itimes(struct chfs_inode *, const struct timespec *,
+ const struct timespec *, const struct timespec *);
+int chfs_update(struct vnode *, const struct timespec *,
+ const struct timespec *, int);
+//int chfs_truncate(struct vnode *, off_t);
+
+/*---------------------------------------------------------------------------*/
+
+/* Some inline functions temporarily placed here */
+static inline int
+chfs_map_leb(struct chfs_mount *chmp, int lnr)
+{
+ int err;
+
+ err = ebh_map_leb(chmp->chm_ebh, lnr);
+ if (err)
+ chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
+
+ return err;
+
+}
+
+static inline int
+chfs_unmap_leb(struct chfs_mount *chmp, int lnr)
+{
+ int err;
+
+ err = ebh_unmap_leb(chmp->chm_ebh, lnr);
+ if (err)
+ chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
+
+ return err;
+}
+
+static inline int
+chfs_read_leb(struct chfs_mount *chmp, int lnr, char *buf,
+ int offset, int len, size_t *retlen)
+{
+ int err;
+
+ err = ebh_read_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
+ if (err)
+ chfs_err("read leb %d:%d failed, error: %d\n",
+ lnr, offset, err);
+
+ return err;
+}
+
+static inline int chfs_write_leb(struct chfs_mount *chmp, int lnr, char *buf,
+ int offset, int len, size_t *retlen)
+{
+ int err;
+ err = ebh_write_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
+ if (err)
+ chfs_err("write leb %d:%d failed, error: %d\n",
+ lnr, offset, err);
+
+ return err;
+}
+
+/******************************************************************************/
+/* Code from dummyfs.h */
+/******************************************************************************/
+/* --------------------------------------------------------------------- */
+
+#define CHFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
+
+static __inline size_t
+CHFS_PAGES_MAX(struct chfs_mount *chmp)
+{
+ size_t freepages;
+
+ freepages = chfs_mem_info(false);
+ if (freepages < CHFS_PAGES_RESERVED)
+ freepages = 0;
+ else
+ freepages -= CHFS_PAGES_RESERVED;
+
+ return MIN(chmp->chm_pages_max, freepages + chmp->chm_pages_used);
+}
+
+#define CHFS_ITIMES(ip, acc, mod, cre) \
+ while ((ip)->iflag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+ chfs_itimes(ip, acc, mod, cre)
+
+/* used for KASSERTs */
+#define IMPLIES(a, b) (!(a) || (b))
+#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
+
+#endif /* __CHFS_H__ */
--- /dev/null
+/* $NetBSD: chfs_args.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef _FS_CHFS_CHFS_ARGS_H_
+#define _FS_CHFS_CHFS_ARGS_H_
+
+#define CHFS_ARGS_VERSION 1
+
+/**
+ * struct chfs_args - arguments needed when mounting filesystem
+ * @fl_index: index of the flash device in the flash layer
+ */
+struct chfs_args {
+ //int ca_version;
+ char *fspec;
+ int fl_index;
+
+ /* Root node attributes. */
+ /*uid_t ca_root_uid;
+ gid_t ca_root_gid;
+ mode_t ca_root_mode;*/
+};
+
+#endif /* _FS_CHFS_CHFS_ARGS_H_ */
--- /dev/null
+/* $NetBSD: chfs_inode.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef __CHFS_INODE_H__
+#define __CHFS_INODE_H__
+
+#include <sys/vnode.h>
+#include <sys/stat.h>
+#include <ufs/ufs/ufsmount.h>
+#include <miscfs/genfs/genfs_node.h>
+
+struct chfs_inode
+{
+ kmutex_t inode_lock; /* lock the fields of chfs_inode */
+
+ LIST_ENTRY(chfs_inode) hash_entry; /* Hash chain. */
+
+ struct ufsmount *ump; /* ufs mount - TODO we should remove it */
+ struct chfs_mount *chmp; /* chfs mount point - TODO we should remove it */
+
+ struct vnode *vp; /* vnode associated with this inode */
+ ino_t ino; /* vnode identifier number */
+
+ struct vnode *devvp; /* vnode for block I/O */
+ dev_t dev; /* device associated with the inode */
+
+ struct chfs_vnode_cache *chvc; /* vnode cache of this node */
+
+ struct chfs_dirent *fd; /* full dirent of this node */
+// struct chfs_dirent *dents; /* directory entries */
+ struct chfs_dirent_list dents;
+
+ struct rb_tree fragtree; /* fragtree of inode */
+
+ uint64_t version; /* version number */
+ //uint64_t highest_version; /* highest vers. num. (used at data nodes) */
+
+ uint32_t mode; /* mode */
+ //int16_t nlink; /* link count */
+ uint64_t size; /* file byte count */
+ uint64_t write_size; /* increasing while write the file out to the flash */
+ uint32_t uid; /* file owner */
+ uint32_t gid; /* file group */
+ uint32_t atime; /* access time */
+ uint32_t mtime; /* modify time */
+ uint32_t ctime; /* creation time */
+
+ uint32_t iflag; /* flags, see below */
+ uint32_t flags; /* status flags (chflags) */
+
+ dev_t rdev; /* used if type is VCHR or VBLK or VFIFO*/
+ char *target; /* used if type is VLNK */
+};
+
+/* These flags are kept in chfs_inode->iflag. */
+#define IN_ACCESS 0x0001 /* Access time update request. */
+#define IN_CHANGE 0x0002 /* Inode change time update request. */
+#define IN_UPDATE 0x0004 /* Inode was written to; update mtime. */
+#define IN_MODIFY 0x2000 /* Modification time update request. */
+#define IN_MODIFIED 0x0008 /* Inode has been modified. */
+#define IN_ACCESSED 0x0010 /* Inode has been accessed. */
+#define IN_RENAME 0x0020 /* Inode is being renamed. */
+#define IN_SHLOCK 0x0040 /* File has shared lock. */
+#define IN_EXLOCK 0x0080 /* File has exclusive lock. */
+#define IN_CLEANING 0x0100 /* LFS: file is being cleaned */
+#define IN_ADIROP 0x0200 /* LFS: dirop in progress */
+#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */
+#define IN_PAGING 0x1000 /* LFS: file is on paging queue */
+
+
+#ifdef VTOI
+# undef VTOI
+#endif
+#ifdef ITOV
+# undef ITOV
+#endif
+
+#define VTOI(vp) ((struct chfs_inode *)(vp)->v_data)
+#define ITOV(ip) ((ip)->vp)
+
+/* copied from ufs_dinode.h */
+#define NDADDR 12 /* Direct addresses in inode. */
+
+#define ROOTINO ((ino_t)2)
+
+/* File permissions. */
+#define IEXEC 0000100 /* Executable. */
+#define IWRITE 0000200 /* Writable. */
+#define IREAD 0000400 /* Readable. */
+#define ISVTX 0001000 /* Sticky bit. */
+#define ISGID 0002000 /* Set-gid. */
+#define ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define IFMT 0170000 /* Mask of file type. */
+#define IFIFO 0010000 /* Named pipe (fifo). */
+#define IFCHR 0020000 /* Character device. */
+#define IFDIR 0040000 /* Directory file. */
+#define IFBLK 0060000 /* Block device. */
+#define IFREG 0100000 /* Regular file. */
+#define IFLNK 0120000 /* Symbolic link. */
+#define IFSOCK 0140000 /* UNIX domain socket. */
+#define IFWHT 0160000 /* Whiteout. */
+
+#endif /* __CHFS_INODE_H__ */
--- /dev/null
+/* $NetBSD: chfs_pool.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef _FS_CHFS_CHFS_POOL_H_
+#define _FS_CHFS_CHFS_POOL_H_
+
+
+/* --------------------------------------------------------------------- */
+
+struct chfs_pool {
+ struct pool chp_pool;
+ struct chfs_mount * chp_mount;
+ char chp_name[64];
+};
+
+/* --------------------------------------------------------------------- */
+
+struct chfs_str_pool {
+ struct chfs_pool chsp_pool_16;
+ struct chfs_pool chsp_pool_32;
+ struct chfs_pool chsp_pool_64;
+ struct chfs_pool chsp_pool_128;
+ struct chfs_pool chsp_pool_256;
+ struct chfs_pool chsp_pool_512;
+ struct chfs_pool chsp_pool_1024;
+};
+
+/* --------------------------------------------------------------------- */
+#ifdef _KERNEL
+
+/*
+ * Convenience functions and macros to manipulate a chfs_pool.
+ */
+
+void chfs_pool_init(struct chfs_pool *chpp, size_t size,
+ const char *what, struct chfs_mount *chmp);
+void chfs_pool_destroy(struct chfs_pool *chpp);
+
+#define CHFS_POOL_GET(chpp, flags) pool_get((struct pool *)(chpp), flags)
+#define CHFS_POOL_PUT(chpp, v) pool_put((struct pool *)(chpp), v)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Functions to manipulate a chfs_str_pool.
+ */
+
+void chfs_str_pool_init(struct chfs_str_pool *, struct chfs_mount *);
+void chfs_str_pool_destroy(struct chfs_str_pool *);
+char * chfs_str_pool_get(struct chfs_str_pool *, size_t, int);
+void chfs_str_pool_put(struct chfs_str_pool *, char *, size_t);
+
+#endif
+
+#endif /* _FS_CHFS_CHFS_POOL_H_ */
--- /dev/null
+/* $NetBSD: debug.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+/*
+ * XipFFS -- Xip Flash File System
+ *
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * ...
+ * University of Szeged, Hungary
+ *
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#ifndef __CHFS_DEBUG_H__
+#define __CHFS_DEBUG_H__
+
+#define CHFS_ERROR_PREFIX "[CHFS ERROR]"
+#define CHFS_WARNING_PREFIX "[CHFS WARNING]"
+#define CHFS_NOTICE_PREFIX "[CHFS NOTICE]"
+#define CHFS_DBG_PREFIX "[CHFS DBG]"
+#define CHFS_DBG2_PREFIX "[CHFS DBG2]"
+#define CHFS_DBG_EBH_PREFIX "[CHFS DBG EBH]"
+#define CHFS_DBG_GC_PREFIX "[CHFS_GC DBG]"
+
+#define unlikely(x) __builtin_expect ((x), 0)
+
+
+
+#define debug_msg(pref, fmt, ...) \
+ do { \
+ printf(pref \
+ " %s: " fmt, __FUNCTION__ , ##__VA_ARGS__); \
+ } while(0)
+
+#define chfs_assert(expr) do { \
+ if (unlikely(!(expr))) { \
+ printf("CHFS assert failed in %s at %u\n", \
+ __func__, __LINE__); \
+ /*dump_stack();*/ \
+ } \
+} while (0)
+
+#ifdef DBG_MSG
+ #define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
+ #define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
+ #define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
+ #define dbg(fmt, ...) debug_msg(CHFS_DBG_PREFIX, fmt, ##__VA_ARGS__)
+ #define dbg2(fmt, ...) debug_msg(CHFS_DBG2_PREFIX(fmt, ##__VA_ARGS__)
+ #define dbg_ebh(fmt, ...) debug_msg(CHFS_DBG_EBH_PREFIX, fmt, ##__VA_ARGS__)
+#else
+ #define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
+ #define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
+ #define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
+ #define dbg(fmt, ...)
+ #define dbg2(fmt, ...)
+ #define dbg_ebh(fmt, ...)
+#endif
+
+#ifdef DBG_MSG_GC
+ #define dbg_gc(fmt, ...) debug_msg(CHFS_DBG_GC_PREFIX, fmt, ##__VA_ARGS__)
+#else
+ #define dbg_gc(fmt, ...)
+#endif
+
+#endif /* __CHFS_DEBUG_H__ */
--- /dev/null
+/* $NetBSD: ebh.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+/*
+ * ebh.h
+ *
+ * Created on: 2009.11.03.
+ * Author: dtengeri
+ */
+
+#ifndef EBH_H_
+#define EBH_H_
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/cdefs.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/kmem.h>
+#include <sys/endian.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+#include <sys/kthread.h>
+
+#include <dev/flash/flash.h>
+#include <ufs/chfs/ebh_media.h>
+#include <ufs/chfs/debug.h>
+#include <ufs/chfs/ebh_misc.h>
+
+/* Maximum retries when getting new PEB before exit with failure */
+#define CHFS_MAX_GET_PEB_RETRIES 2
+
+/**
+ * LEB status
+ *
+ */
+enum {
+ EBH_LEB_UNMAPPED = -1,
+ EBH_LEB_MAPPED,
+ EBH_LEB_DIRTY,
+ EBH_LEB_INVALID,
+ EBH_LEB_ERASE,
+ EBH_LEB_ERASED,
+ EBH_LEB_FREE,
+};
+
+/**
+ * EB header status
+ */
+enum {
+ EBHDR_LEB_OK = 0,
+ EBHDR_LEB_DIRTY,
+ EBHDR_LEB_INVALIDATED,
+ EBHDR_LEB_BADMAGIC,
+ EBHDR_LEB_BADCRC,
+ EBHDR_LEB_FREE,
+ EBHDR_LEB_NO_HDR,
+};
+
+struct chfs_ebh;
+
+/**
+ * struct chfs_ltree_entry - an netry in the lock tree
+ * @rb: RB-node of the tree
+ * @lnr: logical eraseblock number
+ * @users: counts the tasks that are using or want to use the eraseblock
+ * @mutex: read/write mutex to lock the eraseblock
+ */
+struct chfs_ltree_entry {
+ RB_ENTRY(chfs_ltree_entry) rb;
+ int lnr;
+ int users;
+ krwlock_t mutex;
+};
+
+/* Generate structure for Lock tree's red-black tree */
+RB_HEAD(ltree_rbtree, chfs_ltree_entry);
+
+
+/**
+ * struct chfs_scan_leb - scanning infomration about a physical eraseblock
+ * @erase_cnt: erase counter
+ * @pebnr: physical eraseblock number
+ * @info: the status of the PEB's eraseblock header when NOR serial when NAND
+ * @u.list: link in one of the eraseblock list
+ * @u.rb: link in the used RB-tree of chfs_scan_info
+ */
+struct chfs_scan_leb {
+ int erase_cnt;
+ int pebnr;
+ int lnr;
+ uint64_t info;
+ union {
+ TAILQ_ENTRY(chfs_scan_leb) queue;
+ RB_ENTRY(chfs_scan_leb) rb;
+ } u;
+};
+
+TAILQ_HEAD(scan_leb_queue, chfs_scan_leb);
+RB_HEAD(scan_leb_used_rbtree, chfs_scan_leb);
+
+
+
+/**
+ * struct chfs_scan_info - chfs scanning information
+ * @corrupted: queue of corrupted physical eraseblocks
+ * @free: queue of free physical eraseblocks
+ * @erase: queue of the physical eraseblocks signed to erase
+ * @erased: queue of physical eraseblocks that contain no header
+ * @used: RB-tree of used PEBs describing by chfs_scan_leb
+ * @sum_of_ec: summary of erase counters
+ * @num_of_eb: number of free and used eraseblocks
+ * @bad_peb_cnt: counter of bad eraseblocks
+ *
+ * This structure contains information about the scanning for further
+ * processing.
+ */
+struct chfs_scan_info {
+ struct scan_leb_queue corrupted;
+ struct scan_leb_queue free;
+ struct scan_leb_queue erase;
+ struct scan_leb_queue erased;
+ struct scan_leb_used_rbtree used;
+ uint64_t sum_of_ec;
+ int num_of_eb;
+ int bad_peb_cnt;
+};
+
+/**
+ * struct chfs_peb - PEB information for erasing and wear leveling
+ * @erase_cnt: erase counter of the physical eraseblock
+ * @pebnr: physical eraseblock number
+ * @u.queue: link to the queue of the PEBs waiting for erase
+ * @u.rb: link to the RB-tree to the free PEBs
+ */
+struct chfs_peb {
+ int erase_cnt;
+ int pebnr;
+ union {
+ TAILQ_ENTRY(chfs_peb) queue;
+ RB_ENTRY(chfs_peb) rb;
+ } u;
+};
+
+/* Generate queue and rb-tree structures. */
+TAILQ_HEAD(peb_queue, chfs_peb);
+RB_HEAD(peb_free_rbtree, chfs_peb);
+RB_HEAD(peb_in_use_rbtree, chfs_peb);
+
+/**
+ * struct chfs_eb_hdr - in-memory representation of eraseblock headers
+ * @ec_hdr: erase counter header ob eraseblock
+ * @u.nor_hdr: eraseblock header on NOR flash
+ * @u.nand_hdr: eraseblock header on NAND flash
+ */
+struct chfs_eb_hdr {
+ struct chfs_eb_ec_hdr ec_hdr;
+ union {
+ struct chfs_nor_eb_hdr nor_hdr;
+ struct chfs_nand_eb_hdr nand_hdr;
+ } u;
+};
+
+/*
+ * struct chfs_ebh_ops - collection of operations which
+ * depends on flash type
+ * *************************************************************************** *
+ * Direct flash operations:
+ *
+ * @read_eb_hdr: read eraseblock header from media
+ * @write_eb_hdr: write eraseblock header to media
+ * @check_eb_hdr: validates eraseblock header
+ * @mark_eb_hdr_dirty_flash: marks eraseblock dirty on flash
+ * @invalidate_eb_hdr: invalidates eraseblock header
+ * @mark_eb_hdr_free: marks eraseblock header free (after erase)
+ * *************************************************************************** *
+ * Scanning operations:
+ *
+ * @process_eb: process an eraseblock information at scan
+ * *************************************************************************** *
+ * Misc operations:
+ *
+ * @create_eb_hdr: creates an eraseblock header based on flash type
+ * @calc_data_offs: calculates where the data starts
+ */
+struct chfs_ebh_ops {
+ int (*read_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
+ struct chfs_eb_hdr *ebhdr);
+ int (*write_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
+ struct chfs_eb_hdr *ebhdr);
+ int (*check_eb_hdr)(struct chfs_ebh *ebh, void *buf);
+ int (*mark_eb_hdr_dirty_flash)(struct chfs_ebh *ebh, int pebnr, int lid);
+ int (*invalidate_eb_hdr)(struct chfs_ebh *ebh, int pebnr);
+ int (*mark_eb_hdr_free)(struct chfs_ebh *ebh, int pebnr, int ec);
+
+ int (*process_eb)(struct chfs_ebh *ebh, struct chfs_scan_info *si,
+ int pebnr, struct chfs_eb_hdr *ebhdr);
+
+ int (*create_eb_hdr)(struct chfs_eb_hdr *ebhdr, int lnr);
+ int (*calc_data_offs)(struct chfs_ebh *ebh, int pebnr, int offset);
+};
+
+/**
+ * struct erase_thread - background thread for erasing
+ * @thread: pointer to thread structure
+ * @wakeup: conditional variable for sleeping if there isn't any job to do
+ * @running: flag to signal a thread shutdown
+ */
+struct erase_thread {
+ lwp_t *eth_thread;
+ kcondvar_t eth_wakeup;
+ bool eth_running;
+};
+
+
+/**
+ * struct chfs_ebh - eraseblock handler descriptor
+ * @mtd: mtd device descriptor
+ * @eb_size: eraseblock size
+ * @peb_nr: number of PEBs
+ * @lmap: LEB to PEB mapping
+ * @layout_map: the LEBs layout (NOT USED YET)
+ * @ltree: the lock tree
+ * @ltree_lock: protects the tree
+ * @alc_mutex: serializes "atomic LEB change" operation
+ * @free: RB-tree of the free easeblocks
+ * @in_use: RB-tree of PEBs are in use
+ * @to_erase: list of the PEBs waiting for erase
+ * @fully_erased: list of PEBs that have been erased but don't have header
+ * @erase_lock: list and tree lock for fully_erased and to_erase lists and
+ * for the free RB-tree
+ * @bg_erase: background thread for eraseing PEBs.
+ * @ops: collection of operations which depends on flash type
+ * @max_serial: max serial number of eraseblocks, only used on NAND
+ */
+struct chfs_ebh {
+ struct peb_free_rbtree free;
+ struct peb_in_use_rbtree in_use;
+ struct peb_queue to_erase;
+ struct peb_queue fully_erased;
+ struct erase_thread bg_erase;
+ device_t flash_dev;
+ const struct flash_interface *flash_if;
+ struct chfs_ebh_ops *ops;
+ uint64_t *max_serial;
+ int *lmap;
+ //int *layout_map;
+ struct ltree_rbtree ltree;
+ //struct mutex alc_mutex;
+ kmutex_t ltree_lock;
+ kmutex_t alc_mutex;
+ kmutex_t erase_lock;
+ size_t eb_size;
+ size_t peb_nr;
+ flash_size_t flash_size;
+};
+
+/**
+ * struct chfs_erase_info_priv - private information for erase
+ * @ebh: eraseblock handler
+ * @peb: physical eraseblock information
+ */
+struct chfs_erase_info_priv {
+ struct chfs_ebh *ebh;
+ struct chfs_peb *peb;
+};
+
+/* ebh.c */
+
+int ebh_open(struct chfs_ebh *ebh, dev_t dev);
+int ebh_close(struct chfs_ebh *ebh);
+int ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+ uint32_t offset, size_t len, size_t *retlen);
+int ebh_write_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+ uint32_t offset, size_t len, size_t *retlen);
+int ebh_erase_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_map_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_unmap_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_is_mapped(struct chfs_ebh *ebh, int lnr);
+int ebh_change_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+ size_t len, size_t *retlen);
+
+
+#endif /* EBH_H_ */
--- /dev/null
+/* $NetBSD: ebh_media.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef EBH_MEDIA_H_
+#define EBH_MEDIA_H_
+
+#ifndef _LE_TYPES
+#define _LE_TYPES
+typedef uint16_t le16;
+typedef uint32_t le32;
+typedef uint64_t le64;
+#endif
+
+/*****************************************************************************/
+/* EBH specific structures */
+/*****************************************************************************/
+#define CHFS_MAGIC_BITMASK 0x53454452
+
+#define CHFS_LID_NOT_DIRTY_BIT 0x80000000
+#define CHFS_LID_DIRTY_BIT_MASK 0x7fffffff
+
+/* sizeof(crc) + sizeof(lid) */
+#define CHFS_INVALIDATE_SIZE 8
+
+/* Size of magic + crc_ec + erase_cnt */
+#define CHFS_EB_EC_HDR_SIZE sizeof(struct chfs_eb_ec_hdr)
+/* Size of NOR eraseblock header */
+#define CHFS_EB_HDR_NOR_SIZE sizeof(struct chfs_nor_eb_hdr)
+/* Size of NAND eraseblock header */
+#define CHFS_EB_HDR_NAND_SIZE sizeof(struct chfs_nand_eb_hdr)
+
+/*
+ * chfs_eb_ec_hdr - erase counter header of eraseblock
+ * @magic: filesystem magic
+ * @crc_ec: CRC32 sum of erase counter
+ * @erase_cnt: erase counter
+ *
+ * This structure holds the erasablock description information.
+ * This will be written to the beginning of the eraseblock.
+ *
+ */
+struct chfs_eb_ec_hdr {
+ le32 magic;
+ le32 crc_ec;
+ le32 erase_cnt;
+} __packed;
+
+/**
+ * struct chfs_nor_eb_hdr - eraseblock header on NOR flash
+ * @crc: CRC32 sum
+ * @lid: logical identifier
+ *
+ * @lid contains the logical block reference but only the first 31 bit (0-30) is
+ * used. The 32th bit is for marking a lid dirty (marked for recovery purposes).
+ * If a new eraseblock is succesfully assigned with the same lid then the lid of
+ * the old one is zeroed. If power failure happened during this operation then
+ * the recovery detects that there is two eraseblock with the same lid, but one
+ * of them is marked (the old one).
+ *
+ * Invalidated eraseblock header means that the @crc and @lid is set to 0.
+ */
+struct chfs_nor_eb_hdr {
+ le32 crc;
+ le32 lid;
+} __packed;
+
+/**
+ * struct chfs_nand_eb_hdr - eraseblock header on NAND flash
+ * @crc: CRC32 sum
+ * @lid: logical identifier
+ * @serial: layout of the lid
+ *
+ * @serial is an unique number. Every eraseblock header on NAND flash has its
+ * own serial. If there are two eraseblock on the flash referencing to the same
+ * logical eraseblock, the one with bigger serial is the newer.
+ */
+struct chfs_nand_eb_hdr {
+ le32 crc;
+ le32 lid;
+ le64 serial;
+} __packed;
+
+#endif /* EBH_MEDIA_H_ */
--- /dev/null
+/* $NetBSD: ebh_misc.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef EBH_MISC_H_
+#define EBH_MISC_H_
+
+/******************************************************************************/
+/* EBH specific functions */
+/******************************************************************************/
+
+#define CHFS_GET_MEMBER_POS(type, member) \
+ ((unsigned long)(&((type *)0)->member))
+
+#define CHFS_GET_LID(lid) (le32toh(lid) & CHFS_LID_DIRTY_BIT_MASK)
+
+/**
+ * EBH_TREE_DESTROY - destroys an RB-tree and frees the memory of its elements.
+ * @name - the RB-tree structure's name
+ * @head - pointer to the RB-tree's head
+ * @type - type of the elements
+ */
+#define EBH_TREE_DESTROY(name, head, type) \
+ { \
+ type *var, *nxt; \
+ for (var = RB_MIN(name, head); var != NULL; var = nxt) { \
+ nxt = RB_NEXT(name, head, var); \
+ RB_REMOVE(name, head, var); \
+ kmem_free(var, sizeof(type)); \
+ } \
+ }
+
+/* XXX HACK! we need a clean solution for destroying mutexes in trees */
+#define EBH_TREE_DESTROY_MUTEX(name, head, type) \
+ { \
+ type *var, *nxt; \
+ for (var = RB_MIN(name, head); var != NULL; var = nxt) { \
+ nxt = RB_NEXT(name, head, var); \
+ RB_REMOVE(name, head, var); \
+ rw_destroy(&var->mutex); \
+ kmem_free(var, sizeof(type)); \
+ } \
+ }
+
+/**
+ * EBH_QUEUE_DESTROY - destroys a TAILQ and frees the memory of its elements.
+ * @head: pointer to the head of the queue
+ * @type: type of the elements
+ * @entry: name of TAILQ_ENTRY
+ */
+#define EBH_QUEUE_DESTROY(head, type, entry) \
+ { \
+ type *var; \
+ while ((var = TAILQ_FIRST(head))) { \
+ TAILQ_REMOVE(head, var, entry); \
+ kmem_free(var, sizeof(type)); \
+ } \
+ }
+
+#endif /* EBH_MISC_H_ */
--- /dev/null
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ * University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ */
+
+#ifndef __CHFS_MEDIA_H__
+#define __CHFS_MEDIA_H__
+
+#ifndef _LE_TYPES
+#define _LE_TYPES
+typedef uint16_t le16;
+typedef uint32_t le32;
+typedef uint64_t le64;
+#endif
+
+/*****************************************************************************/
+/* File system specific structures */
+/*****************************************************************************/
+
+enum {
+ CHFS_NODETYPE_VNODE = 1,
+ CHFS_NODETYPE_DATA,
+ CHFS_NODETYPE_DIRENT,
+ CHFS_NODETYPE_PADDING,
+};
+
+//#define CHFS_NODE_HDR_SIZE 12 /* magic + type + length + hdr_crc */
+#define CHFS_NODE_HDR_SIZE sizeof(struct chfs_flash_node_hdr)
+
+/* Max size we have to read to get all info.
+ * It is max size of chfs_flash_dirent_node with max name length.
+ */
+#define CHFS_MAX_NODE_SIZE 299
+
+/* This will identify CHfs nodes */
+#define CHFS_FS_MAGIC_BITMASK 0x4AF1
+
+/**
+ * struct chfs_flash_node_hdr - node header, its members are same for
+ * all nodes, used at scan
+ * @magic: filesystem magic
+ * @type: node type
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ */
+struct chfs_flash_node_hdr
+{
+ le16 magic;
+ le16 type;
+ le32 length;
+ le32 hdr_crc;
+} __packed;
+
+/**
+ * struct chfs_flash_vnode - vnode informations stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_VNODE)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @version: vnode's version number
+ * @uid: owner of the file
+ * @gid: group of file
+ * @mode: permissions for vnode
+ * @dn_size: size of written out data nodes
+ * @atime: last access times
+ * @mtime: last modification time
+ * @ctime: change time
+ * @dsize: size of the node's data
+ * @node_crc: crc of full node
+ */
+struct chfs_flash_vnode
+{
+ le16 magic; /*0 */
+ le16 type; /*2 */
+ le32 length; /*4 */
+ le32 hdr_crc; /*8 */
+ le64 vno; /*12*/
+ le64 version; /*20*/
+ le32 uid; /*28*/
+ le32 gid; /*32*/
+ le32 mode; /*36*/
+ le32 dn_size; /*40*/
+ le32 atime; /*44*/
+ le32 mtime; /*48*/
+ le32 ctime; /*52*/
+ le32 dsize; /*56*/
+ le32 node_crc; /*60*/
+} __packed;
+
+/**
+ * struct chfs_flash_data_node - node informations of data stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_DATA)
+ * @length: length of node with data
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @version: vnode's version number
+ * @offset: offset in the file where write begins
+ * @data_length: length of data
+ * @data_crc: crc of data
+ * @node_crc: crc of full node
+ * @data: array of data
+ */
+struct chfs_flash_data_node
+{
+ le16 magic;
+ le16 type;
+ le32 length;
+ le32 hdr_crc;
+ le64 vno;
+ le64 version;
+ le64 offset;
+ le32 data_length;
+ le32 data_crc;
+ le32 node_crc;
+ uint8_t data[0];
+} __packed;
+
+/**
+ * struct chfs_flash_dirent_node - vnode informations stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_DIRENT)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @pvno: vnode identifier id of parent vnode
+ * @version: vnode's version number
+ * @mctime:
+ * @nsize: length of name
+ * @dtype: file type
+ * @unused: just for padding
+ * @name_crc: crc of name
+ * @node_crc: crc of full node
+ * @name: name of the directory entry
+ */
+struct chfs_flash_dirent_node
+{
+ le16 magic;
+ le16 type;
+ le32 length;
+ le32 hdr_crc;
+ le64 vno;
+ le64 pvno;
+ le64 version;
+ le32 mctime;
+ uint8_t nsize;
+ uint8_t dtype;
+ uint8_t unused[2];
+ le32 name_crc;
+ le32 node_crc;
+ uint8_t name[0];
+} __packed;
+
+/**
+ * struct chfs_flash_padding_node - node informations of data stored on
+ * flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_PADDING)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ */
+struct chfs_flash_padding_node
+{
+ le16 magic;
+ le16 type;
+ le32 length;
+ le32 hdr_crc;
+} __packed;
+
+#endif /* __CHFS_MEDIA_H__ */
--- /dev/null
+/* $NetBSD: ext2fs.h,v 1.29 2009/11/27 11:16:54 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ * @(#)fs.h 8.10 (Berkeley) 10/27/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ *
+ * @(#)fs.h 8.10 (Berkeley) 10/27/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_H_
+#define _UFS_EXT2FS_EXT2FS_H_
+
+#include <sys/bswap.h>
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups. The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss. This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * The first boot and super blocks are given in absolute disk addresses.
+ * The byte-offset forms are preferred, as they don't imply a sector size.
+ */
+#define BBSIZE 1024
+#define SBSIZE 1024
+#define BBOFF ((off_t)(0))
+#define SBOFF ((off_t)(BBOFF + BBSIZE))
+#define BBLOCK ((daddr_t)(0))
+#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
+
+/*
+ * Addresses stored in inodes are capable of addressing blocks
+ * XXX
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define LOG_MINBSIZE 10
+#define MINBSIZE (1 << LOG_MINBSIZE)
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define MAXMNTLEN 512
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define MINFREE 5
+
+/*
+ * Super block for an ext2fs file system.
+ */
+struct ext2fs {
+ uint32_t e2fs_icount; /* Inode count */
+ uint32_t e2fs_bcount; /* blocks count */
+ uint32_t e2fs_rbcount; /* reserved blocks count */
+ uint32_t e2fs_fbcount; /* free blocks count */
+ uint32_t e2fs_ficount; /* free inodes count */
+ uint32_t e2fs_first_dblock; /* first data block */
+ uint32_t e2fs_log_bsize; /* block size = 1024*(2^e2fs_log_bsize) */
+ uint32_t e2fs_fsize; /* fragment size */
+ uint32_t e2fs_bpg; /* blocks per group */
+ uint32_t e2fs_fpg; /* frags per group */
+ uint32_t e2fs_ipg; /* inodes per group */
+ uint32_t e2fs_mtime; /* mount time */
+ uint32_t e2fs_wtime; /* write time */
+ uint16_t e2fs_mnt_count; /* mount count */
+ uint16_t e2fs_max_mnt_count; /* max mount count */
+ uint16_t e2fs_magic; /* magic number */
+ uint16_t e2fs_state; /* file system state */
+ uint16_t e2fs_beh; /* behavior on errors */
+ uint16_t e2fs_minrev; /* minor revision level */
+ uint32_t e2fs_lastfsck; /* time of last fsck */
+ uint32_t e2fs_fsckintv; /* max time between fscks */
+ uint32_t e2fs_creator; /* creator OS */
+ uint32_t e2fs_rev; /* revision level */
+ uint16_t e2fs_ruid; /* default uid for reserved blocks */
+ uint16_t e2fs_rgid; /* default gid for reserved blocks */
+ /* EXT2_DYNAMIC_REV superblocks */
+ uint32_t e2fs_first_ino; /* first non-reserved inode */
+ uint16_t e2fs_inode_size; /* size of inode structure */
+ uint16_t e2fs_block_group_nr; /* block grp number of this sblk*/
+ uint32_t e2fs_features_compat; /* compatible feature set */
+ uint32_t e2fs_features_incompat; /* incompatible feature set */
+ uint32_t e2fs_features_rocompat; /* RO-compatible feature set */
+ uint8_t e2fs_uuid[16]; /* 128-bit uuid for volume */
+ char e2fs_vname[16]; /* volume name */
+ char e2fs_fsmnt[64]; /* name mounted on */
+ uint32_t e2fs_algo; /* For compression */
+ uint8_t e2fs_prealloc; /* # of blocks to preallocate */
+ uint8_t e2fs_dir_prealloc; /* # of blocks to preallocate for dir */
+ uint16_t e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
+ uint32_t reserved2[204];
+};
+
+
+/* in-memory data for ext2fs */
+struct m_ext2fs {
+ struct ext2fs e2fs;
+ u_char e2fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+ int8_t e2fs_ronly; /* mounted read-only flag */
+ int8_t e2fs_fmod; /* super block modified flag */
+ int32_t e2fs_bsize; /* block size */
+ int32_t e2fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int32_t e2fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int64_t e2fs_qbmask; /* ~fs_bmask - for use with quad size */
+ int32_t e2fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int32_t e2fs_ncg; /* number of cylinder groups */
+ int32_t e2fs_ngdb; /* number of group descriptor block */
+ int32_t e2fs_ipb; /* number of inodes per block */
+ int32_t e2fs_itpg; /* number of inode table per group */
+ struct ext2_gd *e2fs_gd; /* group descripors */
+};
+
+
+
+/*
+ * Filesystem identification
+ */
+#define E2FS_MAGIC 0xef53 /* the ext2fs magic number */
+#define E2FS_REV0 0 /* GOOD_OLD revision */
+#define E2FS_REV1 1 /* Support compat/incompat features */
+
+/* compatible/incompatible features */
+#define EXT2F_COMPAT_PREALLOC 0x0001
+#define EXT2F_COMPAT_HASJOURNAL 0x0004
+#define EXT2F_COMPAT_RESIZE 0x0010
+
+#define EXT2F_ROCOMPAT_SPARSESUPER 0x0001
+#define EXT2F_ROCOMPAT_LARGEFILE 0x0002
+#define EXT2F_ROCOMPAT_BTREE_DIR 0x0004
+
+#define EXT2F_INCOMPAT_COMP 0x0001
+#define EXT2F_INCOMPAT_FTYPE 0x0002
+
+/*
+ * Features supported in this implementation
+ *
+ * We support the following REV1 features:
+ * - EXT2F_ROCOMPAT_SPARSESUPER
+ * superblock backups stored only in cg_has_sb(bno) groups
+ * - EXT2F_ROCOMPAT_LARGEFILE
+ * use e2di_dacl in struct ext2fs_dinode to store
+ * upper 32bit of size for >2GB files
+ * - EXT2F_INCOMPAT_FTYPE
+ * store file type to e2d_type in struct ext2fs_direct
+ * (on REV0 e2d_namlen is uint16_t and no e2d_type, like ffs)
+ */
+#define EXT2F_COMPAT_SUPP 0x0000
+#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \
+ | EXT2F_ROCOMPAT_LARGEFILE)
+#define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE
+
+/*
+ * Definitions of behavior on errors
+ */
+#define E2FS_BEH_CONTINUE 1 /* continue operation */
+#define E2FS_BEH_READONLY 2 /* remount fs read only */
+#define E2FS_BEH_PANIC 3 /* cause panic */
+#define E2FS_BEH_DEFAULT E2FS_BEH_CONTINUE
+
+/*
+ * OS identification
+ */
+#define E2FS_OS_LINUX 0
+#define E2FS_OS_HURD 1
+#define E2FS_OS_MASIX 2
+#define E2FS_OS_FREEBSD 3
+#define E2FS_OS_LITES 4
+
+/*
+ * Filesystem clean flags
+ */
+#define E2FS_ISCLEAN 0x01
+#define E2FS_ERRORS 0x02
+
+/* ext2 file system block group descriptor */
+
+struct ext2_gd {
+ uint32_t ext2bgd_b_bitmap; /* blocks bitmap block */
+ uint32_t ext2bgd_i_bitmap; /* inodes bitmap block */
+ uint32_t ext2bgd_i_tables; /* inodes table block */
+ uint16_t ext2bgd_nbfree; /* number of free blocks */
+ uint16_t ext2bgd_nifree; /* number of free inodes */
+ uint16_t ext2bgd_ndirs; /* number of directories */
+ uint16_t reserved;
+ uint32_t reserved2[3];
+};
+
+
+/*
+ * If the EXT2F_ROCOMPAT_SPARSESUPER flag is set, the cylinder group has a
+ * copy of the super and cylinder group descriptors blocks only if it's
+ * 1, a power of 3, 5 or 7
+ */
+
+static __inline int cg_has_sb(int) __unused;
+static __inline int
+cg_has_sb(int i)
+{
+ int a3, a5, a7;
+
+ if (i == 0 || i == 1)
+ return 1;
+ for (a3 = 3, a5 = 5, a7 = 7;
+ a3 <= i || a5 <= i || a7 <= i;
+ a3 *= 3, a5 *= 5, a7 *= 7)
+ if (i == a3 || i == a5 || i == a7)
+ return 1;
+ return 0;
+}
+
+/* EXT2FS metadatas are stored in little-endian byte order. These macros
+ * helps reading theses metadatas
+ */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define h2fs16(x) (x)
+# define h2fs32(x) (x)
+# define h2fs64(x) (x)
+# define fs2h16(x) (x)
+# define fs2h32(x) (x)
+# define fs2h64(x) (x)
+# define e2fs_sbload(old, new) memcpy((new), (old), SBSIZE);
+# define e2fs_cgload(old, new, size) memcpy((new), (old), (size));
+# define e2fs_sbsave(old, new) memcpy((new), (old), SBSIZE);
+# define e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
+#else
+void e2fs_sb_bswap(struct ext2fs *, struct ext2fs *);
+void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
+# define h2fs16(x) bswap16(x)
+# define h2fs32(x) bswap32(x)
+# define h2fs64(x) bswap64(x)
+# define fs2h16(x) bswap16(x)
+# define fs2h32(x) bswap32(x)
+# define fs2h64(x) bswap64(x)
+# define e2fs_sbload(old, new) e2fs_sb_bswap((old), (new))
+# define e2fs_cgload(old, new, size) e2fs_cg_bswap((old), (new), (size));
+# define e2fs_sbsave(old, new) e2fs_sb_bswap((old), (new))
+# define e2fs_cgsave(old, new, size) e2fs_cg_bswap((old), (new), (size));
+#endif
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->e2fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->e2fs_fsbtodb)
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to file system block offset.
+ * inode number to cylinder group number.
+ * inode number to file system block address.
+ */
+#define ino_to_cg(fs, x) (((x) - 1) / (fs)->e2fs.e2fs_ipg)
+#define ino_to_fsba(fs, x) \
+ ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables + \
+ (((x) - 1) % (fs)->e2fs.e2fs_ipg) / (fs)->e2fs_ipb)
+#define ino_to_fsbo(fs, x) (((x) - 1) % (fs)->e2fs_ipb)
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define dtog(fs, d) (((d) - (fs)->e2fs.e2fs_first_dblock) / (fs)->e2fs.e2fs_fpg)
+#define dtogd(fs, d) \
+ (((d) - (fs)->e2fs.e2fs_first_dblock) % (fs)->e2fs.e2fs_fpg)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->e2fs_bsize) */ \
+ ((loc) & (fs)->e2fs_qbmask)
+#define lblktosize(fs, blk) /* calculates (blk * fs->e2fs_bsize) */ \
+ ((blk) << (fs)->e2fs_bshift)
+#define lblkno(fs, loc) /* calculates (loc / fs->e2fs_bsize) */ \
+ ((loc) >> (fs)->e2fs_bshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
+ (((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
+#define fragroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
+ (((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define freespace(fs) \
+ ((fs)->e2fs.e2fs_fbcount - (fs)->e2fs.e2fs_rbcount)
+
+/*
+ * Number of indirects in a file system block.
+ */
+#define NINDIR(fs) ((fs)->e2fs_bsize / sizeof(uint32_t))
+
+#endif /* !_UFS_EXT2FS_EXT2FS_H_ */
--- /dev/null
+/* $NetBSD: ext2fs_dinode.h,v 1.22 2009/11/27 11:16:54 tsutsui 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.
+ *
+ * @(#)dinode.h 8.6 (Berkeley) 9/13/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ *
+ * @(#)dinode.h 8.6 (Berkeley) 9/13/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_DINODE_H_
+#define _UFS_EXT2FS_EXT2FS_DINODE_H_
+
+#include <sys/stat.h>
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ * Inode 3 to 10 are reserved in ext2fs.
+ */
+#define EXT2_BADBLKINO ((ino_t)1)
+#define EXT2_ROOTINO ((ino_t)2)
+#define EXT2_ACLIDXINO ((ino_t)3)
+#define EXT2_ACLDATAINO ((ino_t)4)
+#define EXT2_BOOTLOADERINO ((ino_t)5)
+#define EXT2_UNDELDIRINO ((ino_t)6)
+#define EXT2_RESIZEINO ((ino_t)7)
+#define EXT2_JOURNALINO ((ino_t)8)
+#define EXT2_FIRSTINO ((ino_t)11)
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NDADDR 12 /* Direct addresses in inode. */
+#define NIADDR 3 /* Indirect addresses in inode. */
+
+#define EXT2_MAXSYMLINKLEN ((NDADDR+NIADDR) * sizeof (uint32_t))
+
+struct ext2fs_dinode {
+ uint16_t e2di_mode; /* 0: IFMT, permissions; see below. */
+ uint16_t e2di_uid; /* 2: Owner UID */
+ uint32_t e2di_size; /* 4: Size (in bytes) */
+ uint32_t e2di_atime; /* 8: Acces time */
+ uint32_t e2di_ctime; /* 12: Create time */
+ uint32_t e2di_mtime; /* 16: Modification time */
+ uint32_t e2di_dtime; /* 20: Deletion time */
+ uint16_t e2di_gid; /* 24: Owner GID */
+ uint16_t e2di_nlink; /* 26: File link count */
+ uint32_t e2di_nblock; /* 28: Blocks count */
+ uint32_t e2di_flags; /* 32: Status flags (chflags) */
+ uint32_t e2di_linux_reserved1; /* 36 */
+ uint32_t e2di_blocks[NDADDR+NIADDR]; /* 40: disk blocks */
+ uint32_t e2di_gen; /* 100: generation number */
+ uint32_t e2di_facl; /* 104: file ACL (not implemented) */
+ uint32_t e2di_dacl; /* 108: dir ACL (not implemented) */
+ uint32_t e2di_faddr; /* 112: fragment address */
+ uint8_t e2di_nfrag; /* 116: fragment number */
+ uint8_t e2di_fsize; /* 117: fragment size */
+ uint16_t e2di_linux_reserved2; /* 118 */
+ uint16_t e2di_uid_high; /* 120: Owner UID top 16 bits */
+ uint16_t e2di_gid_high; /* 122: Owner GID top 16 bits */
+ uint32_t e2di_linux_reserved3; /* 124 */
+};
+
+
+
+#define E2MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(uint32_t))
+
+/* File permissions. */
+#define EXT2_IEXEC 0000100 /* Executable. */
+#define EXT2_IWRITE 0000200 /* Writable. */
+#define EXT2_IREAD 0000400 /* Readable. */
+#define EXT2_ISVTX 0001000 /* Sticky bit. */
+#define EXT2_ISGID 0002000 /* Set-gid. */
+#define EXT2_ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define EXT2_IFMT 0170000 /* Mask of file type. */
+#define EXT2_IFIFO 0010000 /* Named pipe (fifo). */
+#define EXT2_IFCHR 0020000 /* Character device. */
+#define EXT2_IFDIR 0040000 /* Directory file. */
+#define EXT2_IFBLK 0060000 /* Block device. */
+#define EXT2_IFREG 0100000 /* Regular file. */
+#define EXT2_IFLNK 0120000 /* Symbolic link. */
+#define EXT2_IFSOCK 0140000 /* UNIX domain socket. */
+
+/* file flags */
+#define EXT2_SECRM 0x00000001 /* Secure deletion */
+#define EXT2_UNRM 0x00000002 /* Undelete */
+#define EXT2_COMPR 0x00000004 /* Compress file */
+#define EXT2_SYNC 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE 0x00000010 /* Immutable file */
+#define EXT2_APPEND 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP 0x00000040 /* do not dump file */
+
+/* Size of on-disk inode. */
+#define EXT2_REV0_DINODE_SIZE sizeof(struct ext2fs_dinode)
+#define EXT2_DINODE_SIZE(fs) ((fs)->e2fs.e2fs_rev > E2FS_REV0 ? \
+ (fs)->e2fs.e2fs_inode_size : \
+ EXT2_REV0_DINODE_SIZE)
+
+/*
+ * The e2di_blocks fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+
+#define e2di_rdev e2di_blocks[0]
+#define e2di_shortlink e2di_blocks
+
+/* e2fs needs byte swapping on big-endian systems */
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define e2fs_iload(old, new) \
+ memcpy((new),(old),sizeof(struct ext2fs_dinode))
+# define e2fs_isave(old, new) \
+ memcpy((new),(old),sizeof(struct ext2fs_dinode))
+#else
+void e2fs_i_bswap(struct ext2fs_dinode *, struct ext2fs_dinode *);
+# define e2fs_iload(old, new) e2fs_i_bswap((old), (new))
+# define e2fs_isave(old, new) e2fs_i_bswap((old), (new))
+#endif
+
+#endif /* !_UFS_EXT2FS_EXT2FS_DINODE_H_ */
--- /dev/null
+/* $NetBSD: ext2fs_dir.h,v 1.18 2009/10/19 18:41:17 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ * @(#)dir.h 8.4 (Berkeley) 8/10/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ *
+ * @(#)dir.h 8.4 (Berkeley) 8/10/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_DIR_H_
+#define _UFS_EXT2FS_EXT2FS_DIR_H_
+
+/*
+ * Theoretically, directories can be more than 2Gb in length, however, in
+ * practice this seems unlikely. So, we define the type doff_t as a 32-bit
+ * quantity to keep down the cost of doing lookup on a 32-bit machine.
+ */
+#define doff_t int32_t
+#define EXT2FS_MAXDIRSIZE INT32_MAX
+
+/*
+ * A directory consists of some number of blocks of e2fs_bsize bytes.
+ *
+ * Each block contains some number of directory entry
+ * structures, which are of variable length. Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry. These are followed by the name padded to a 4 byte boundary
+ * with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is EXT2FS_MAXNAMLEN.
+ *
+ * The macro EXT2FS_DIRSIZ(fmt, dp) gives the amount of space required to
+ * represent a directory entry. Free space in a directory is represented by
+ * entries which have dp->e2d_reclen > DIRSIZ(fmt, dp). All d2fs_bsize bytes
+ * in a directory block are claimed by the directory entries. This
+ * usually results in the last entry in a directory having a large
+ * dp->e2d_reclen. When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->e2d_reclen. If the first entry of
+ * a directory block is free, then its dp->e2d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->e2d_ino set to 0.
+ * Ext2 rev 0 has a 16 bits e2d_namlen. For Ext2 vev 1 this has been split
+ * into a 8 bits e2d_namlen and 8 bits e2d_type (looks like ffs, isnt't it ? :)
+ * It's safe to use this for rev 0 as well because all ext2 are little-endian.
+ */
+
+#define EXT2FS_MAXNAMLEN 255
+
+struct ext2fs_direct {
+ uint32_t e2d_ino; /* inode number of entry */
+ uint16_t e2d_reclen; /* length of this record */
+ uint8_t e2d_namlen; /* length of string in d_name */
+ uint8_t e2d_type; /* file type */
+ char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
+};
+
+/* Ext2 directory file types (not the same as FFS. Sigh.) */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+#define E2IFTODT(mode) (((mode) & 0170000) >> 12)
+
+static __inline uint8_t inot2ext2dt(uint16_t) __unused;
+static __inline uint8_t
+inot2ext2dt(uint16_t type)
+{
+
+ switch (type) {
+ case E2IFTODT(EXT2_IFIFO):
+ return EXT2_FT_FIFO;
+ case E2IFTODT(EXT2_IFCHR):
+ return EXT2_FT_CHRDEV;
+ case E2IFTODT(EXT2_IFDIR):
+ return EXT2_FT_DIR;
+ case E2IFTODT(EXT2_IFBLK):
+ return EXT2_FT_BLKDEV;
+ case E2IFTODT(EXT2_IFREG):
+ return EXT2_FT_REG_FILE;
+ case E2IFTODT(EXT2_IFLNK):
+ return EXT2_FT_SYMLINK;
+ case E2IFTODT(EXT2_IFSOCK):
+ return EXT2_FT_SOCK;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * The EXT2FS_DIRSIZ macro gives the minimum record length which will hold
+ * the directory entryfor a name len "len" (without the terminating null byte).
+ * This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name without a
+ * terminating null byte, rounded up to a 4 byte boundary.
+ */
+#define EXT2FS_DIRSIZ(len) roundup2(8 + len, 4)
+
+/*
+ * Template for manipulating directories. Should use struct direct's,
+ * but the name field is EXT2FS_MAXNAMLEN - 1, and this just won't do.
+ */
+struct ext2fs_dirtemplate {
+ uint32_t dot_ino;
+ int16_t dot_reclen;
+ uint8_t dot_namlen;
+ uint8_t dot_type;
+ char dot_name[4]; /* must be multiple of 4 */
+ uint32_t dotdot_ino;
+ int16_t dotdot_reclen;
+ uint8_t dotdot_namlen;
+ uint8_t dotdot_type;
+ char dotdot_name[4]; /* ditto */
+};
+
+#endif /* !_UFS_EXT2FS_EXT2FS_DIR_H_ */
--- /dev/null
+/* $NetBSD: ext2fs_extern.h,v 1.43 2011/07/12 16:59:48 dholland 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.3 (Berkeley) 4/16/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*-
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ *
+ * @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_EXTERN_H_
+#define _UFS_EXT2FS_EXT2FS_EXTERN_H_
+
+struct buf;
+struct fid;
+struct m_ext2fs;
+struct inode;
+struct mount;
+struct nameidata;
+struct lwp;
+struct proc;
+struct statvfs;
+struct timeval;
+struct ufsmount;
+struct uio;
+struct vnode;
+struct mbuf;
+struct componentname;
+
+extern struct pool ext2fs_inode_pool; /* memory pool for inodes */
+extern struct pool ext2fs_dinode_pool; /* memory pool for dinodes */
+
+#define EXT2FS_ITIMES(ip, acc, mod, cre) \
+ while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+ ext2fs_itimes(ip, acc, mod, cre)
+
+__BEGIN_DECLS
+
+/* ext2fs_alloc.c */
+int ext2fs_alloc(struct inode *, daddr_t, daddr_t , kauth_cred_t,
+ daddr_t *);
+int ext2fs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
+ kauth_cred_t, struct buf **);
+int ext2fs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+/* XXX ondisk32 */
+daddr_t ext2fs_blkpref(struct inode *, daddr_t, int, int32_t *);
+void ext2fs_blkfree(struct inode *, daddr_t);
+int ext2fs_vfree(struct vnode *, ino_t, int);
+
+/* ext2fs_balloc.c */
+int ext2fs_balloc(struct inode *, daddr_t, int, kauth_cred_t,
+ struct buf **, int);
+int ext2fs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+
+/* ext2fs_bmap.c */
+int ext2fs_bmap(void *);
+
+/* ext2fs_inode.c */
+u_int64_t ext2fs_size(struct inode *);
+int ext2fs_setsize(struct inode *, u_int64_t);
+int ext2fs_update(struct vnode *, const struct timespec *,
+ const struct timespec *, int);
+int ext2fs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+int ext2fs_inactive(void *);
+
+/* ext2fs_lookup.c */
+int ext2fs_readdir(void *);
+int ext2fs_lookup(void *);
+int ext2fs_direnter(struct inode *, struct vnode *,
+ const struct ufs_lookup_results *,
+ struct componentname *);
+int ext2fs_dirremove(struct vnode *, const struct ufs_lookup_results *,
+ struct componentname *);
+int ext2fs_dirrewrite(struct inode *, const struct ufs_lookup_results *,
+ struct inode *, struct componentname *);
+int ext2fs_dirempty(struct inode *, ino_t, kauth_cred_t);
+int ext2fs_checkpath(struct inode *, struct inode *, kauth_cred_t);
+
+/* ext2fs_subr.c */
+int ext2fs_blkatoff(struct vnode *, off_t, char **, struct buf **);
+void ext2fs_fragacct(struct m_ext2fs *, int, int32_t[], int);
+void ext2fs_itimes(struct inode *, const struct timespec *,
+ const struct timespec *, const struct timespec *);
+
+/* ext2fs_vfsops.c */
+VFS_PROTOS(ext2fs);
+int ext2fs_reload(struct mount *, kauth_cred_t, struct lwp *);
+int ext2fs_mountfs(struct vnode *, struct mount *);
+int ext2fs_flushfiles(struct mount *, int);
+int ext2fs_sbupdate(struct ufsmount *, int);
+int ext2fs_cgupdate(struct ufsmount *, int);
+void ext2fs_set_inode_guid(struct inode *);
+
+/* ext2fs_readwrite.c */
+int ext2fs_read(void *);
+int ext2fs_write(void *);
+
+/* ext2fs_vnops.c */
+int ext2fs_create(void *);
+int ext2fs_mknod(void *);
+int ext2fs_open(void *);
+int ext2fs_access(void *);
+int ext2fs_getattr(void *);
+int ext2fs_setattr(void *);
+int ext2fs_remove(void *);
+int ext2fs_link(void *);
+int ext2fs_rename(void *);
+int ext2fs_mkdir(void *);
+int ext2fs_rmdir(void *);
+int ext2fs_symlink(void *);
+int ext2fs_readlink(void *);
+int ext2fs_advlock(void *);
+int ext2fs_fsync(void *);
+int ext2fs_vinit(struct mount *, int (**specops)(void *),
+ int (**fifoops)(void *), struct vnode **);
+int ext2fs_makeinode(int, struct vnode *, struct vnode **,
+ struct componentname *cnp);
+int ext2fs_reclaim(void *);
+
+__END_DECLS
+
+#define IS_EXT2_VNODE(vp) (vp->v_tag == VT_EXT2FS)
+
+extern int (**ext2fs_vnodeop_p)(void *);
+extern int (**ext2fs_specop_p)(void *);
+extern int (**ext2fs_fifoop_p)(void *);
+
+#endif /* !_UFS_EXT2FS_EXT2FS_EXTERN_H_ */
--- /dev/null
+/* $NetBSD: ffs_extern.h,v 1.78 2011/06/17 14:23:52 manu 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
+ */
+
+#ifndef _UFS_FFS_FFS_EXTERN_H_
+#define _UFS_FFS_FFS_EXTERN_H_
+
+/*
+ * Sysctl values for the fast filesystem.
+ */
+#define FFS_CLUSTERREAD 1 /* cluster reading enabled */
+#define FFS_CLUSTERWRITE 2 /* cluster writing enabled */
+#define FFS_REALLOCBLKS 3 /* block reallocation enabled */
+#define FFS_ASYNCFREE 4 /* asynchronous block freeing enabled */
+#define FFS_LOG_CHANGEOPT 5 /* log optimalization strategy change */
+#define FFS_EXTATTR_AUTOCREATE 6 /* size for backing file autocreation */
+#define FFS_MAXID 7 /* number of valid ffs ids */
+
+struct buf;
+struct fid;
+struct fs;
+struct inode;
+struct ufs1_dinode;
+struct ufs2_dinode;
+struct mount;
+struct nameidata;
+struct lwp;
+struct statvfs;
+struct timeval;
+struct timespec;
+struct ufsmount;
+struct uio;
+struct vnode;
+struct mbuf;
+struct cg;
+
+#if defined(_KERNEL)
+
+#include <sys/pool.h>
+
+#define FFS_NOBLK ((daddr_t)-1)
+
+#define FFS_ITIMES(ip, acc, mod, cre) \
+ while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+ ffs_itimes(ip, acc, mod, cre)
+
+extern pool_cache_t ffs_inode_cache; /* memory pool for inodes */
+extern pool_cache_t ffs_dinode1_cache; /* memory pool for UFS1 dinodes */
+extern pool_cache_t ffs_dinode2_cache; /* memory pool for UFS2 dinodes */
+
+#endif /* defined(_KERNEL) */
+
+__BEGIN_DECLS
+
+#if defined(_KERNEL)
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/wapbl.h>
+
+/* ffs_alloc.c */
+int ffs_alloc(struct inode *, daddr_t, daddr_t , int, int, kauth_cred_t,
+ daddr_t *);
+int ffs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
+ kauth_cred_t, struct buf **, daddr_t *);
+int ffs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int, int32_t *);
+daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int, int64_t *);
+int ffs_blkalloc(struct inode *, daddr_t, long);
+int ffs_blkalloc_ump(struct ufsmount *, daddr_t, long);
+void ffs_blkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
+void ffs_blkfree_snap(struct fs *, struct vnode *, daddr_t, long, ino_t);
+int ffs_vfree(struct vnode *, ino_t, int);
+int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
+int ffs_freefile(struct mount *, ino_t, int);
+int ffs_freefile_snap(struct fs *, struct vnode *, ino_t, int);
+
+/* ffs_balloc.c */
+int ffs_balloc(struct vnode *, off_t, int, kauth_cred_t, int,
+ struct buf **);
+
+/* ffs_inode.c */
+int ffs_update(struct vnode *, const struct timespec *,
+ const struct timespec *, int);
+int ffs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+
+/* ffs_vfsops.c */
+VFS_PROTOS(ffs);
+
+int ffs_reload(struct mount *, kauth_cred_t, struct lwp *);
+int ffs_mountfs(struct vnode *, struct mount *, struct lwp *);
+int ffs_flushfiles(struct mount *, int, struct lwp *);
+int ffs_sbupdate(struct ufsmount *, int);
+int ffs_cgupdate(struct ufsmount *, int);
+
+/* ffs_vnops.c */
+int ffs_read(void *);
+int ffs_write(void *);
+int ffs_fsync(void *);
+int ffs_spec_fsync(void *);
+int ffs_reclaim(void *);
+int ffs_getpages(void *);
+void ffs_gop_size(struct vnode *, off_t, off_t *, int);
+int ffs_openextattr(void *);
+int ffs_closeextattr(void *);
+int ffs_getextattr(void *);
+int ffs_setextattr(void *);
+int ffs_listextattr(void *);
+int ffs_deleteextattr(void *);
+int ffs_lock(void *);
+int ffs_unlock(void *);
+int ffs_islocked(void *);
+int ffs_full_fsync(struct vnode *, int);
+
+/*
+ * Snapshot function prototypes.
+ */
+int ffs_snapshot_init(struct ufsmount *);
+void ffs_snapshot_fini(struct ufsmount *);
+int ffs_snapblkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
+void ffs_snapremove(struct vnode *);
+int ffs_snapshot(struct mount *, struct vnode *, struct timespec *);
+void ffs_snapshot_mount(struct mount *);
+void ffs_snapshot_unmount(struct mount *);
+void ffs_snapgone(struct inode *);
+int ffs_snapshot_read(struct vnode *, struct uio *, int);
+
+/* Write Ahead Physical Block Logging */
+void ffs_wapbl_verify_inodes(struct mount *, const char *);
+void ffs_wapbl_replay_finish(struct mount *);
+int ffs_wapbl_start(struct mount *);
+int ffs_wapbl_stop(struct mount *, int);
+int ffs_wapbl_replay_start(struct mount *, struct fs *, struct vnode *);
+void ffs_wapbl_blkalloc(struct fs *, struct vnode *, daddr_t, int);
+
+void ffs_wapbl_sync_metadata(struct mount *, daddr_t *, int *, int);
+void ffs_wapbl_abort_sync_metadata(struct mount *, daddr_t *, int *, int);
+
+extern int (**ffs_vnodeop_p)(void *);
+extern int (**ffs_specop_p)(void *);
+extern int (**ffs_fifoop_p)(void *);
+
+#endif /* defined(_KERNEL) */
+
+/* ffs_appleufs.c */
+struct appleufslabel;
+u_int16_t ffs_appleufs_cksum(const struct appleufslabel *);
+int ffs_appleufs_validate(const char*, const struct appleufslabel *,
+ struct appleufslabel *);
+void ffs_appleufs_set(struct appleufslabel *, const char *, time_t,
+ uint64_t);
+
+/* 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 *);
+struct csum;
+void ffs_csum_swap(struct csum *, struct csum *, int);
+struct csum_total;
+void ffs_csumtotal_swap(struct csum_total *, struct csum_total *);
+void ffs_cg_swap(struct cg *, struct cg *, struct fs *);
+
+/* ffs_subr.c */
+#if defined(_KERNEL)
+void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
+int ffs_getblk(struct vnode *, daddr_t, daddr_t, int, bool, buf_t **);
+#endif /* defined(_KERNEL) */
+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);
+void ffs_itimes(struct inode *, const struct timespec *,
+ const struct timespec *, const struct timespec *);
+void ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
+
+/* ffs_quota2.c */
+int ffs_quota2_mount(struct mount *);
+
+__END_DECLS
+
+#endif /* !_UFS_FFS_FFS_EXTERN_H_ */
--- /dev/null
+/* $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ * @(#)fs.h 8.13 (Berkeley) 3/21/95
+ */
+
+/*
+ * NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
+ */
+
+#ifndef _UFS_FFS_FS_H_
+#define _UFS_FFS_FS_H_
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups. The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss. This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For file system fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ * [fs->fs_sblkno] Super-block
+ * [fs->fs_cblkno] Cylinder group block
+ * [fs->fs_iblkno] Inode blocks
+ * [fs->fs_dblkno] Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * Depending on the architecture and the media, the superblock may
+ * reside in any one of four places. For tiny media where every block
+ * counts, it is placed at the very front of the partition. Historically,
+ * UFS1 placed it 8K from the front to leave room for the disk label and
+ * a small bootstrap. For UFS2 it got moved to 64K from the front to leave
+ * room for the disk label and a bigger bootstrap, and for really piggy
+ * systems we check at 256K from the front if the first three fail. In
+ * all cases the size of the superblock will be SBLOCKSIZE. All values are
+ * given in byte-offset form, so they do not imply a sector size. The
+ * SBLOCKSEARCH specifies the order in which the locations should be searched.
+ *
+ * Unfortunately the UFS2/FFSv2 change was done without adequate consideration
+ * of backward compatibility. In particular 'newfs' for a FFSv2 partition
+ * must overwrite any old FFSv1 superblock at 8k, and preferrably as many
+ * of the alternates as it can find - otherwise attempting to mount on a
+ * system that only supports FFSv1 is likely to succeed!.
+ * For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
+ * the disk, and a system that tries to find an FFSv2 filesystem in preference
+ * to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
+ * As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
+ * with 64k blocks is at 64k - just where the code looks first when playing
+ * 'hunt the superblock'.
+ *
+ * The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
+ * can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
+ * This is the default superblock type for NetBSD since ffsv2 support was added.
+ */
+#define BBSIZE 8192
+#define BBOFF ((off_t)(0))
+#define BBLOCK ((daddr_t)(0))
+
+#define SBLOCK_FLOPPY 0
+#define SBLOCK_UFS1 8192
+#define SBLOCK_UFS2 65536
+#define SBLOCK_PIGGY 262144
+#define SBLOCKSIZE 8192
+/*
+ * NB: Do not, under any circumstances, look for an ffsv1 filesystem at
+ * SBLOCK_UFS2. Doing so will find the wrong superblock for filesystems
+ * with a 64k block size.
+ */
+#define SBLOCKSEARCH \
+ { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
+
+/*
+ * Max number of fragments per block. This value is NOT tweakable.
+ */
+#define MAXFRAG 8
+
+
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressable; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks. To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary. The file system format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided. The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The file system records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define MINBSIZE 4096
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define MAXMNTLEN 468
+
+/*
+ * The volume name for this filesystem is maintained in fs_volname.
+ * MAXVOLLEN defines the length of the buffer allocated.
+ * This space used to be part of of fs_fsmnt.
+ */
+#define MAXVOLLEN 32
+
+/*
+ * There is a 128-byte region in the superblock reserved for in-core
+ * pointers to summary information. Originally this included an array
+ * of pointers to blocks of struct csum; now there are just four
+ * pointers and the remaining space is padded with fs_ocsp[].
+ * NOCSPTRS determines the size of this padding. One pointer (fs_csp)
+ * is taken away to point to a contiguous array of struct csum for
+ * all cylinder groups; a second (fs_maxcluster) points to an array
+ * of cluster sizes that is computed as cylinder groups are inspected;
+ * the third (fs_contigdirs) points to an array that tracks the
+ * creation of new directories; and the fourth (fs_active) is used
+ * by snapshots.
+ */
+#define NOCSPTRS ((128 / sizeof(void *)) - 4)
+
+/*
+ * A summary of contiguous blocks of various sizes is maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig. To conserve space, a maximum summary size
+ * is set by FS_MAXCONTIG.
+ */
+#define FS_MAXCONTIG 16
+
+/*
+ * The maximum number of snapshot nodes that can be associated
+ * with each filesystem. This limit affects only the number of
+ * snapshot files that can be recorded within the superblock so
+ * that they can be found when the filesystem is mounted. However,
+ * maintaining too many will slow the filesystem performance, so
+ * having this limit is a good idea.
+ */
+#define FSMAXSNAP 20
+
+/*
+ * Used to identify special blocks in snapshots:
+ *
+ * BLK_NOCOPY - A block that was unallocated at the time the snapshot
+ * was taken, hence does not need to be copied when written.
+ * BLK_SNAP - A block held by another snapshot that is not needed by this
+ * snapshot. When the other snapshot is freed, the BLK_SNAP entries
+ * are converted to BLK_NOCOPY. These are needed to allow fsck to
+ * identify blocks that are in use by other snapshots (which are
+ * expunged from this snapshot).
+ */
+#define BLK_NOCOPY ((daddr_t)(1))
+#define BLK_SNAP ((daddr_t)(2))
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. This value is used only
+ * when creating a file system and can be overriden from the
+ * command line. By default we choose to optimize for time.
+ */
+#define MINFREE 5
+#define DEFAULTOPT FS_OPTTIME
+
+/*
+ * Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
+ * tune the layout preferences for directories within a filesystem.
+ * His algorithm can be tuned by adjusting the following parameters
+ * which tell the system the average file size and the average number
+ * of files per directory. These defaults are well selected for typical
+ * filesystems, but may need to be tuned for odd cases like filesystems
+ * being used for squid caches or news spools.
+ */
+#define AVFILESIZ 16384 /* expected average file size */
+#define AFPDIR 64 /* expected number of files per directory */
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ */
+struct csum {
+ int32_t cs_ndir; /* number of directories */
+ int32_t cs_nbfree; /* number of free blocks */
+ int32_t cs_nifree; /* number of free inodes */
+ int32_t cs_nffree; /* number of free frags */
+};
+
+struct csum_total {
+ int64_t cs_ndir; /* number of directories */
+ int64_t cs_nbfree; /* number of free blocks */
+ int64_t cs_nifree; /* number of free inodes */
+ int64_t cs_nffree; /* number of free frags */
+ int64_t cs_spare[4]; /* future expansion */
+};
+
+
+/*
+ * Super block for an FFS file system in memory.
+ */
+struct fs {
+ int32_t fs_firstfield; /* historic file system linked list, */
+ int32_t fs_unused_1; /* used for incore super blocks */
+ int32_t fs_sblkno; /* addr of super-block in filesys */
+ int32_t fs_cblkno; /* offset of cyl-block in filesys */
+ int32_t fs_iblkno; /* offset of inode-blocks in filesys */
+ int32_t fs_dblkno; /* offset of first data after cg */
+ int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
+ int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
+ int32_t fs_old_time; /* last time written */
+ int32_t fs_old_size; /* number of blocks in fs */
+ int32_t fs_old_dsize; /* number of data blocks in fs */
+ int32_t fs_ncg; /* number of cylinder groups */
+ int32_t fs_bsize; /* size of basic blocks in fs */
+ int32_t fs_fsize; /* size of frag blocks in fs */
+ int32_t fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ int32_t fs_minfree; /* minimum percentage of free blocks */
+ int32_t fs_old_rotdelay; /* num of ms for optimal next block */
+ int32_t fs_old_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
+ int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int32_t fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ int32_t fs_maxcontig; /* max number of contiguous blks */
+ int32_t fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ int32_t fs_fragshift; /* block to frag shift */
+ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int32_t fs_sbsize; /* actual size of super block */
+ int32_t fs_spare1[2]; /* old fs_csmask */
+ /* old fs_csshift */
+ int32_t fs_nindir; /* value of NINDIR */
+ int32_t fs_inopb; /* value of INOPB */
+ int32_t fs_old_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ int32_t fs_optim; /* optimization preference, see below */
+/* these fields are derived from the hardware */
+ int32_t fs_old_npsect; /* # sectors/track including spares */
+ int32_t fs_old_interleave; /* hardware sector interleave */
+ int32_t fs_old_trackskew; /* sector 0 skew, per track */
+/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
+ int32_t fs_id[2]; /* unique file system id */
+/* sizes determined by number of cylinder groups and their sizes */
+ int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
+ int32_t fs_cssize; /* size of cyl grp summary area */
+ int32_t fs_cgsize; /* cylinder group size */
+/* these fields are derived from the hardware */
+ int32_t fs_spare2; /* old fs_ntrak */
+ int32_t fs_old_nsect; /* sectors per track */
+ int32_t fs_old_spc; /* sectors per cylinder */
+ int32_t fs_old_ncyl; /* cylinders in file system */
+ int32_t fs_old_cpg; /* cylinders per group */
+ int32_t fs_ipg; /* inodes per group */
+ int32_t fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct csum fs_old_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ int8_t fs_fmod; /* super block modified flag */
+ uint8_t fs_clean; /* file system is clean flag */
+ int8_t fs_ronly; /* mounted read-only flag */
+ uint8_t fs_old_flags; /* see FS_ flags below */
+ u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+ u_char fs_volname[MAXVOLLEN]; /* volume name */
+ uint64_t fs_swuid; /* system-wide uid */
+ int32_t fs_pad;
+/* these fields retain the current block allocation info */
+ int32_t fs_cgrotor; /* last cg searched (UNUSED) */
+ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
+ u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
+ struct csum *fs_csp; /* cg summary info buffer for fs_cs */
+ int32_t *fs_maxcluster; /* max cluster in each cyl group */
+ u_char *fs_active; /* used by snapshots to track fs */
+ int32_t fs_old_cpc; /* cyl per cycle in postbl */
+/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
+ int32_t fs_maxbsize; /* maximum blocking factor permitted */
+ uint8_t fs_journal_version; /* journal format version */
+ uint8_t fs_journal_location; /* journal location type */
+ uint8_t fs_journal_reserved[2];/* reserved for future use */
+ uint32_t fs_journal_flags; /* journal flags */
+ uint64_t fs_journallocs[4]; /* location info for journal */
+ uint32_t fs_quota_magic; /* see quota2.h */
+ uint8_t fs_quota_flags; /* see quota2.h */
+ uint8_t fs_quota_reserved[3];
+ uint64_t fs_quotafile[2]; /* pointer to quota inodes */
+ int64_t fs_sparecon64[9]; /* reserved for future use */
+ int64_t fs_sblockloc; /* byte offset of standard superblock */
+ struct csum_total fs_cstotal; /* cylinder summary information */
+ int64_t fs_time; /* last time written */
+ int64_t fs_size; /* number of blocks in fs */
+ int64_t fs_dsize; /* number of data blocks in fs */
+ int64_t fs_csaddr; /* blk addr of cyl grp summary area */
+ int64_t fs_pendingblocks; /* blocks in process of being freed */
+ int32_t fs_pendinginodes; /* inodes in process of being freed */
+ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
+/* back to stuff that has been around a while */
+ int32_t fs_avgfilesize; /* expected average file size */
+ int32_t fs_avgfpdir; /* expected # of files per directory */
+ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
+ int32_t fs_sparecon32[26]; /* reserved for future constants */
+ uint32_t fs_flags; /* see FS_ flags below */
+/* back to stuff that has been around a while (again) */
+ int32_t fs_contigsumsize; /* size of cluster summary array */
+ int32_t fs_maxsymlinklen; /* max length of an internal symlink */
+ int32_t fs_old_inodefmt; /* format of on-disk inodes */
+ u_int64_t fs_maxfilesize; /* maximum representable file size */
+ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
+ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
+ int32_t fs_state; /* validate fs_clean field (UNUSED) */
+ int32_t fs_old_postblformat; /* format of positional layout tables */
+ int32_t fs_old_nrpos; /* number of rotational positions */
+ int32_t fs_spare5[2]; /* old fs_postbloff */
+ /* old fs_rotbloff */
+ int32_t fs_magic; /* magic number */
+};
+
+#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 */
+
+#define old_fs_postbl(fs_, cylno, opostblsave) \
+ ((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
+ ((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
+ ? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
+ : ((int16_t *)((uint8_t *)(fs_) + \
+ (fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
+#define old_fs_rotbl(fs) \
+ (((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
+ ? ((uint8_t *)(&(fs)->fs_magic+1)) \
+ : ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
+
+/*
+ * File system identification
+ */
+#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast file system magic number */
+#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast file system magic number */
+#define FS_UFS1_MAGIC_SWAPPED 0x54190100
+#define FS_UFS2_MAGIC_SWAPPED 0x19015419
+#define FS_OKAY 0x7c269d38 /* superblock checksum */
+#define FS_42INODEFMT -1 /* 4.2BSD inode format */
+#define FS_44INODEFMT 2 /* 4.4BSD inode format */
+
+/*
+ * File system clean flags
+ */
+#define FS_ISCLEAN 0x01
+#define FS_WASCLEAN 0x02
+
+/*
+ * Preference for optimization.
+ */
+#define FS_OPTTIME 0 /* minimize allocation time */
+#define FS_OPTSPACE 1 /* minimize disk fragmentation */
+
+/*
+ * File system flags
+ */
+#define FS_UNCLEAN 0x001 /* file system not clean at mount (unused) */
+#define FS_DOSOFTDEP 0x002 /* file system using soft dependencies */
+#define FS_NEEDSFSCK 0x004 /* needs sync fsck (FreeBSD compat, unused) */
+#define FS_INDEXDIRS 0x008 /* kernel supports indexed directories */
+#define FS_ACLS 0x010 /* file system has ACLs enabled */
+#define FS_MULTILABEL 0x020 /* file system is MAC multi-label */
+#define FS_GJOURNAL 0x40 /* gjournaled file system */
+#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
+#define FS_DOWAPBL 0x100 /* Write ahead physical block logging */
+#define FS_DOQUOTA2 0x200 /* in-filesystem quotas */
+
+/* File system flags that are ok for NetBSD if set in fs_flags */
+#define FS_KNOWN_FLAGS (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
+
+/*
+ * File system internal flags, also in fs_flags.
+ * (Pick highest number to avoid conflicts with others)
+ */
+#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
+#define FS_INTERNAL 0x80000000 /* mask for internal flags */
+
+/*
+ * Macros to access bits in the fs_active array.
+ */
+#define ACTIVECG_SET(fs, cg) \
+ do { \
+ if ((fs)->fs_active != NULL) \
+ setbit((fs)->fs_active, (cg)); \
+ } while (/*CONSTCOND*/ 0)
+#define ACTIVECG_CLR(fs, cg) \
+ do { \
+ if ((fs)->fs_active != NULL) \
+ clrbit((fs)->fs_active, (cg)); \
+ } while (/*CONSTCOND*/ 0)
+#define ACTIVECG_ISSET(fs, cg) \
+ ((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
+
+/*
+ * The size of a cylinder group is calculated by CGSIZE. The maximum size
+ * is limited by the fact that cylinder groups are at most one block.
+ * Its size is derived from the size of the maps maintained in the
+ * cylinder group and the (struct cg) size.
+ */
+#define CGSIZE_IF(fs, ipg, fpg) \
+ /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
+ /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
+ /* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \
+ /* inode map */ howmany((ipg), NBBY) + \
+ /* block map */ howmany((fpg), NBBY) +\
+ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
+ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
+ /* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
+
+#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
+
+/*
+ * The minimal number of cylinder groups that should be created.
+ */
+#define MINCYLGRPS 4
+
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define fs_cs(fs, indx) fs_csp[indx]
+
+/*
+ * Cylinder group block for a file system.
+ */
+#define CG_MAGIC 0x090255
+struct cg {
+ int32_t cg_firstfield; /* historic cyl groups linked list */
+ int32_t cg_magic; /* magic number */
+ int32_t cg_old_time; /* time last written */
+ int32_t cg_cgx; /* we are the cgx'th cylinder group */
+ int16_t cg_old_ncyl; /* number of cyl's this cg */
+ int16_t cg_old_niblk; /* number of inode blocks this cg */
+ int32_t cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int32_t cg_rotor; /* position of last used block */
+ int32_t cg_frotor; /* position of last used frag */
+ int32_t cg_irotor; /* position of last used inode */
+ int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
+ int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
+ int32_t cg_old_boff; /* (u_int16) free block positions */
+ int32_t cg_iusedoff; /* (u_int8) used inode map */
+ int32_t cg_freeoff; /* (u_int8) free block map */
+ int32_t cg_nextfreeoff; /* (u_int8) next available space */
+ int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
+ int32_t cg_clusteroff; /* (u_int8) free cluster map */
+ int32_t cg_nclusterblks; /* number of clusters this cg */
+ int32_t cg_niblk; /* number of inode blocks this cg */
+ int32_t cg_initediblk; /* last initialized inode */
+ int32_t cg_sparecon32[3]; /* reserved for future use */
+ int64_t cg_time; /* time last written */
+ int64_t cg_sparecon64[3]; /* reserved for future use */
+ u_int8_t cg_space[1]; /* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
+ * The following structure is defined
+ * for compatibility with old file systems.
+ */
+struct ocg {
+ int32_t cg_firstfield; /* historic linked list of cyl groups */
+ int32_t cg_unused_1; /* used for incore cyl groups */
+ int32_t cg_time; /* time last written */
+ int32_t cg_cgx; /* we are the cgx'th cylinder group */
+ int16_t cg_ncyl; /* number of cyl's this cg */
+ int16_t cg_niblk; /* number of inode blocks this cg */
+ int32_t cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int32_t cg_rotor; /* position of last used block */
+ int32_t cg_frotor; /* position of last used frag */
+ int32_t cg_irotor; /* position of last used inode */
+ int32_t cg_frsum[8]; /* counts of available frags */
+ int32_t cg_btot[32]; /* block totals per cylinder */
+ int16_t cg_b[32][8]; /* positions of free blocks */
+ u_int8_t cg_iused[256]; /* used inode map */
+ int32_t cg_magic; /* magic number */
+ u_int8_t cg_free[1]; /* free block map */
+/* actually longer */
+};
+
+
+/*
+ * Macros for access to cylinder group array structures.
+ */
+#define old_cg_blktot_old(cgp, ns) \
+ (((struct ocg *)(cgp))->cg_btot)
+#define old_cg_blks_old(fs, cgp, cylno, ns) \
+ (((struct ocg *)(cgp))->cg_b[cylno])
+
+#define old_cg_blktot_new(cgp, ns) \
+ ((int32_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_old_btotoff, (ns))))
+#define old_cg_blks_new(fs, cgp, cylno, ns) \
+ ((int16_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
+
+#define old_cg_blktot(cgp, ns) \
+ ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+ old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
+#define old_cg_blks(fs, cgp, cylno, ns) \
+ ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+ old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
+
+#define cg_inosused_new(cgp, ns) \
+ ((u_int8_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_iusedoff, (ns))))
+#define cg_blksfree_new(cgp, ns) \
+ ((u_int8_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_freeoff, (ns))))
+#define cg_chkmagic_new(cgp, ns) \
+ (ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
+
+#define cg_inosused_old(cgp, ns) \
+ (((struct ocg *)(cgp))->cg_iused)
+#define cg_blksfree_old(cgp, ns) \
+ (((struct ocg *)(cgp))->cg_free)
+#define cg_chkmagic_old(cgp, ns) \
+ (ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
+
+#define cg_inosused(cgp, ns) \
+ ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+ cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
+#define cg_blksfree(cgp, ns) \
+ ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+ cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
+#define cg_chkmagic(cgp, ns) \
+ (cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
+
+#define cg_clustersfree(cgp, ns) \
+ ((u_int8_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_clusteroff, (ns))))
+#define cg_clustersum(cgp, ns) \
+ ((int32_t *)((u_int8_t *)(cgp) + \
+ ufs_rw32((cgp)->cg_clustersumoff, (ns))))
+
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#if defined (_KERNEL)
+#define fsbtodb(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
+#define dbtofsb(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
+#else
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
+#endif
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define cgbase(fs, c) (((daddr_t)(fs)->fs_fpg) * (c))
+#define cgstart_ufs1(fs, c) \
+ (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
+#define cgstart_ufs2(fs, c) cgbase((fs), (c))
+#define cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
+ ? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
+#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
+#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
+#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to file system block offset.
+ * inode number to cylinder group number.
+ * inode number to file system block address.
+ */
+#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
+#define ino_to_fsba(fs, x) \
+ ((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
+ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define dtog(fs, d) ((d) / (fs)->fs_fpg)
+#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define blkmap(fs, map, loc) \
+ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+#define old_cbtocylno(fs, bno) \
+ (fsbtodb(fs, bno) / (fs)->fs_old_spc)
+#define old_cbtorpos(fs, bno) \
+ ((fs)->fs_old_nrpos <= 1 ? 0 : \
+ (fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
+ fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
+ (fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
+ ((loc) & (fs)->fs_qbmask)
+#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
+ ((loc) & (fs)->fs_qfmask)
+#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
+ (((off_t)(frag)) << (fs)->fs_fshift)
+#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
+ (((off_t)(blk)) << (fs)->fs_bshift)
+#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
+ ((loc) >> (fs)->fs_bshift)
+#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
+ ((loc) >> (fs)->fs_fshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
+ (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
+#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
+ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
+ ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
+ ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define freespace(fs, percentreserved) \
+ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+ (fs)->fs_cstotal.cs_nffree - \
+ (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the file system.
+ */
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+
+#define sblksize(fs, size, lbn) \
+ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (size)))))
+
+
+/*
+ * Number of inodes in a secondary storage block/fragment.
+ */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * Number of indirects in a file system block.
+ */
+#define NINDIR(fs) ((fs)->fs_nindir)
+
+/*
+ * Apple UFS Label:
+ * We check for this to decide to use APPLEUFS_DIRBLKSIZ
+ */
+#define APPLEUFS_LABEL_MAGIC 0x4c41424c /* LABL */
+#define APPLEUFS_LABEL_SIZE 1024
+#define APPLEUFS_LABEL_OFFSET (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
+#define APPLEUFS_LABEL_VERSION 1
+#define APPLEUFS_MAX_LABEL_NAME 512
+
+struct appleufslabel {
+ u_int32_t ul_magic;
+ u_int16_t ul_checksum;
+ u_int16_t ul_unused0;
+ u_int32_t ul_version;
+ u_int32_t ul_time;
+ u_int16_t ul_namelen;
+ u_char ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
+ u_int16_t ul_unused1;
+ u_int64_t ul_uuid; /* Note this is only 4 byte aligned */
+ u_char ul_reserved[24];
+ u_char ul_unused[460];
+} __packed;
+
+
+#endif /* !_UFS_FFS_FS_H_ */
--- /dev/null
+/* $NetBSD: lfs.h,v 1.134 2011/07/11 08:27:40 hannken Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Konrad E. Schroder <perseant@hhhh.org>.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ * @(#)lfs.h 8.9 (Berkeley) 5/8/95
+ */
+
+#ifndef _UFS_LFS_LFS_H_
+#define _UFS_LFS_LFS_H_
+
+#include <sys/rwlock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/condvar.h>
+
+/*
+ * Compile-time options for LFS.
+ */
+#define LFS_IFIND_RETRIES 16
+#define LFS_LOGLENGTH 1024 /* size of debugging log */
+#define LFS_MAX_ACTIVE 10 /* Dirty segments before ckp forced */
+
+/*
+ * Fixed filesystem layout parameters
+ */
+#define LFS_LABELPAD 8192 /* LFS label size */
+#define LFS_SBPAD 8192 /* LFS superblock size */
+
+#define LFS_UNUSED_INUM 0 /* 0: out of band inode number */
+#define LFS_IFILE_INUM 1 /* 1: IFILE inode number */
+ /* 2: Root inode number */
+#define LOSTFOUNDINO 3 /* 3: lost+found inode number */
+#define LFS_FIRST_INUM 4 /* 4: first free inode number */
+
+#define LFS_V1_SUMMARY_SIZE 512 /* V1 fixed summary size */
+#define LFS_DFL_SUMMARY_SIZE 512 /* Default summary size */
+
+#define LFS_MAX_DADDR 0x7fffffff /* Highest addressable fsb */
+
+#define LFS_MAXNAMLEN 255 /* maximum name length in a dir */
+
+/* Adjustable filesystem parameters */
+#define MIN_FREE_SEGS 20
+#define MIN_RESV_SEGS 15
+#ifndef LFS_ATIME_IFILE
+# define LFS_ATIME_IFILE 0 /* Store atime info in ifile (optional in LFSv1) */
+#endif
+#define LFS_MARKV_MAXBLKCNT 65536 /* Max block count for lfs_markv() */
+
+/* Misc. definitions */
+#define BW_CLEAN 1 /* Flag for lfs_bwrite_ext() */
+#define PG_DELWRI PG_PAGER1 /* Local def for delayed pageout */
+
+/* Resource limits */
+#define LFS_MAX_RESOURCE(x, u) (((x) >> 2) - 10 * (u))
+#define LFS_WAIT_RESOURCE(x, u) (((x) >> 1) - ((x) >> 3) - 10 * (u))
+#define LFS_INVERSE_MAX_RESOURCE(x, u) (((x) + 10 * (u)) << 2)
+#define LFS_MAX_BUFS LFS_MAX_RESOURCE(nbuf, 1)
+#define LFS_WAIT_BUFS LFS_WAIT_RESOURCE(nbuf, 1)
+#define LFS_INVERSE_MAX_BUFS(n) LFS_INVERSE_MAX_RESOURCE(n, 1)
+#define LFS_MAX_BYTES LFS_MAX_RESOURCE(bufmem_lowater, PAGE_SIZE)
+#define LFS_INVERSE_MAX_BYTES(n) LFS_INVERSE_MAX_RESOURCE(n, PAGE_SIZE)
+#define LFS_WAIT_BYTES LFS_WAIT_RESOURCE(bufmem_lowater, PAGE_SIZE)
+#define LFS_MAX_DIROP ((desiredvnodes >> 2) + (desiredvnodes >> 3))
+#define SIZEOF_DIROP(fs) (2 * ((fs)->lfs_bsize + DINODE1_SIZE))
+#define LFS_MAX_FSDIROP(fs) \
+ ((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 : \
+ (((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) / \
+ (2 * SIZEOF_DIROP(fs)))
+#define LFS_MAX_PAGES lfs_max_pages()
+#define LFS_WAIT_PAGES lfs_wait_pages()
+#define LFS_BUFWAIT 2 /* How long to wait if over *_WAIT_* */
+
+#ifdef _KERNEL
+int lfs_wait_pages(void);
+int lfs_max_pages(void);
+#endif /* _KERNEL */
+
+/* How starved can we be before we start holding back page writes */
+#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_resvseg)
+
+/*
+ * Reserved blocks for lfs_malloc
+ */
+
+/* Structure to keep reserved blocks */
+typedef struct lfs_res_blk {
+ void *p;
+ LIST_ENTRY(lfs_res_blk) res;
+ int size;
+ char inuse;
+} res_t;
+
+/* Types for lfs_newbuf and lfs_malloc */
+#define LFS_NB_UNKNOWN -1
+#define LFS_NB_SUMMARY 0
+#define LFS_NB_SBLOCK 1
+#define LFS_NB_IBLOCK 2
+#define LFS_NB_CLUSTER 3
+#define LFS_NB_CLEAN 4
+#define LFS_NB_BLKIOV 5
+#define LFS_NB_COUNT 6 /* always last */
+
+/* Number of reserved memory blocks of each type */
+#define LFS_N_SUMMARIES 2
+#define LFS_N_SBLOCKS 1 /* Always 1, to throttle superblock writes */
+#define LFS_N_IBLOCKS 16 /* In theory ssize/bsize; in practice around 2 */
+#define LFS_N_CLUSTERS 16 /* In theory ssize/MAXPHYS */
+#define LFS_N_CLEAN 0
+#define LFS_N_BLKIOV 1
+
+/* Total count of "large" (non-pool) types */
+#define LFS_N_TOTAL (LFS_N_SUMMARIES + LFS_N_SBLOCKS + LFS_N_IBLOCKS + \
+ LFS_N_CLUSTERS + LFS_N_CLEAN + LFS_N_BLKIOV)
+
+/* Counts for pool types */
+#define LFS_N_CL LFS_N_CLUSTERS
+#define LFS_N_BPP 2
+#define LFS_N_SEG 2
+
+/*
+ * "struct buf" associated definitions
+ */
+
+/* Unassigned disk addresses. */
+#define UNASSIGNED -1
+#define UNWRITTEN -2
+
+/* Unused logical block number */
+#define LFS_UNUSED_LBN -1
+
+/* Determine if a buffer belongs to the ifile */
+#define IS_IFILE(bp) (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM)
+
+# define LFS_LOCK_BUF(bp) do { \
+ if (((bp)->b_flags & B_LOCKED) == 0 && bp->b_iodone == NULL) { \
+ mutex_enter(&lfs_lock); \
+ ++locked_queue_count; \
+ locked_queue_bytes += bp->b_bufsize; \
+ mutex_exit(&lfs_lock); \
+ } \
+ (bp)->b_flags |= B_LOCKED; \
+} while (0)
+
+# define LFS_UNLOCK_BUF(bp) do { \
+ if (((bp)->b_flags & B_LOCKED) != 0 && bp->b_iodone == NULL) { \
+ mutex_enter(&lfs_lock); \
+ --locked_queue_count; \
+ locked_queue_bytes -= bp->b_bufsize; \
+ if (locked_queue_count < LFS_WAIT_BUFS && \
+ locked_queue_bytes < LFS_WAIT_BYTES) \
+ cv_broadcast(&locked_queue_cv); \
+ mutex_exit(&lfs_lock); \
+ } \
+ (bp)->b_flags &= ~B_LOCKED; \
+} while (0)
+
+#ifdef _KERNEL
+
+extern u_long bufmem_lowater, bufmem_hiwater; /* XXX */
+
+# define LFS_IS_MALLOC_BUF(bp) ((bp)->b_iodone == lfs_callback)
+
+# ifdef DEBUG
+# define LFS_DEBUG_COUNTLOCKED(m) do { \
+ if (lfs_debug_log_subsys[DLOG_LLIST]) { \
+ lfs_countlocked(&locked_queue_count, &locked_queue_bytes, (m)); \
+ cv_broadcast(&locked_queue_cv); \
+ } \
+} while (0)
+# else
+# define LFS_DEBUG_COUNTLOCKED(m)
+# endif
+
+/* log for debugging writes to the Ifile */
+# ifdef DEBUG
+struct lfs_log_entry {
+ const char *op;
+ const char *file;
+ int pid;
+ int line;
+ daddr_t block;
+ unsigned long flags;
+};
+extern int lfs_lognum;
+extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
+# define LFS_BWRITE_LOG(bp) lfs_bwrite_log((bp), __FILE__, __LINE__)
+# define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags, thepid) do {\
+ int _s; \
+ \
+ mutex_enter(&lfs_lock); \
+ _s = splbio(); \
+ lfs_log[lfs_lognum].op = theop; \
+ lfs_log[lfs_lognum].file = thefile; \
+ lfs_log[lfs_lognum].line = (theline); \
+ lfs_log[lfs_lognum].pid = (thepid); \
+ lfs_log[lfs_lognum].block = (lbn); \
+ lfs_log[lfs_lognum].flags = (theflags); \
+ lfs_lognum = (lfs_lognum + 1) % LFS_LOGLENGTH; \
+ splx(_s); \
+ mutex_exit(&lfs_lock); \
+} while (0)
+
+# define LFS_BCLEAN_LOG(fs, bp) do { \
+ if ((bp)->b_vp == (fs)->lfs_ivnode) \
+ LFS_ENTER_LOG("clear", __FILE__, __LINE__, \
+ bp->b_lblkno, bp->b_flags, curproc->p_pid);\
+} while (0)
+
+/* Must match list in lfs_vfsops.c ! */
+# define DLOG_RF 0 /* roll forward */
+# define DLOG_ALLOC 1 /* inode alloc */
+# define DLOG_AVAIL 2 /* lfs_{,r,f}avail */
+# define DLOG_FLUSH 3 /* flush */
+# define DLOG_LLIST 4 /* locked list accounting */
+# define DLOG_WVNODE 5 /* vflush/writevnodes verbose */
+# define DLOG_VNODE 6 /* vflush/writevnodes */
+# define DLOG_SEG 7 /* segwrite */
+# define DLOG_SU 8 /* seguse accounting */
+# define DLOG_CLEAN 9 /* cleaner routines */
+# define DLOG_MOUNT 10 /* mount/unmount */
+# define DLOG_PAGE 11 /* putpages/gop_write */
+# define DLOG_DIROP 12 /* dirop accounting */
+# define DLOG_MALLOC 13 /* lfs_malloc accounting */
+# define DLOG_MAX 14 /* The terminator */
+# define DLOG(a) lfs_debug_log a
+# else /* ! DEBUG */
+# define LFS_BCLEAN_LOG(fs, bp)
+# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp)->b_vp, (bp))
+# define DLOG(a)
+# endif /* ! DEBUG */
+#else /* ! _KERNEL */
+# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp))
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+/* Filehandle structure for exported LFSes */
+struct lfid {
+ struct ufid lfid_ufid;
+#define lfid_len lfid_ufid.ufid_len
+#define lfid_ino lfid_ufid.ufid_ino
+#define lfid_gen lfid_ufid.ufid_gen
+ uint32_t lfid_ident;
+};
+#endif /* _KERNEL */
+
+/*
+ * "struct inode" associated definitions
+ */
+
+/* Address calculations for metadata located in the inode */
+#define S_INDIR(fs) -NDADDR
+#define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1)
+#define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1)
+
+/* For convenience */
+#define IN_ALLMOD (IN_MODIFIED|IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_MODIFY|IN_ACCESSED|IN_CLEANING)
+
+#define LFS_SET_UINO(ip, flags) do { \
+ if (((flags) & IN_ACCESSED) && !((ip)->i_flag & IN_ACCESSED)) \
+ ++(ip)->i_lfs->lfs_uinodes; \
+ if (((flags) & IN_CLEANING) && !((ip)->i_flag & IN_CLEANING)) \
+ ++(ip)->i_lfs->lfs_uinodes; \
+ if (((flags) & IN_MODIFIED) && !((ip)->i_flag & IN_MODIFIED)) \
+ ++(ip)->i_lfs->lfs_uinodes; \
+ (ip)->i_flag |= (flags); \
+} while (0)
+
+#define LFS_CLR_UINO(ip, flags) do { \
+ if (((flags) & IN_ACCESSED) && ((ip)->i_flag & IN_ACCESSED)) \
+ --(ip)->i_lfs->lfs_uinodes; \
+ if (((flags) & IN_CLEANING) && ((ip)->i_flag & IN_CLEANING)) \
+ --(ip)->i_lfs->lfs_uinodes; \
+ if (((flags) & IN_MODIFIED) && ((ip)->i_flag & IN_MODIFIED)) \
+ --(ip)->i_lfs->lfs_uinodes; \
+ (ip)->i_flag &= ~(flags); \
+ if ((ip)->i_lfs->lfs_uinodes < 0) { \
+ panic("lfs_uinodes < 0"); \
+ } \
+} while (0)
+
+#define LFS_ITIMES(ip, acc, mod, cre) \
+ while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+ lfs_itimes(ip, acc, mod, cre)
+
+/*
+ * "struct vnode" associated definitions
+ */
+
+/* Heuristic emptiness measure */
+#define VPISEMPTY(vp) (LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
+ !(vp->v_type == VREG && (vp)->v_iflag & VI_ONWORKLST) &&\
+ VTOI(vp)->i_lfs_nbtree == 0)
+
+#define WRITEINPROG(vp) ((vp)->v_numoutput > 0 || \
+ (!LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
+ !(VTOI(vp)->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING))))
+
+
+/*
+ * On-disk and in-memory checkpoint segment usage structure.
+ */
+typedef struct segusage SEGUSE;
+struct segusage {
+ u_int32_t su_nbytes; /* 0: number of live bytes */
+ u_int32_t su_olastmod; /* 4: SEGUSE last modified timestamp */
+ u_int16_t su_nsums; /* 8: number of summaries in segment */
+ u_int16_t su_ninos; /* 10: number of inode blocks in seg */
+
+#define SEGUSE_ACTIVE 0x01 /* segment currently being written */
+#define SEGUSE_DIRTY 0x02 /* segment has data in it */
+#define SEGUSE_SUPERBLOCK 0x04 /* segment contains a superblock */
+#define SEGUSE_ERROR 0x08 /* cleaner: do not clean segment */
+#define SEGUSE_EMPTY 0x10 /* segment is empty */
+#define SEGUSE_INVAL 0x20 /* segment is invalid */
+ u_int32_t su_flags; /* 12: segment flags */
+ u_int64_t su_lastmod; /* 16: last modified timestamp */
+};
+
+typedef struct segusage_v1 SEGUSE_V1;
+struct segusage_v1 {
+ u_int32_t su_nbytes; /* 0: number of live bytes */
+ u_int32_t su_lastmod; /* 4: SEGUSE last modified timestamp */
+ u_int16_t su_nsums; /* 8: number of summaries in segment */
+ u_int16_t su_ninos; /* 10: number of inode blocks in seg */
+ u_int32_t su_flags; /* 12: segment flags */
+};
+
+#define SEGUPB(fs) (fs->lfs_sepb)
+#define SEGTABSIZE_SU(fs) \
+ (((fs)->lfs_nseg + SEGUPB(fs) - 1) / (fs)->lfs_sepb)
+
+#ifdef _KERNEL
+# define SHARE_IFLOCK(F) \
+ do { \
+ rw_enter(&(F)->lfs_iflock, RW_READER); \
+ } while(0)
+# define UNSHARE_IFLOCK(F) \
+ do { \
+ rw_exit(&(F)->lfs_iflock); \
+ } while(0)
+#else /* ! _KERNEL */
+# define SHARE_IFLOCK(F)
+# define UNSHARE_IFLOCK(F)
+#endif /* ! _KERNEL */
+
+/* Read in the block with a specific segment usage entry from the ifile. */
+#define LFS_SEGENTRY(SP, F, IN, BP) do { \
+ int _e; \
+ SHARE_IFLOCK(F); \
+ VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
+ if ((_e = bread((F)->lfs_ivnode, \
+ ((IN) / (F)->lfs_sepb) + (F)->lfs_cleansz, \
+ (F)->lfs_bsize, NOCRED, 0, &(BP))) != 0) \
+ panic("lfs: ifile read: %d", _e); \
+ if ((F)->lfs_version == 1) \
+ (SP) = (SEGUSE *)((SEGUSE_V1 *)(BP)->b_data + \
+ ((IN) & ((F)->lfs_sepb - 1))); \
+ else \
+ (SP) = (SEGUSE *)(BP)->b_data + ((IN) % (F)->lfs_sepb); \
+ UNSHARE_IFLOCK(F); \
+} while (0)
+
+#define LFS_WRITESEGENTRY(SP, F, IN, BP) do { \
+ if ((SP)->su_nbytes == 0) \
+ (SP)->su_flags |= SEGUSE_EMPTY; \
+ else \
+ (SP)->su_flags &= ~SEGUSE_EMPTY; \
+ (F)->lfs_suflags[(F)->lfs_activesb][(IN)] = (SP)->su_flags; \
+ LFS_BWRITE_LOG(BP); \
+} while (0)
+
+/*
+ * On-disk file information. One per file with data blocks in the segment.
+ */
+typedef struct finfo FINFO;
+struct finfo {
+ u_int32_t fi_nblocks; /* number of blocks */
+ u_int32_t fi_version; /* version number */
+ u_int32_t fi_ino; /* inode number */
+ u_int32_t fi_lastlength; /* length of last block in array */
+ int32_t fi_blocks[1]; /* array of logical block numbers */
+};
+/* sizeof FINFO except fi_blocks */
+#define FINFOSIZE (sizeof(FINFO) - sizeof(int32_t))
+
+/*
+ * Index file inode entries.
+ */
+typedef struct ifile IFILE;
+struct ifile {
+ u_int32_t if_version; /* inode version number */
+#define LFS_UNUSED_DADDR 0 /* out-of-band daddr */
+ int32_t if_daddr; /* inode disk address */
+#define LFS_ORPHAN_NEXTFREE (~(u_int32_t)0) /* indicate orphaned file */
+ u_int32_t if_nextfree; /* next-unallocated inode */
+ u_int32_t if_atime_sec; /* Last access time, seconds */
+ u_int32_t if_atime_nsec; /* and nanoseconds */
+};
+
+typedef struct ifile_v1 IFILE_V1;
+struct ifile_v1 {
+ u_int32_t if_version; /* inode version number */
+ int32_t if_daddr; /* inode disk address */
+ u_int32_t if_nextfree; /* next-unallocated inode */
+#if LFS_ATIME_IFILE
+ struct timespec if_atime; /* Last access time */
+#endif
+};
+
+/*
+ * LFSv1 compatibility code is not allowed to touch if_atime, since it
+ * may not be mapped!
+ */
+/* Read in the block with a specific inode from the ifile. */
+#define LFS_IENTRY(IP, F, IN, BP) do { \
+ int _e; \
+ SHARE_IFLOCK(F); \
+ VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
+ if ((_e = bread((F)->lfs_ivnode, \
+ (IN) / (F)->lfs_ifpb + (F)->lfs_cleansz + (F)->lfs_segtabsz, \
+ (F)->lfs_bsize, NOCRED, 0, &(BP))) != 0) \
+ panic("lfs: ifile ino %d read %d", (int)(IN), _e); \
+ if ((F)->lfs_version == 1) \
+ (IP) = (IFILE *)((IFILE_V1 *)(BP)->b_data + \
+ (IN) % (F)->lfs_ifpb); \
+ else \
+ (IP) = (IFILE *)(BP)->b_data + (IN) % (F)->lfs_ifpb; \
+ UNSHARE_IFLOCK(F); \
+} while (0)
+
+/*
+ * Cleaner information structure. This resides in the ifile and is used
+ * to pass information from the kernel to the cleaner.
+ */
+typedef struct _cleanerinfo {
+ u_int32_t clean; /* number of clean segments */
+ u_int32_t dirty; /* number of dirty segments */
+ int32_t bfree; /* disk blocks free */
+ int32_t avail; /* disk blocks available */
+ u_int32_t free_head; /* head of the inode free list */
+ u_int32_t free_tail; /* tail of the inode free list */
+#define LFS_CLEANER_MUST_CLEAN 0x01
+ u_int32_t flags; /* status word from the kernel */
+} CLEANERINFO;
+
+#define CLEANSIZE_SU(fs) \
+ ((sizeof(CLEANERINFO) + (fs)->lfs_bsize - 1) >> (fs)->lfs_bshift)
+
+/* Read in the block with the cleaner info from the ifile. */
+#define LFS_CLEANERINFO(CP, F, BP) do { \
+ SHARE_IFLOCK(F); \
+ VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
+ if (bread((F)->lfs_ivnode, \
+ (daddr_t)0, (F)->lfs_bsize, NOCRED, 0, &(BP))) \
+ panic("lfs: ifile read"); \
+ (CP) = (CLEANERINFO *)(BP)->b_data; \
+ UNSHARE_IFLOCK(F); \
+} while (0)
+
+/*
+ * Synchronize the Ifile cleaner info with current avail and bfree.
+ */
+#define LFS_SYNC_CLEANERINFO(cip, fs, bp, w) do { \
+ mutex_enter(&lfs_lock); \
+ if ((w) || (cip)->bfree != (fs)->lfs_bfree || \
+ (cip)->avail != (fs)->lfs_avail - (fs)->lfs_ravail - \
+ (fs)->lfs_favail) { \
+ (cip)->bfree = (fs)->lfs_bfree; \
+ (cip)->avail = (fs)->lfs_avail - (fs)->lfs_ravail - \
+ (fs)->lfs_favail; \
+ if (((bp)->b_flags & B_GATHERED) == 0) { \
+ (fs)->lfs_flags |= LFS_IFDIRTY; \
+ } \
+ mutex_exit(&lfs_lock); \
+ (void) LFS_BWRITE_LOG(bp); /* Ifile */ \
+ } else { \
+ mutex_exit(&lfs_lock); \
+ brelse(bp, 0); \
+ } \
+} while (0)
+
+/*
+ * Get the head of the inode free list.
+ * Always called with the segment lock held.
+ */
+#define LFS_GET_HEADFREE(FS, CIP, BP, FREEP) do { \
+ if ((FS)->lfs_version > 1) { \
+ LFS_CLEANERINFO((CIP), (FS), (BP)); \
+ (FS)->lfs_freehd = (CIP)->free_head; \
+ brelse(BP, 0); \
+ } \
+ *(FREEP) = (FS)->lfs_freehd; \
+} while (0)
+
+#define LFS_PUT_HEADFREE(FS, CIP, BP, VAL) do { \
+ (FS)->lfs_freehd = (VAL); \
+ if ((FS)->lfs_version > 1) { \
+ LFS_CLEANERINFO((CIP), (FS), (BP)); \
+ (CIP)->free_head = (VAL); \
+ LFS_BWRITE_LOG(BP); \
+ mutex_enter(&lfs_lock); \
+ (FS)->lfs_flags |= LFS_IFDIRTY; \
+ mutex_exit(&lfs_lock); \
+ } \
+} while (0)
+
+#define LFS_GET_TAILFREE(FS, CIP, BP, FREEP) do { \
+ LFS_CLEANERINFO((CIP), (FS), (BP)); \
+ *(FREEP) = (CIP)->free_tail; \
+ brelse(BP, 0); \
+} while (0)
+
+#define LFS_PUT_TAILFREE(FS, CIP, BP, VAL) do { \
+ LFS_CLEANERINFO((CIP), (FS), (BP)); \
+ (CIP)->free_tail = (VAL); \
+ LFS_BWRITE_LOG(BP); \
+ mutex_enter(&lfs_lock); \
+ (FS)->lfs_flags |= LFS_IFDIRTY; \
+ mutex_exit(&lfs_lock); \
+} while (0)
+
+/*
+ * On-disk segment summary information
+ */
+typedef struct segsum_v1 SEGSUM_V1;
+struct segsum_v1 {
+ u_int32_t ss_sumsum; /* 0: check sum of summary block */
+ u_int32_t ss_datasum; /* 4: check sum of data */
+ u_int32_t ss_magic; /* 8: segment summary magic number */
+#define SS_MAGIC 0x061561
+ int32_t ss_next; /* 12: next segment */
+ u_int32_t ss_create; /* 16: creation time stamp */
+ u_int16_t ss_nfinfo; /* 20: number of file info structures */
+ u_int16_t ss_ninos; /* 22: number of inodes in summary */
+
+#define SS_DIROP 0x01 /* segment begins a dirop */
+#define SS_CONT 0x02 /* more partials to finish this write*/
+#define SS_CLEAN 0x04 /* written by the cleaner */
+#define SS_RFW 0x08 /* written by the roll-forward agent */
+ u_int16_t ss_flags; /* 24: used for directory operations */
+ u_int16_t ss_pad; /* 26: extra space */
+ /* FINFO's and inode daddr's... */
+};
+
+typedef struct segsum SEGSUM;
+struct segsum {
+ u_int32_t ss_sumsum; /* 0: check sum of summary block */
+ u_int32_t ss_datasum; /* 4: check sum of data */
+ u_int32_t ss_magic; /* 8: segment summary magic number */
+ int32_t ss_next; /* 12: next segment */
+ u_int32_t ss_ident; /* 16: roll-forward fsid */
+#define ss_ocreate ss_ident /* ident is where create was in v1 */
+ u_int16_t ss_nfinfo; /* 20: number of file info structures */
+ u_int16_t ss_ninos; /* 22: number of inodes in summary */
+ u_int16_t ss_flags; /* 24: used for directory operations */
+ u_int8_t ss_pad[6]; /* 26: extra space */
+ u_int64_t ss_serial; /* 32: serial number */
+ u_int64_t ss_create; /* 40: time stamp */
+ /* FINFO's and inode daddr's... */
+};
+
+#define SEGSUM_SIZE(fs) ((fs)->lfs_version == 1 ? sizeof(SEGSUM_V1) : sizeof(SEGSUM))
+
+
+/*
+ * On-disk super block.
+ */
+struct dlfs {
+#define LFS_MAGIC 0x070162
+ u_int32_t dlfs_magic; /* 0: magic number */
+#define LFS_VERSION 2
+ u_int32_t dlfs_version; /* 4: version number */
+
+ u_int32_t dlfs_size; /* 8: number of blocks in fs (v1) */
+ /* number of frags in fs (v2) */
+ u_int32_t dlfs_ssize; /* 12: number of blocks per segment (v1) */
+ /* number of bytes per segment (v2) */
+ u_int32_t dlfs_dsize; /* 16: number of disk blocks in fs */
+ u_int32_t dlfs_bsize; /* 20: file system block size */
+ u_int32_t dlfs_fsize; /* 24: size of frag blocks in fs */
+ u_int32_t dlfs_frag; /* 28: number of frags in a block in fs */
+
+/* Checkpoint region. */
+ u_int32_t dlfs_freehd; /* 32: start of the free list */
+ int32_t dlfs_bfree; /* 36: number of free disk blocks */
+ u_int32_t dlfs_nfiles; /* 40: number of allocated inodes */
+ int32_t dlfs_avail; /* 44: blocks available for writing */
+ int32_t dlfs_uinodes; /* 48: inodes in cache not yet on disk */
+ int32_t dlfs_idaddr; /* 52: inode file disk address */
+ u_int32_t dlfs_ifile; /* 56: inode file inode number */
+ int32_t dlfs_lastseg; /* 60: address of last segment written */
+ int32_t dlfs_nextseg; /* 64: address of next segment to write */
+ int32_t dlfs_curseg; /* 68: current segment being written */
+ int32_t dlfs_offset; /* 72: offset in curseg for next partial */
+ int32_t dlfs_lastpseg; /* 76: address of last partial written */
+ u_int32_t dlfs_inopf; /* 80: v1: time stamp; v2: inodes per frag */
+#define dlfs_otstamp dlfs_inopf
+
+/* These are configuration parameters. */
+ u_int32_t dlfs_minfree; /* 84: minimum percentage of free blocks */
+
+/* These fields can be computed from the others. */
+ u_int64_t dlfs_maxfilesize; /* 88: maximum representable file size */
+ u_int32_t dlfs_fsbpseg; /* 96: fsb per segment */
+ u_int32_t dlfs_inopb; /* 100: inodes per block */
+ u_int32_t dlfs_ifpb; /* 104: IFILE entries per block */
+ u_int32_t dlfs_sepb; /* 108: SEGUSE entries per block */
+ u_int32_t dlfs_nindir; /* 112: indirect pointers per block */
+ u_int32_t dlfs_nseg; /* 116: number of segments */
+ u_int32_t dlfs_nspf; /* 120: number of sectors per fragment */
+ u_int32_t dlfs_cleansz; /* 124: cleaner info size in blocks */
+ u_int32_t dlfs_segtabsz; /* 128: segment table size in blocks */
+ u_int32_t dlfs_segmask; /* 132: calculate offset within a segment */
+ u_int32_t dlfs_segshift; /* 136: fast mult/div for segments */
+ u_int32_t dlfs_bshift; /* 140: calc block number from file offset */
+ u_int32_t dlfs_ffshift; /* 144: fast mult/div for frag from file */
+ u_int32_t dlfs_fbshift; /* 148: fast mult/div for frag from block */
+ u_int64_t dlfs_bmask; /* 152: calc block offset from file offset */
+ u_int64_t dlfs_ffmask; /* 160: calc frag offset from file offset */
+ u_int64_t dlfs_fbmask; /* 168: calc frag offset from block offset */
+ u_int32_t dlfs_blktodb; /* 176: blktodb and dbtoblk shift constant */
+ u_int32_t dlfs_sushift; /* 180: fast mult/div for segusage table */
+
+ int32_t dlfs_maxsymlinklen; /* 184: max length of an internal symlink */
+#define LFS_MIN_SBINTERVAL 5 /* minimum superblock segment spacing */
+#define LFS_MAXNUMSB 10 /* 188: superblock disk offsets */
+ int32_t dlfs_sboffs[LFS_MAXNUMSB];
+
+ u_int32_t dlfs_nclean; /* 228: Number of clean segments */
+ u_char dlfs_fsmnt[MNAMELEN]; /* 232: name mounted on */
+#define LFS_PF_CLEAN 0x1
+ u_int16_t dlfs_pflags; /* 322: file system persistent flags */
+ int32_t dlfs_dmeta; /* 324: total number of dirty summaries */
+ u_int32_t dlfs_minfreeseg; /* 328: segments not counted in bfree */
+ u_int32_t dlfs_sumsize; /* 332: size of summary blocks */
+ u_int64_t dlfs_serial; /* 336: serial number */
+ u_int32_t dlfs_ibsize; /* 344: size of inode blocks */
+ int32_t dlfs_start; /* 348: start of segment 0 */
+ u_int64_t dlfs_tstamp; /* 352: time stamp */
+#define LFS_44INODEFMT 0
+#define LFS_MAXINODEFMT 0
+ u_int32_t dlfs_inodefmt; /* 360: inode format version */
+ u_int32_t dlfs_interleave; /* 364: segment interleave */
+ u_int32_t dlfs_ident; /* 368: per-fs identifier */
+ u_int32_t dlfs_fsbtodb; /* 372: fsbtodb abd dbtodsb shift constant */
+ u_int32_t dlfs_resvseg; /* 376: segments reserved for the cleaner */
+ int8_t dlfs_pad[128]; /* 380: round to 512 bytes */
+/* Checksum -- last valid disk field. */
+ u_int32_t dlfs_cksum; /* 508: checksum for superblock checking */
+};
+
+/* Type used for the inode bitmap */
+typedef u_int32_t lfs_bm_t;
+
+/*
+ * Linked list of segments whose byte count needs updating following a
+ * file truncation.
+ */
+struct segdelta {
+ long segnum;
+ size_t num;
+ LIST_ENTRY(segdelta) list;
+};
+
+/*
+ * In-memory super block.
+ */
+struct lfs {
+ struct dlfs lfs_dlfs; /* on-disk parameters */
+#define lfs_magic lfs_dlfs.dlfs_magic
+#define lfs_version lfs_dlfs.dlfs_version
+#define lfs_size lfs_dlfs.dlfs_size
+#define lfs_ssize lfs_dlfs.dlfs_ssize
+#define lfs_dsize lfs_dlfs.dlfs_dsize
+#define lfs_bsize lfs_dlfs.dlfs_bsize
+#define lfs_fsize lfs_dlfs.dlfs_fsize
+#define lfs_frag lfs_dlfs.dlfs_frag
+#define lfs_freehd lfs_dlfs.dlfs_freehd
+#define lfs_bfree lfs_dlfs.dlfs_bfree
+#define lfs_nfiles lfs_dlfs.dlfs_nfiles
+#define lfs_avail lfs_dlfs.dlfs_avail
+#define lfs_uinodes lfs_dlfs.dlfs_uinodes
+#define lfs_idaddr lfs_dlfs.dlfs_idaddr
+#define lfs_ifile lfs_dlfs.dlfs_ifile
+#define lfs_lastseg lfs_dlfs.dlfs_lastseg
+#define lfs_nextseg lfs_dlfs.dlfs_nextseg
+#define lfs_curseg lfs_dlfs.dlfs_curseg
+#define lfs_offset lfs_dlfs.dlfs_offset
+#define lfs_lastpseg lfs_dlfs.dlfs_lastpseg
+#define lfs_otstamp lfs_dlfs.dlfs_inopf
+#define lfs_inopf lfs_dlfs.dlfs_inopf
+#define lfs_minfree lfs_dlfs.dlfs_minfree
+#define lfs_maxfilesize lfs_dlfs.dlfs_maxfilesize
+#define lfs_fsbpseg lfs_dlfs.dlfs_fsbpseg
+#define lfs_inopb lfs_dlfs.dlfs_inopb
+#define lfs_ifpb lfs_dlfs.dlfs_ifpb
+#define lfs_sepb lfs_dlfs.dlfs_sepb
+#define lfs_nindir lfs_dlfs.dlfs_nindir
+#define lfs_nseg lfs_dlfs.dlfs_nseg
+#define lfs_nspf lfs_dlfs.dlfs_nspf
+#define lfs_cleansz lfs_dlfs.dlfs_cleansz
+#define lfs_segtabsz lfs_dlfs.dlfs_segtabsz
+#define lfs_segmask lfs_dlfs.dlfs_segmask
+#define lfs_segshift lfs_dlfs.dlfs_segshift
+#define lfs_bmask lfs_dlfs.dlfs_bmask
+#define lfs_bshift lfs_dlfs.dlfs_bshift
+#define lfs_ffmask lfs_dlfs.dlfs_ffmask
+#define lfs_ffshift lfs_dlfs.dlfs_ffshift
+#define lfs_fbmask lfs_dlfs.dlfs_fbmask
+#define lfs_fbshift lfs_dlfs.dlfs_fbshift
+#define lfs_blktodb lfs_dlfs.dlfs_blktodb
+#define lfs_fsbtodb lfs_dlfs.dlfs_fsbtodb
+#define lfs_sushift lfs_dlfs.dlfs_sushift
+#define lfs_maxsymlinklen lfs_dlfs.dlfs_maxsymlinklen
+#define lfs_sboffs lfs_dlfs.dlfs_sboffs
+#define lfs_cksum lfs_dlfs.dlfs_cksum
+#define lfs_pflags lfs_dlfs.dlfs_pflags
+#define lfs_fsmnt lfs_dlfs.dlfs_fsmnt
+#define lfs_nclean lfs_dlfs.dlfs_nclean
+#define lfs_dmeta lfs_dlfs.dlfs_dmeta
+#define lfs_minfreeseg lfs_dlfs.dlfs_minfreeseg
+#define lfs_sumsize lfs_dlfs.dlfs_sumsize
+#define lfs_serial lfs_dlfs.dlfs_serial
+#define lfs_ibsize lfs_dlfs.dlfs_ibsize
+#define lfs_start lfs_dlfs.dlfs_start
+#define lfs_tstamp lfs_dlfs.dlfs_tstamp
+#define lfs_inodefmt lfs_dlfs.dlfs_inodefmt
+#define lfs_interleave lfs_dlfs.dlfs_interleave
+#define lfs_ident lfs_dlfs.dlfs_ident
+#define lfs_resvseg lfs_dlfs.dlfs_resvseg
+
+/* These fields are set at mount time and are meaningless on disk. */
+ struct segment *lfs_sp; /* current segment being written */
+ struct vnode *lfs_ivnode; /* vnode for the ifile */
+ u_int32_t lfs_seglock; /* single-thread the segment writer */
+ pid_t lfs_lockpid; /* pid of lock holder */
+ lwpid_t lfs_locklwp; /* lwp of lock holder */
+ u_int32_t lfs_iocount; /* number of ios pending */
+ u_int32_t lfs_writer; /* don't allow any dirops to start */
+ u_int32_t lfs_dirops; /* count of active directory ops */
+ u_int32_t lfs_dirvcount; /* count of VDIROP nodes in this fs */
+ u_int32_t lfs_doifile; /* Write ifile blocks on next write */
+ u_int32_t lfs_nactive; /* Number of segments since last ckp */
+ int8_t lfs_fmod; /* super block modified flag */
+ int8_t lfs_ronly; /* mounted read-only flag */
+#define LFS_NOTYET 0x01
+#define LFS_IFDIRTY 0x02
+#define LFS_WARNED 0x04
+#define LFS_UNDIROP 0x08
+ int8_t lfs_flags; /* currently unused flag */
+ u_int16_t lfs_activesb; /* toggle between superblocks */
+ daddr_t lfs_sbactive; /* disk address of current sb write */
+ struct vnode *lfs_flushvp; /* vnode being flushed */
+ int lfs_flushvp_fakevref; /* fake vref count for flushvp */
+ struct vnode *lfs_unlockvp; /* being inactivated in lfs_segunlock */
+ u_int32_t lfs_diropwait; /* # procs waiting on dirop flush */
+ size_t lfs_devbsize; /* Device block size */
+ size_t lfs_devbshift; /* Device block shift */
+ krwlock_t lfs_fraglock;
+ krwlock_t lfs_iflock; /* Ifile lock */
+ kcondvar_t lfs_stopcv; /* Wrap lock */
+ struct lwp *lfs_stoplwp;
+ pid_t lfs_rfpid; /* Process ID of roll-forward agent */
+ int lfs_nadirop; /* number of active dirop nodes */
+ long lfs_ravail; /* blocks pre-reserved for writing */
+ long lfs_favail; /* blocks pre-reserved for writing */
+ res_t *lfs_resblk; /* Reserved memory for pageout */
+ TAILQ_HEAD(, inode) lfs_dchainhd; /* dirop vnodes */
+ TAILQ_HEAD(, inode) lfs_pchainhd; /* paging vnodes */
+#define LFS_RESHASH_WIDTH 17
+ LIST_HEAD(, lfs_res_blk) lfs_reshash[LFS_RESHASH_WIDTH];
+ int lfs_pdflush; /* pagedaemon wants us to flush */
+ u_int32_t **lfs_suflags; /* Segment use flags */
+#ifdef _KERNEL
+ struct pool lfs_clpool; /* Pool for struct lfs_cluster */
+ struct pool lfs_bpppool; /* Pool for bpp */
+ struct pool lfs_segpool; /* Pool for struct segment */
+#endif /* _KERNEL */
+#define LFS_MAX_CLEANIND 64
+ int32_t lfs_cleanint[LFS_MAX_CLEANIND]; /* Active cleaning intervals */
+ int lfs_cleanind; /* Index into intervals */
+ int lfs_sleepers; /* # procs sleeping this fs */
+ int lfs_pages; /* dirty pages blaming this fs */
+ lfs_bm_t *lfs_ino_bitmap; /* Inuse inodes bitmap */
+ int lfs_nowrap; /* Suspend log wrap */
+ int lfs_wrappass; /* Allow first log wrap requester to pass */
+ int lfs_wrapstatus; /* Wrap status */
+ LIST_HEAD(, segdelta) lfs_segdhd; /* List of pending trunc accounting events */
+};
+
+/* NINDIR is the number of indirects in a file system block. */
+#define NINDIR(fs) ((fs)->lfs_nindir)
+
+/* INOPB is the number of inodes in a secondary storage block. */
+#define INOPB(fs) ((fs)->lfs_inopb)
+/* INOPF is the number of inodes in a fragment. */
+#define INOPF(fs) ((fs)->lfs_inopf)
+
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \
+ ? (fs)->lfs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_ffs1_size))))
+#define blkoff(fs, loc) ((int)((loc) & (fs)->lfs_bmask))
+#define fragoff(fs, loc) /* calculates (loc % fs->lfs_fsize) */ \
+ ((int)((loc) & (fs)->lfs_ffmask))
+
+#if defined (_KERNEL)
+#define fsbtodb(fs, b) ((b) << ((fs)->lfs_ffshift - DEV_BSHIFT))
+#define dbtofsb(fs, b) ((b) >> ((fs)->lfs_ffshift - DEV_BSHIFT))
+#else
+#define fsbtodb(fs, b) ((b) << (fs)->lfs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->lfs_fsbtodb)
+#endif
+
+#define lblkno(fs, loc) ((loc) >> (fs)->lfs_bshift)
+#define lblktosize(fs, blk) ((blk) << (fs)->lfs_bshift)
+
+#define fsbtob(fs, b) ((b) << (fs)->lfs_ffshift)
+#define btofsb(fs, b) ((b) >> (fs)->lfs_ffshift)
+
+#define numfrags(fs, loc) /* calculates (loc / fs->lfs_fsize) */ \
+ ((loc) >> (fs)->lfs_ffshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->lfs_bsize) */ \
+ ((off_t)(((size) + (fs)->lfs_bmask) & (~(fs)->lfs_bmask)))
+#define fragroundup(fs, size) /* calculates roundup(size, fs->lfs_fsize) */ \
+ ((off_t)(((size) + (fs)->lfs_ffmask) & (~(fs)->lfs_ffmask)))
+#define fragstoblks(fs, frags)/* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->lfs_fbshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->lfs_fbshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->lfs_frag) */ \
+ ((fsb) & ((fs)->lfs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->lfs_frag) */ \
+ ((fsb) &~ ((fs)->lfs_frag - 1))
+#define dblksize(fs, dp, lbn) \
+ (((lbn) >= NDADDR || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\
+ ? (fs)->lfs_bsize \
+ : (fragroundup(fs, blkoff(fs, (dp)->di_size))))
+
+#define segsize(fs) ((fs)->lfs_version == 1 ? \
+ lblktosize((fs), (fs)->lfs_ssize) : \
+ (fs)->lfs_ssize)
+#define segtod(fs, seg) (((fs)->lfs_version == 1 ? \
+ (fs)->lfs_ssize << (fs)->lfs_blktodb : \
+ btofsb((fs), (fs)->lfs_ssize)) * (seg))
+#define dtosn(fs, daddr) /* block address to segment number */ \
+ ((uint32_t)(((daddr) - (fs)->lfs_start) / segtod((fs), 1)))
+#define sntod(fs, sn) /* segment number to disk address */ \
+ ((daddr_t)(segtod((fs), (sn)) + (fs)->lfs_start))
+
+/*
+ * Structures used by lfs_bmapv and lfs_markv to communicate information
+ * about inodes and data blocks.
+ */
+typedef struct block_info {
+ u_int32_t bi_inode; /* inode # */
+ int32_t bi_lbn; /* logical block w/in file */
+ int32_t bi_daddr; /* disk address of block */
+ u_int64_t bi_segcreate; /* origin segment create time */
+ int bi_version; /* file version number */
+ void *bi_bp; /* data buffer */
+ int bi_size; /* size of the block (if fragment) */
+} BLOCK_INFO;
+
+/* Compatibility for 1.5 binaries */
+typedef struct block_info_15 {
+ u_int32_t bi_inode; /* inode # */
+ int32_t bi_lbn; /* logical block w/in file */
+ int32_t bi_daddr; /* disk address of block */
+ u_int32_t bi_segcreate; /* origin segment create time */
+ int bi_version; /* file version number */
+ void *bi_bp; /* data buffer */
+ int bi_size; /* size of the block (if fragment) */
+} BLOCK_INFO_15;
+
+/* In-memory description of a segment about to be written. */
+struct segment {
+ struct lfs *fs; /* file system pointer */
+ struct buf **bpp; /* pointer to buffer array */
+ struct buf **cbpp; /* pointer to next available bp */
+ struct buf **start_bpp; /* pointer to first bp in this set */
+ struct buf *ibp; /* buffer pointer to inode page */
+ struct ufs1_dinode *idp; /* pointer to ifile dinode */
+ struct finfo *fip; /* current fileinfo pointer */
+ struct vnode *vp; /* vnode being gathered */
+ void *segsum; /* segment summary info */
+ u_int32_t ninodes; /* number of inodes in this segment */
+ int32_t seg_bytes_left; /* bytes left in segment */
+ int32_t sum_bytes_left; /* bytes left in summary block */
+ u_int32_t seg_number; /* number of this segment */
+ int32_t *start_lbp; /* beginning lbn for this set */
+
+#define SEGM_CKP 0x01 /* doing a checkpoint */
+#define SEGM_CLEAN 0x02 /* cleaner call; don't sort */
+#define SEGM_SYNC 0x04 /* wait for segment */
+#define SEGM_PROT 0x08 /* don't inactivate at segunlock */
+#define SEGM_PAGEDAEMON 0x10 /* pagedaemon called us */
+#define SEGM_WRITERD 0x20 /* LFS writed called us */
+#define SEGM_FORCE_CKP 0x40 /* Force checkpoint right away */
+ u_int16_t seg_flags; /* run-time flags for this segment */
+ u_int32_t seg_iocount; /* number of ios pending */
+ int ndupino; /* number of duplicate inodes */
+};
+
+#ifdef _KERNEL
+struct lfs_cluster {
+ size_t bufsize; /* Size of kept data */
+ struct buf **bpp; /* Array of kept buffers */
+ int bufcount; /* Number of kept buffers */
+#define LFS_CL_MALLOC 0x00000001
+#define LFS_CL_SHIFT 0x00000002
+#define LFS_CL_SYNC 0x00000004
+ u_int32_t flags; /* Flags */
+ struct lfs *fs; /* LFS that this belongs to */
+ struct segment *seg; /* Segment structure, for LFS_CL_SYNC */
+};
+
+/*
+ * Splay tree containing block numbers allocated through lfs_balloc.
+ */
+struct lbnentry {
+ SPLAY_ENTRY(lbnentry) entry;
+ daddr_t lbn;
+};
+#endif /* _KERNEL */
+
+/*
+ * LFS inode extensions.
+ */
+struct lfs_inode_ext {
+ off_t lfs_osize; /* size of file on disk */
+ u_int32_t lfs_effnblocks; /* number of blocks when i/o completes */
+ size_t lfs_fragsize[NDADDR]; /* size of on-disk direct blocks */
+ TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */
+ TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */
+#define LFSI_NO_GOP_WRITE 0x01
+#define LFSI_DELETED 0x02
+#define LFSI_WRAPBLOCK 0x04
+#define LFSI_WRAPWAIT 0x08
+ u_int32_t lfs_iflags; /* Inode flags */
+ daddr_t lfs_hiblk; /* Highest lbn held by inode */
+#ifdef _KERNEL
+ SPLAY_HEAD(lfs_splay, lbnentry) lfs_lbtree; /* Tree of balloc'd lbns */
+ int lfs_nbtree; /* Size of tree */
+ LIST_HEAD(, segdelta) lfs_segdhd;
+#endif
+ int16_t lfs_odnlink; /* on-disk nlink count for cleaner */
+};
+#define i_lfs_osize inode_ext.lfs->lfs_osize
+#define i_lfs_effnblks inode_ext.lfs->lfs_effnblocks
+#define i_lfs_fragsize inode_ext.lfs->lfs_fragsize
+#define i_lfs_dchain inode_ext.lfs->lfs_dchain
+#define i_lfs_pchain inode_ext.lfs->lfs_pchain
+#define i_lfs_iflags inode_ext.lfs->lfs_iflags
+#define i_lfs_hiblk inode_ext.lfs->lfs_hiblk
+#define i_lfs_lbtree inode_ext.lfs->lfs_lbtree
+#define i_lfs_nbtree inode_ext.lfs->lfs_nbtree
+#define i_lfs_segdhd inode_ext.lfs->lfs_segdhd
+#define i_lfs_odnlink inode_ext.lfs->lfs_odnlink
+
+/*
+ * Macros for determining free space on the disk, with the variable metadata
+ * of segment summaries and inode blocks taken into account.
+ */
+/* Estimate number of clean blocks not available for writing */
+#define LFS_EST_CMETA(F) (int32_t)((((F)->lfs_dmeta * \
+ (int64_t)(F)->lfs_nclean) / \
+ ((F)->lfs_nseg - (F)->lfs_nclean)))
+
+/* Estimate total size of the disk not including metadata */
+#define LFS_EST_NONMETA(F) ((F)->lfs_dsize - (F)->lfs_dmeta - LFS_EST_CMETA(F))
+
+/* Estimate number of blocks actually available for writing */
+#define LFS_EST_BFREE(F) ((F)->lfs_bfree > LFS_EST_CMETA(F) ? \
+ (F)->lfs_bfree - LFS_EST_CMETA(F) : 0)
+
+/* Amount of non-meta space not available to mortal man */
+#define LFS_EST_RSVD(F) (int32_t)((LFS_EST_NONMETA(F) * \
+ (u_int64_t)(F)->lfs_minfree) / \
+ 100)
+
+/* Can credential C write BB blocks */
+#define ISSPACE(F, BB, C) \
+ ((((C) == NOCRED || kauth_cred_geteuid(C) == 0) && \
+ LFS_EST_BFREE(F) >= (BB)) || \
+ (kauth_cred_geteuid(C) != 0 && IS_FREESPACE(F, BB)))
+
+/* Can an ordinary user write BB blocks */
+#define IS_FREESPACE(F, BB) \
+ (LFS_EST_BFREE(F) >= (BB) + LFS_EST_RSVD(F))
+
+/*
+ * The minimum number of blocks to create a new inode. This is:
+ * directory direct block (1) + NIADDR indirect blocks + inode block (1) +
+ * ifile direct block (1) + NIADDR indirect blocks = 3 + 2 * NIADDR blocks.
+ */
+#define LFS_NRESERVE(F) (btofsb((F), (2 * NIADDR + 3) << (F)->lfs_bshift))
+
+/* Statistics Counters */
+struct lfs_stats { /* Must match sysctl list in lfs_vfsops.h ! */
+ u_int segsused;
+ u_int psegwrites;
+ u_int psyncwrites;
+ u_int pcleanwrites;
+ u_int blocktot;
+ u_int cleanblocks;
+ u_int ncheckpoints;
+ u_int nwrites;
+ u_int nsync_writes;
+ u_int wait_exceeded;
+ u_int write_exceeded;
+ u_int flush_invoked;
+ u_int vflush_invoked;
+ u_int clean_inlocked;
+ u_int clean_vnlocked;
+ u_int segs_reclaimed;
+};
+#ifdef _KERNEL
+extern struct lfs_stats lfs_stats;
+#endif
+
+/* Fcntls to take the place of the lfs syscalls */
+struct lfs_fcntl_markv {
+ BLOCK_INFO *blkiov; /* blocks to relocate */
+ int blkcnt; /* number of blocks */
+};
+
+#define LFCNSEGWAITALL _FCNR_FSPRIV('L', 14, struct timeval)
+#define LFCNSEGWAIT _FCNR_FSPRIV('L', 15, struct timeval)
+#define LFCNBMAPV _FCNRW_FSPRIV('L', 2, struct lfs_fcntl_markv)
+#define LFCNMARKV _FCNRW_FSPRIV('L', 3, struct lfs_fcntl_markv)
+#define LFCNRECLAIM _FCNO_FSPRIV('L', 4)
+
+struct lfs_fhandle {
+ char space[28]; /* FHANDLE_SIZE_COMPAT (but used from userland too) */
+};
+#define LFCNREWIND _FCNR_FSPRIV('L', 6, int)
+#define LFCNINVAL _FCNR_FSPRIV('L', 7, int)
+#define LFCNRESIZE _FCNR_FSPRIV('L', 8, int)
+#define LFCNWRAPSTOP _FCNR_FSPRIV('L', 9, int)
+#define LFCNWRAPGO _FCNR_FSPRIV('L', 10, int)
+#define LFCNIFILEFH _FCNW_FSPRIV('L', 11, struct lfs_fhandle)
+#define LFCNWRAPPASS _FCNR_FSPRIV('L', 12, int)
+# define LFS_WRAP_GOING 0x0
+# define LFS_WRAP_WAITING 0x1
+#define LFCNWRAPSTATUS _FCNW_FSPRIV('L', 13, int)
+
+/*
+ * Compat. Defined for kernel only. Userland always uses
+ * "the one true version".
+ */
+#ifdef _KERNEL
+#include <compat/sys/time_types.h>
+
+#define LFCNSEGWAITALL_COMPAT _FCNW_FSPRIV('L', 0, struct timeval50)
+#define LFCNSEGWAIT_COMPAT _FCNW_FSPRIV('L', 1, struct timeval50)
+#define LFCNIFILEFH_COMPAT _FCNW_FSPRIV('L', 5, struct lfs_fhandle)
+#define LFCNIFILEFH_COMPAT2 _FCN_FSPRIV(F_FSOUT, 'L', 11, 32)
+#define LFCNWRAPSTOP_COMPAT _FCNO_FSPRIV('L', 9)
+#define LFCNWRAPGO_COMPAT _FCNO_FSPRIV('L', 10)
+#define LFCNSEGWAITALL_COMPAT_50 _FCNR_FSPRIV('L', 0, struct timeval50)
+#define LFCNSEGWAIT_COMPAT_50 _FCNR_FSPRIV('L', 1, struct timeval50)
+#endif
+
+#ifdef _KERNEL
+/* XXX MP */
+#define LFS_SEGLOCK_HELD(fs) \
+ ((fs)->lfs_seglock != 0 && \
+ (fs)->lfs_lockpid == curproc->p_pid && \
+ (fs)->lfs_locklwp == curlwp->l_lid)
+#endif /* _KERNEL */
+
+/* Debug segment lock */
+#ifdef notyet
+# define ASSERT_SEGLOCK(fs) KASSERT(LFS_SEGLOCK_HELD(fs))
+# define ASSERT_NO_SEGLOCK(fs) KASSERT(!LFS_SEGLOCK_HELD(fs))
+# define ASSERT_DUNNO_SEGLOCK(fs)
+# define ASSERT_MAYBE_SEGLOCK(fs)
+#else /* !notyet */
+# define ASSERT_DUNNO_SEGLOCK(fs) \
+ DLOG((DLOG_SEG, "lfs func %s seglock wrong (%d)\n", __func__, \
+ LFS_SEGLOCK_HELD(fs)))
+# define ASSERT_SEGLOCK(fs) do { \
+ if (!LFS_SEGLOCK_HELD(fs)) { \
+ DLOG((DLOG_SEG, "lfs func %s seglock wrong (0)\n", __func__)); \
+ } \
+} while(0)
+# define ASSERT_NO_SEGLOCK(fs) do { \
+ if (LFS_SEGLOCK_HELD(fs)) { \
+ DLOG((DLOG_SEG, "lfs func %s seglock wrong (1)\n", __func__)); \
+ } \
+} while(0)
+# define ASSERT_MAYBE_SEGLOCK(x)
+#endif /* !notyet */
+
+__BEGIN_DECLS
+void lfs_itimes(struct inode *, const struct timespec *,
+ const struct timespec *, const struct timespec *);
+__END_DECLS
+
+#endif /* !_UFS_LFS_LFS_H_ */
--- /dev/null
+/* $NetBSD: lfs_extern.h,v 1.96 2008/06/28 01:34:05 rumble Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Konrad E. Schroder <perseant@hhhh.org>.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)lfs_extern.h 8.6 (Berkeley) 5/8/95
+ */
+
+#ifndef _UFS_LFS_LFS_EXTERN_H_
+#define _UFS_LFS_LFS_EXTERN_H_
+
+#ifdef _KERNEL
+#include <sys/mallocvar.h>
+
+MALLOC_DECLARE(M_SEGMENT);
+#endif
+
+/* Copied from ext2fs for ITIMES. XXX This is a bogus use of v_tag. */
+#define IS_LFS_VNODE(vp) (vp->v_tag == VT_LFS)
+
+/*
+ * Sysctl values for LFS.
+ */
+#define LFS_WRITEINDIR 1 /* flush indirect blocks on non-checkpoint writes */
+#define LFS_CLEAN_VNHEAD 2 /* put prev unrefed cleaned vnodes on head of free list */
+#define LFS_DOSTATS 3
+#define LFS_MAXPAGES 4
+#define LFS_FS_PAGETRIP 5
+#define LFS_STATS 6
+#define LFS_DO_RFW 7
+#define LFS_DEBUGLOG 8
+#define LFS_IGNORE_LAZY_SYNC 9
+#define LFS_MAXID 10
+
+struct fid;
+struct mount;
+struct nameidata;
+struct proc;
+struct statvfs;
+struct timeval;
+struct inode;
+struct uio;
+struct mbuf;
+struct ufs1_dinode;
+struct buf;
+struct vnode;
+struct dlfs;
+struct lfs;
+struct segment;
+struct block_info;
+
+#if defined(_KERNEL)
+
+extern int lfs_allclean_wakeup;
+extern struct pool lfs_inode_pool; /* memory pool for inodes */
+extern struct pool lfs_dinode_pool; /* memory pool for dinodes */
+extern struct pool lfs_inoext_pool; /* memory pool for inode extension */
+extern struct pool lfs_lbnentry_pool; /* memory pool for balloc accounting */
+
+extern int locked_queue_count;
+extern long locked_queue_bytes;
+extern int lfs_subsys_pages;
+extern int lfs_dirvcount;
+extern kmutex_t lfs_lock;
+extern int lfs_debug_log_subsys[];
+extern kcondvar_t lfs_writing_cv;
+extern kcondvar_t locked_queue_cv;
+
+__BEGIN_DECLS
+/* lfs_alloc.c */
+void lfs_vcreate(struct mount *, ino_t, struct vnode *);
+int lfs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+int lfs_vfree(struct vnode *, ino_t, int);
+void lfs_order_freelist(struct lfs *);
+int lfs_extend_ifile(struct lfs *, kauth_cred_t);
+int lfs_ialloc(struct lfs *, struct vnode *, ino_t, int, struct vnode **);
+void lfs_orphan(struct lfs *, ino_t);
+
+/* lfs_balloc.c */
+int lfs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, struct buf **);
+void lfs_register_block(struct vnode *, daddr_t);
+void lfs_deregister_block(struct vnode *, daddr_t);
+void lfs_deregister_all(struct vnode *);
+
+/* lfs_bio.c */
+int lfs_availwait(struct lfs *, int);
+int lfs_bwrite_ext(struct buf *, int);
+int lfs_fits(struct lfs *, int);
+void lfs_flush_fs(struct lfs *, int);
+void lfs_flush(struct lfs *, int, int);
+int lfs_check(struct vnode *, daddr_t, int);
+void lfs_freebuf(struct lfs *, struct buf *);
+struct buf *lfs_newbuf(struct lfs *, struct vnode *, daddr_t, size_t, int);
+void lfs_countlocked(int *, long *, const char *);
+int lfs_reserve(struct lfs *, struct vnode *, struct vnode *, int);
+
+/* lfs_debug.c */
+#ifdef DEBUG
+int lfs_bwrite_log(struct buf *, const char *, int);
+void lfs_dumplog(void);
+void lfs_dump_super(struct lfs *);
+void lfs_dump_dinode(struct ufs1_dinode *);
+void lfs_check_bpp(struct lfs *, struct segment *, char *, int);
+void lfs_check_segsum(struct lfs *, struct segment *, char *, int);
+void lfs_debug_log(int, const char *, ...);
+#endif /* DEBUG */
+
+/* lfs_inode.c */
+int lfs_update(struct vnode *, const struct timespec *, const struct timespec *,
+ int);
+int lfs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+struct ufs1_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *);
+void lfs_finalize_ino_seguse(struct lfs *, struct inode *);
+void lfs_finalize_fs_seguse(struct lfs *);
+
+/* lfs_rfw.c */
+int lfs_rf_valloc(struct lfs *, ino_t, int, struct lwp *, struct vnode **);
+void lfs_roll_forward(struct lfs *, struct mount *, struct lwp *);
+
+/* lfs_segment.c */
+void lfs_imtime(struct lfs *);
+int lfs_vflush(struct vnode *);
+int lfs_segwrite(struct mount *, int);
+int lfs_writefile(struct lfs *, struct segment *, struct vnode *);
+int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
+int lfs_gatherblock(struct segment *, struct buf *, kmutex_t *);
+int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *));
+void lfs_update_single(struct lfs *, struct segment *, struct vnode *,
+ daddr_t, int32_t, int);
+void lfs_updatemeta(struct segment *);
+int lfs_rewind(struct lfs *, int);
+void lfs_unset_inval_all(struct lfs *);
+int lfs_initseg(struct lfs *);
+int lfs_writeseg(struct lfs *, struct segment *);
+void lfs_writesuper(struct lfs *, daddr_t);
+int lfs_match_data(struct lfs *, struct buf *);
+int lfs_match_indir(struct lfs *, struct buf *);
+int lfs_match_dindir(struct lfs *, struct buf *);
+int lfs_match_tindir(struct lfs *, struct buf *);
+void lfs_callback(struct buf *);
+int lfs_vref(struct vnode *);
+void lfs_vunref(struct vnode *);
+void lfs_vunref_head(struct vnode *);
+void lfs_acquire_finfo(struct lfs *fs, ino_t, int);
+void lfs_release_finfo(struct lfs *fs);
+
+/* lfs_subr.c */
+void lfs_setup_resblks(struct lfs *);
+void lfs_pad_check(unsigned char *, int, char *, int);
+void lfs_free_resblks(struct lfs *);
+void *lfs_malloc(struct lfs *, size_t, int);
+void lfs_free(struct lfs *, void *, int);
+int lfs_seglock(struct lfs *, unsigned long);
+void lfs_segunlock(struct lfs *);
+void lfs_segunlock_relock(struct lfs *);
+int lfs_writer_enter(struct lfs *, const char *);
+void lfs_writer_leave(struct lfs *);
+void lfs_wakeup_cleaner(struct lfs *);
+
+/* lfs_syscalls.c */
+int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct ufs1_dinode *);
+struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *);
+int lfs_do_segclean(struct lfs *, unsigned long);
+int lfs_segwait(fsid_t *, struct timeval *);
+int lfs_bmapv(struct proc *, fsid_t *, struct block_info *, int);
+int lfs_markv(struct proc *, fsid_t *, struct block_info *, int);
+
+/* lfs_vfsops.c */
+void lfs_init(void);
+void lfs_reinit(void);
+void lfs_done(void);
+int lfs_mountroot(void);
+int lfs_mount(struct mount *, const char *, void *, size_t *);
+int lfs_unmount(struct mount *, int);
+int lfs_statvfs(struct mount *, struct statvfs *);
+int lfs_sync(struct mount *, int, kauth_cred_t);
+int lfs_vget(struct mount *, ino_t, struct vnode **);
+int lfs_fhtovp(struct mount *, struct fid *, struct vnode **);
+int lfs_vptofh(struct vnode *, struct fid *, size_t *);
+void lfs_vinit(struct mount *, struct vnode **);
+int lfs_resize_fs(struct lfs *, int);
+
+/* lfs_vnops.c */
+void lfs_mark_vnode(struct vnode *);
+void lfs_unmark_vnode(struct vnode *);
+int lfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+void lfs_gop_size(struct vnode *, off_t, off_t *, int);
+int lfs_putpages_ext(void *, int);
+int lfs_gatherpages(struct vnode *);
+void lfs_flush_dirops(struct lfs *);
+void lfs_flush_pchain(struct lfs *);
+
+int lfs_bwrite (void *);
+int lfs_fsync (void *);
+int lfs_symlink (void *);
+int lfs_mknod (void *);
+int lfs_create (void *);
+int lfs_mkdir (void *);
+int lfs_read (void *);
+int lfs_remove (void *);
+int lfs_rmdir (void *);
+int lfs_link (void *);
+int lfs_mmap (void *);
+int lfs_rename (void *);
+int lfs_getattr (void *);
+int lfs_setattr (void *);
+int lfs_close (void *);
+int lfsspec_close(void *);
+int lfsfifo_close(void *);
+int lfs_fcntl (void *);
+int lfs_inactive (void *);
+int lfs_reclaim (void *);
+int lfs_strategy (void *);
+int lfs_write (void *);
+int lfs_getpages (void *);
+int lfs_putpages (void *);
+
+extern int lfs_mount_type;
+extern int (**lfs_vnodeop_p)(void *);
+extern int (**lfs_specop_p)(void *);
+extern int (**lfs_fifoop_p)(void *);
+extern const struct genfs_ops lfs_genfsops;
+
+#endif /* defined(_KERNEL) */
+
+/* lfs_cksum.c */
+u_int32_t cksum(void *, size_t);
+u_int32_t lfs_cksum_part(void *, size_t, u_int32_t);
+#define lfs_cksum_fold(sum) (sum)
+u_int32_t lfs_sb_cksum(struct dlfs *);
+
+__END_DECLS
+
+#endif /* !_UFS_LFS_LFS_EXTERN_H_ */
--- /dev/null
+/* $NetBSD: mfs_extern.h,v 1.31 2010/03/02 17:20:02 pooka Exp $ */
+
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ * @(#)mfs_extern.h 8.4 (Berkeley) 3/30/95
+ */
+
+#ifndef _UFS_MFS_MFS_EXTERN_H_
+#define _UFS_MFS_MFS_EXTERN_H_
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/mallocvar.h>
+
+struct buf;
+struct mount;
+struct nameidata;
+struct proc;
+struct statvfs;
+struct vnode;
+
+__BEGIN_DECLS
+#define mfs_ioctl genfs_enoioctl
+
+/* mfs_vfsops.c */
+VFS_PROTOS(mfs);
+
+int mfs_initminiroot(void *);
+
+/* mfs_vnops.c */
+int mfs_open(void *);
+int mfs_strategy(void *);
+void mfs_doio(struct buf *, void *);
+int mfs_bmap(void *);
+int mfs_close(void *);
+int mfs_inactive(void *);
+int mfs_reclaim(void *);
+int mfs_print(void *);
+int mfs_fsync(void *);
+
+#ifdef _KERNEL
+
+#include <sys/mutex.h>
+
+extern kmutex_t mfs_lock;
+extern void *mfs_rootbase;
+extern u_long mfs_rootsize;
+
+#endif
+
+__END_DECLS
+
+#endif /* !_UFS_MFS_MFS_EXTERN_H_ */
--- /dev/null
+/* $NetBSD: mfsnode.h,v 1.21 2008/03/26 14:19:43 ad Exp $ */
+
+/*
+ * Copyright (c) 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.
+ *
+ * @(#)mfsnode.h 8.3 (Berkeley) 5/19/95
+ */
+
+#ifndef _UFS_MFS_MFSNODE_H_
+#define _UFS_MFS_MFSNODE_H_
+
+/*
+ * This structure defines the control data for the memory based file system.
+ */
+
+struct mfsnode {
+ struct vnode *mfs_vnode; /* vnode associated with this mfsnode */
+ void *mfs_baseoff; /* base of file system in memory */
+ long mfs_size; /* size of memory file system */
+ struct proc *mfs_proc; /* supporting process */
+ int mfs_shutdown; /* shutdown this mfsnode */
+#if defined(_KERNEL)
+ kcondvar_t mfs_cv; /* notifier */
+ int mfs_refcnt; /* number of references */
+ struct bufq_state *mfs_buflist;/* list of I/O requests */
+#endif /* defined(_KERNEL) */
+};
+
+#if defined(_KERNEL)
+/*
+ * Convert between mfsnode pointers and vnode pointers
+ */
+#define VTOMFS(vp) ((struct mfsnode *)(vp)->v_data)
+#define MFSTOV(mfsp) ((mfsp)->mfs_vnode)
+
+/* Prototypes for MFS operations on vnodes. */
+#define mfs_lookup genfs_badop
+#define mfs_create genfs_badop
+#define mfs_mknod genfs_badop
+#define mfs_access genfs_badop
+#define mfs_getattr genfs_badop
+#define mfs_setattr genfs_badop
+#define mfs_read genfs_badop
+#define mfs_write genfs_badop
+#define mfs_poll genfs_badop
+#define mfs_mmap genfs_badop
+#define mfs_seek genfs_badop
+#define mfs_remove genfs_badop
+#define mfs_link genfs_badop
+#define mfs_rename genfs_badop
+#define mfs_mkdir genfs_badop
+#define mfs_rmdir genfs_badop
+#define mfs_symlink genfs_badop
+#define mfs_readdir genfs_badop
+#define mfs_readlink genfs_badop
+#define mfs_abortop genfs_badop
+#define mfs_islocked genfs_noislocked
+#define mfs_pathconf genfs_badop
+#define mfs_advlock genfs_badop
+#define mfs_bwrite vn_bwrite
+#define mfs_revoke genfs_revoke
+#define mfs_putpages genfs_null_putpages
+
+#endif /* defined(_KERNEL) */
+
+#endif /* !_UFS_MFS_MFSNODE_H_ */
--- /dev/null
+/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad 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, 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.
+ *
+ * @(#)dinode.h 8.9 (Berkeley) 3/29/95
+ */
+
+/*
+ * NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
+ */
+
+#ifndef _UFS_UFS_DINODE_H_
+#define _UFS_UFS_DINODE_H_
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be used for
+ * normal purposes and historically bad blocks were linked to inode 1, thus
+ * the root inode is 2. (Inode 1 is no longer used for this purpose, however
+ * numerous dump tapes make this assumption, so we are stuck with it).
+ */
+#define ROOTINO ((ino_t)2)
+
+/*
+ * The Whiteout inode# is a dummy non-zero inode number which will
+ * never be allocated to a real file. It is used as a place holder
+ * in the directory entry which has been tagged as a DT_W entry.
+ * See the comments about ROOTINO above.
+ */
+#define WINO ((ino_t)1)
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NXADDR 2
+#define NDADDR 12 /* Direct addresses in inode. */
+#define NIADDR 3 /* Indirect addresses in inode. */
+
+struct ufs1_dinode {
+ u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
+ int16_t di_nlink; /* 2: File link count. */
+ union {
+ u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
+ u_int32_t inumber; /* 4: Lfs: inode number. */
+ } di_u;
+ u_int64_t di_size; /* 8: File byte count. */
+ int32_t di_atime; /* 16: Last access time. */
+ int32_t di_atimensec; /* 20: Last access time. */
+ int32_t di_mtime; /* 24: Last modified time. */
+ int32_t di_mtimensec; /* 28: Last modified time. */
+ int32_t di_ctime; /* 32: Last inode change time. */
+ int32_t di_ctimensec; /* 36: Last inode change time. */
+ int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
+ int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
+ u_int32_t di_flags; /* 100: Status flags (chflags). */
+ u_int32_t di_blocks; /* 104: Blocks actually held. */
+ int32_t di_gen; /* 108: Generation number. */
+ u_int32_t di_uid; /* 112: File owner. */
+ u_int32_t di_gid; /* 116: File group. */
+ u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
+};
+
+struct ufs2_dinode {
+ u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
+ int16_t di_nlink; /* 2: File link count. */
+ u_int32_t di_uid; /* 4: File owner. */
+ u_int32_t di_gid; /* 8: File group. */
+ u_int32_t di_blksize; /* 12: Inode blocksize. */
+ u_int64_t di_size; /* 16: File byte count. */
+ u_int64_t di_blocks; /* 24: Bytes actually held. */
+ int64_t di_atime; /* 32: Last access time. */
+ int64_t di_mtime; /* 40: Last modified time. */
+ int64_t di_ctime; /* 48: Last inode change time. */
+ int64_t di_birthtime; /* 56: Inode creation time. */
+ int32_t di_mtimensec; /* 64: Last modified time. */
+ int32_t di_atimensec; /* 68: Last access time. */
+ int32_t di_ctimensec; /* 72: Last inode change time. */
+ int32_t di_birthnsec; /* 76: Inode creation time. */
+ int32_t di_gen; /* 80: Generation number. */
+ u_int32_t di_kernflags; /* 84: Kernel flags. */
+ u_int32_t di_flags; /* 88: Status flags (chflags). */
+ int32_t di_extsize; /* 92: External attributes block. */
+ int64_t di_extb[NXADDR];/* 96: External attributes block. */
+ int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
+ int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
+ u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
+ int64_t di_spare[2]; /* 240: Reserved; currently unused */
+};
+
+/*
+ * The di_db fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+#define di_inumber di_u.inumber
+#define di_ogid di_u.oldids[1]
+#define di_ouid di_u.oldids[0]
+#define di_rdev di_db[0]
+#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
+#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
+
+#define MAXSYMLINKLEN(ip) \
+ ((ip)->i_ump->um_fstype == UFS1) ? \
+ MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
+
+/* NeXT used to keep short symlinks in the inode even when using
+ * FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,
+ * but short symlinks were stored in inodes shorter than this:
+ */
+#define APPLEUFS_MAXSYMLINKLEN 60
+
+/* File permissions. */
+#define IEXEC 0000100 /* Executable. */
+#define IWRITE 0000200 /* Writable. */
+#define IREAD 0000400 /* Readable. */
+#define ISVTX 0001000 /* Sticky bit. */
+#define ISGID 0002000 /* Set-gid. */
+#define ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define IFMT 0170000 /* Mask of file type. */
+#define IFIFO 0010000 /* Named pipe (fifo). */
+#define IFCHR 0020000 /* Character device. */
+#define IFDIR 0040000 /* Directory file. */
+#define IFBLK 0060000 /* Block device. */
+#define IFREG 0100000 /* Regular file. */
+#define IFLNK 0120000 /* Symbolic link. */
+#define IFSOCK 0140000 /* UNIX domain socket. */
+#define IFWHT 0160000 /* Whiteout. */
+
+/* Size of the on-disk inode. */
+#define DINODE1_SIZE (sizeof(struct ufs1_dinode)) /* 128 */
+#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
+
+#endif /* !_UFS_UFS_DINODE_H_ */
--- /dev/null
+/* $NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ * @(#)dir.h 8.5 (Berkeley) 4/27/95
+ */
+
+#ifndef _UFS_UFS_DIR_H_
+#define _UFS_UFS_DIR_H_
+
+/*
+ * Theoretically, directories can be more than 2Gb in length; however, in
+ * practice this seems unlikely. So, we define the type doff_t as a 32-bit
+ * quantity to keep down the cost of doing lookup on a 32-bit machine.
+ */
+#define doff_t int32_t
+#define MAXDIRSIZE (0x7fffffff)
+
+/*
+ * A directory consists of some number of blocks of DIRBLKSIZ
+ * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZ byte block contains some number of directory entry
+ * structures, which are of variable length. Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry. These are followed by the name padded to a 4 byte boundary.
+ * All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is FFS_MAXNAMLEN.
+ *
+ * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
+ * a directory entry. Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes
+ * in a directory block are claimed by the directory entries. This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen. When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen. If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+#undef DIRBLKSIZ
+#define DIRBLKSIZ DEV_BSIZE
+#define FFS_MAXNAMLEN 255
+#define APPLEUFS_DIRBLKSIZ 1024
+
+#define d_ino d_fileno
+struct direct {
+ u_int32_t d_fileno; /* inode number of entry */
+ u_int16_t d_reclen; /* length of this record */
+ u_int8_t d_type; /* file type, see below */
+ u_int8_t d_namlen; /* length of string in d_name */
+ char d_name[FFS_MAXNAMLEN + 1];/* name with length <= FFS_MAXNAMLEN */
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTODT(mode) (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype) ((dirtype) << 12)
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry. This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#define DIRECTSIZ(namlen) \
+ ((sizeof(struct direct) - (FFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define DIRSIZ(oldfmt, dp, needswap) \
+ (((oldfmt) && !(needswap)) ? \
+ DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
+#else
+#define DIRSIZ(oldfmt, dp, needswap) \
+ (((oldfmt) && (needswap)) ? \
+ DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
+#endif
+
+#define OLDDIRFMT 1
+#define NEWDIRFMT 0
+
+/*
+ * Template for manipulating directories. Should use struct direct's,
+ * but the name field is FFS_MAXNAMLEN - 1, and this just won't do.
+ */
+struct dirtemplate {
+ u_int32_t dot_ino;
+ int16_t dot_reclen;
+ u_int8_t dot_type;
+ u_int8_t dot_namlen;
+ char dot_name[4]; /* must be multiple of 4 */
+ u_int32_t dotdot_ino;
+ int16_t dotdot_reclen;
+ u_int8_t dotdot_type;
+ u_int8_t dotdot_namlen;
+ char dotdot_name[4]; /* ditto */
+};
+
+/*
+ * This is the old format of directories, sanz type element.
+ */
+struct odirtemplate {
+ u_int32_t dot_ino;
+ int16_t dot_reclen;
+ u_int16_t dot_namlen;
+ char dot_name[4]; /* must be multiple of 4 */
+ u_int32_t dotdot_ino;
+ int16_t dotdot_reclen;
+ u_int16_t dotdot_namlen;
+ char dotdot_name[4]; /* ditto */
+};
+#endif /* !_UFS_UFS_DIR_H_ */
--- /dev/null
+/* $NetBSD: dirhash.h,v 1.6 2008/06/04 11:33:19 ad Exp $ */
+
+/*
+ * Copyright (c) 2001 Ian Dowse. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/ufs/ufs/dirhash.h,v 1.2.2.2 2004/12/08 11:54:13 dwmalone Exp $
+ */
+
+#ifndef _UFS_UFS_DIRHASH_H_
+#define _UFS_UFS_DIRHASH_H_
+
+/*
+ * For fast operations on large directories, we maintain a hash
+ * that maps the file name to the offset of the directory entry within
+ * the directory file.
+ *
+ * The hashing uses a dumb spillover to the next free slot on
+ * collisions, so we must keep the utilisation low to avoid
+ * long linear searches. Deleted entries that are not the last
+ * in a chain must be marked DIRHASH_DEL.
+ *
+ * We also maintain information about free space in each block
+ * to speed up creations.
+ */
+#define DIRHASH_EMPTY (-1) /* entry unused */
+#define DIRHASH_DEL (-2) /* deleted entry; may be part of chain */
+
+#define DIRALIGN 4
+#define DH_NFSTATS (DIRECTSIZ(FFS_MAXNAMLEN + 1) / DIRALIGN)
+ /* max DIRALIGN words in a directory entry */
+
+/*
+ * Dirhash uses a score mechanism to achieve a hybrid between a
+ * least-recently-used and a least-often-used algorithm for entry
+ * recycling. The score is incremented when a directory is used, and
+ * decremented when the directory is a candidate for recycling. When
+ * the score reaches zero, the hash is recycled. Hashes are linked
+ * together on a TAILQ list, and hashes with higher scores filter
+ * towards the tail (most recently used) end of the list.
+ *
+ * New hash entries are given an inital score of DH_SCOREINIT and are
+ * placed at the most-recently-used end of the list. This helps a lot
+ * in the worst-case case scenario where every directory access is
+ * to a directory that is not hashed (i.e. the working set of hash
+ * candidates is much larger than the configured memry limit). In this
+ * case it limits the number of hash builds to 1/DH_SCOREINIT of the
+ * number of accesses.
+ */
+#define DH_SCOREINIT 8 /* initial dh_score when dirhash built */
+#define DH_SCOREMAX 64 /* max dh_score value */
+
+/*
+ * The main hash table has 2 levels. It is an array of pointers to
+ * blocks of DH_NBLKOFF offsets.
+ */
+#define DH_BLKOFFSHIFT 8
+#define DH_NBLKOFF (1 << DH_BLKOFFSHIFT)
+#define DH_BLKOFFMASK (DH_NBLKOFF - 1)
+
+#define DH_ENTRY(dh, slot) \
+ ((dh)->dh_hash[(slot) >> DH_BLKOFFSHIFT][(slot) & DH_BLKOFFMASK])
+
+struct dirhash {
+ kmutex_t dh_lock; /* protects all fields except dh_list */
+
+ doff_t **dh_hash; /* the hash array (2-level) */
+ size_t dh_hashsz;
+ int dh_narrays; /* number of entries in dh_hash */
+ int dh_hlen; /* total slots in the 2-level hash array */
+ int dh_hused; /* entries in use */
+
+ u_int8_t *dh_blkfree; /* free DIRALIGN words in each dir block */
+ size_t dh_blkfreesz;
+ int dh_nblk; /* size of dh_blkfree array */
+ int dh_dirblks; /* number of DIRBLKSIZ blocks in dir */
+ int dh_firstfree[DH_NFSTATS + 1]; /* first blk with N words free */
+
+ int dh_seqopt; /* sequential access optimisation enabled */
+ doff_t dh_seqoff; /* sequential access optimisation offset */
+
+ int dh_score; /* access count for this dirhash */
+
+ int dh_onlist; /* true if on the ufsdirhash_list chain */
+
+ /* Protected by ufsdirhash_lock. */
+ TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */
+};
+
+
+/*
+ * Dirhash functions.
+ */
+int ufsdirhash_build(struct inode *);
+doff_t ufsdirhash_findfree(struct inode *, int, int *);
+doff_t ufsdirhash_enduseful(struct inode *);
+int ufsdirhash_lookup(struct inode *, const char *, int, doff_t *,
+ struct buf **, doff_t *);
+void ufsdirhash_newblk(struct inode *, doff_t);
+void ufsdirhash_add(struct inode *, struct direct *, doff_t);
+void ufsdirhash_remove(struct inode *, struct direct *, doff_t);
+void ufsdirhash_move(struct inode *, struct direct *, doff_t, doff_t);
+void ufsdirhash_dirtrunc(struct inode *, doff_t);
+void ufsdirhash_free(struct inode *);
+void ufsdirhash_checkblock(struct inode *, char *, doff_t);
+void ufsdirhash_init(void);
+void ufsdirhash_done(void);
+
+#endif /* !_UFS_UFS_DIRHASH_H_ */
--- /dev/null
+/* $NetBSD: extattr.h,v 1.10 2011/10/09 21:15:34 chs Exp $ */
+
+/*-
+ * Copyright (c) 1999-2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/ufs/ufs/extattr.h,v 1.20 2005/01/31 08:16:45 imp Exp $
+ */
+
+/*
+ * Support for file system extended attributes on the UFS1 file system.
+ * Developed by the TrustedBSD Project.
+ */
+
+#ifndef _UFS_UFS_EXTATTR_H_
+#define _UFS_UFS_EXTATTR_H_
+
+#define UFS_EXTATTR_MAGIC 0x00b5d5ec
+#define UFS_EXTATTR_VERSION 0x00000003
+#define UFS_EXTATTR_FSROOTSUBDIR ".attribute"
+#define UFS_EXTATTR_SUBDIR_SYSTEM "system"
+#define UFS_EXTATTR_SUBDIR_USER "user"
+#define UFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */
+
+#define UFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */
+#define UFS_EXTATTR_PERM_KERNEL 0x00000000
+#define UFS_EXTATTR_PERM_ROOT 0x00000001
+#define UFS_EXTATTR_PERM_OWNER 0x00000002
+#define UFS_EXTATTR_PERM_ANYONE 0x00000003
+
+#define UFS_EXTATTR_UEPM_INITIALIZED 0x00000001
+#define UFS_EXTATTR_UEPM_STARTED 0x00000002
+
+#define UFS_EXTATTR_CMD_START EXTATTR_CMD_START
+#define UFS_EXTATTR_CMD_STOP EXTATTR_CMD_STOP
+#define UFS_EXTATTR_CMD_ENABLE 0x00000003
+#define UFS_EXTATTR_CMD_DISABLE 0x00000004
+
+struct ufs_extattr_fileheader {
+ uint32_t uef_magic; /* magic number for sanity checking */
+ uint32_t uef_version; /* version of attribute file */
+ uint32_t uef_size; /* size of attributes, w/o header */
+};
+
+struct ufs_extattr_header {
+ uint32_t ueh_flags; /* flags for attribute */
+ uint32_t ueh_len; /* local defined length; <= uef_size */
+ uint32_t ueh_i_gen; /* generation number for sanity */
+ /* data follows the header */
+};
+
+#ifdef _KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_EXTATTR);
+#endif
+
+struct vnode;
+LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
+struct ufs_extattr_list_entry {
+ LIST_ENTRY(ufs_extattr_list_entry) uele_entries;
+ struct ufs_extattr_fileheader uele_fileheader;
+ int uele_attrnamespace;
+ char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
+ struct vnode *uele_backing_vnode;
+ int uele_flags;
+};
+
+/* uele_flags */
+#define UELE_F_NEEDSWAP 0x01 /* needs byte swap */
+
+#define UELE_NEEDSWAP(uele) ((uele)->uele_flags & UELE_F_NEEDSWAP)
+
+struct lock;
+struct ufs_extattr_per_mount {
+ kmutex_t uepm_lock;
+ struct ufs_extattr_list_head uepm_list;
+ kauth_cred_t uepm_ucred;
+ int uepm_lockcnt;
+ int uepm_flags;
+};
+
+void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
+void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
+int ufs_extattr_start(struct mount *mp, struct lwp *l);
+int ufs_extattr_autostart(struct mount *mp, struct lwp *l);
+void ufs_extattr_stop(struct mount *mp, struct lwp *l);
+int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
+ int attrnamespace, const char *attrname);
+struct vop_getextattr_args;
+int ufs_getextattr(struct vop_getextattr_args *ap);
+struct vop_deleteextattr_args;
+int ufs_deleteextattr(struct vop_deleteextattr_args *ap);
+struct vop_setextattr_args;
+int ufs_setextattr(struct vop_setextattr_args *ap);
+struct vop_listextattr_args;
+int ufs_listextattr(struct vop_listextattr_args *ap);
+void ufs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l);
+
+void ufs_extattr_init(void);
+void ufs_extattr_done(void);
+
+#endif /* !_KERNEL */
+
+#endif /* !_UFS_UFS_EXTATTR_H_ */
--- /dev/null
+/* $NetBSD: inode.h,v 1.58 2011/07/12 02:22:13 dholland 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
+ */
+
+#ifndef _UFS_UFS_INODE_H_
+#define _UFS_UFS_INODE_H_
+
+#include <sys/vnode.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <miscfs/genfs/genfs_node.h>
+
+/*
+ * Lookup result state (other than the result inode). This is
+ * currently stashed in the vnode between VOP_LOOKUP and directory
+ * operation VOPs, which is gross.
+ */
+struct ufs_lookup_results {
+ int32_t ulr_count; /* Size of free slot in directory. */
+ doff_t ulr_endoff; /* End of useful stuff in directory. */
+ doff_t ulr_diroff; /* Offset in dir, where we found last entry. */
+ doff_t ulr_offset; /* Offset of free space in directory. */
+ u_int32_t ulr_reclen; /* Size of found directory entry. */
+};
+
+/* notyet XXX */
+#define UFS_CHECK_CRAPCOUNTER(dp) ((void)(dp)->i_crapcounter)
+
+/*
+ * Per-filesystem inode extensions.
+ */
+struct ffs_inode_ext {
+ daddr_t *ffs_snapblklist; /* Collect expunged snapshot blocks. */
+ /* follow two fields are used by contiguous allocation code only. */
+ daddr_t ffs_first_data_blk; /* first data block on disk. */
+ daddr_t ffs_first_indir_blk; /* first indirect block on disk. */
+};
+
+struct ext2fs_inode_ext {
+ daddr_t ext2fs_last_lblk; /* last logical block allocated */
+ daddr_t ext2fs_last_blk; /* last block allocated on disk */
+};
+
+struct lfs_inode_ext;
+
+/*
+ * The inode is used to describe each active (or recently active) file in the
+ * UFS filesystem. It is composed of two types of information. The first part
+ * is the information that is needed only while the file is active (such as
+ * the identity of the file and linkage to speed its lookup). The second part
+ * is the permanent meta-data associated with the file which is read in
+ * from the permanent dinode from long term storage when the file becomes
+ * active, and is put back when the file is no longer being used.
+ */
+struct inode {
+ struct genfs_node i_gnode;
+ LIST_ENTRY(inode) i_hash;/* Hash chain. */
+ TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
+ struct vnode *i_vnode; /* Vnode associated with this inode. */
+ struct ufsmount *i_ump; /* Mount point associated with this inode. */
+ struct vnode *i_devvp; /* Vnode for block I/O. */
+ u_int32_t i_flag; /* flags, see below */
+ dev_t i_dev; /* Device associated with the inode. */
+ ino_t i_number; /* The identity of the inode. */
+
+ union { /* Associated filesystem. */
+ struct fs *fs; /* FFS */
+ struct lfs *lfs; /* LFS */
+ struct m_ext2fs *e2fs; /* EXT2FS */
+ } inode_u;
+#define i_fs inode_u.fs
+#define i_lfs inode_u.lfs
+#define i_e2fs inode_u.e2fs
+
+ void *i_unused1; /* Unused. */
+ struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
+ u_quad_t i_modrev; /* Revision level for NFS lease. */
+ struct lockf *i_lockf;/* Head of byte-level lock list. */
+
+ /*
+ * Side effects; used during (and after) directory lookup.
+ * XXX should not be here.
+ */
+ struct ufs_lookup_results i_crap;
+ unsigned i_crapcounter; /* serial number for i_crap */
+
+ /*
+ * Inode extensions
+ */
+ union {
+ /* Other extensions could go here... */
+ struct ffs_inode_ext ffs;
+ struct ext2fs_inode_ext e2fs;
+ struct lfs_inode_ext *lfs;
+ } inode_ext;
+#define i_snapblklist inode_ext.ffs.ffs_snapblklist
+#define i_ffs_first_data_blk inode_ext.ffs.ffs_first_data_blk
+#define i_ffs_first_indir_blk inode_ext.ffs.ffs_first_indir_blk
+#define i_e2fs_last_lblk inode_ext.e2fs.ext2fs_last_lblk
+#define i_e2fs_last_blk inode_ext.e2fs.ext2fs_last_blk
+ /*
+ * Copies from the on-disk dinode itself.
+ *
+ * These fields are currently only used by FFS and LFS,
+ * do NOT use them with ext2fs.
+ */
+ u_int16_t i_mode; /* IFMT, permissions; see below. */
+ int16_t i_nlink; /* File link count. */
+ u_int64_t i_size; /* File byte count. */
+ u_int32_t i_flags; /* Status flags (chflags). */
+ int32_t i_gen; /* Generation number. */
+ u_int32_t i_uid; /* File owner. */
+ u_int32_t i_gid; /* File group. */
+ u_int16_t i_omode; /* Old mode, for ufs_reclaim. */
+
+ struct dirhash *i_dirhash; /* Hashing for large directories */
+
+ /*
+ * The on-disk dinode itself.
+ */
+ union {
+ struct ufs1_dinode *ffs1_din; /* 128 bytes of the on-disk dinode. */
+ struct ufs2_dinode *ffs2_din;
+ struct ext2fs_dinode *e2fs_din; /* 128 bytes of the on-disk
+ dinode. */
+ } i_din;
+};
+
+#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_ffs1_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_size i_din.ffs1_din->di_size
+#define i_ffs1_uid i_din.ffs1_din->di_uid
+#define i_ffs1_ouid i_din.ffs1_din->di_u.oldids[0]
+#define i_ffs1_ogid i_din.ffs1_din->di_u.oldids[1]
+
+#define i_ffs2_atime i_din.ffs2_din->di_atime
+#define i_ffs2_atimensec i_din.ffs2_din->di_atimensec
+#define i_ffs2_birthtime i_din.ffs2_din->di_birthtime
+#define i_ffs2_birthnsec i_din.ffs2_din->di_birthnsec
+#define i_ffs2_blocks i_din.ffs2_din->di_blocks
+#define i_ffs2_blksize i_din.ffs2_din->di_blksize
+#define i_ffs2_ctime i_din.ffs2_din->di_ctime
+#define i_ffs2_ctimensec i_din.ffs2_din->di_ctimensec
+#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_ffs2_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_size i_din.ffs2_din->di_size
+#define i_ffs2_uid i_din.ffs2_din->di_uid
+#define i_ffs2_kernflags i_din.ffs2_din->di_kernflags
+#define i_ffs2_extsize i_din.ffs2_din->di_extsize
+#define i_ffs2_extb i_din.ffs2_din->di_extb
+
+#define i_e2fs_mode i_din.e2fs_din->e2di_mode
+#define i_e2fs_uid i_din.e2fs_din->e2di_uid
+#define i_e2fs_size i_din.e2fs_din->e2di_size
+#define i_e2fs_atime i_din.e2fs_din->e2di_atime
+#define i_e2fs_ctime i_din.e2fs_din->e2di_ctime
+#define i_e2fs_mtime i_din.e2fs_din->e2di_mtime
+#define i_e2fs_dtime i_din.e2fs_din->e2di_dtime
+#define i_e2fs_gid i_din.e2fs_din->e2di_gid
+#define i_e2fs_nlink i_din.e2fs_din->e2di_nlink
+#define i_e2fs_nblock i_din.e2fs_din->e2di_nblock
+#define i_e2fs_flags i_din.e2fs_din->e2di_flags
+#define i_e2fs_blocks i_din.e2fs_din->e2di_blocks
+#define i_e2fs_gen i_din.e2fs_din->e2di_gen
+#define i_e2fs_facl i_din.e2fs_din->e2di_facl
+#define i_e2fs_dacl i_din.e2fs_din->e2di_dacl
+#define i_e2fs_faddr i_din.e2fs_din->e2di_faddr
+#define i_e2fs_nfrag i_din.e2fs_din->e2di_nfrag
+#define i_e2fs_fsize i_din.e2fs_din->e2di_fsize
+#define i_e2fs_rdev i_din.e2fs_din->e2di_rdev
+#define i_e2fs_uid_high i_din.e2fs_din->e2di_uid_high
+#define i_e2fs_gid_high i_din.e2fs_din->e2di_gid_high
+
+/* These flags are kept in i_flag. */
+#define IN_ACCESS 0x0001 /* Access time update request. */
+#define IN_CHANGE 0x0002 /* Inode change time update request. */
+#define IN_UPDATE 0x0004 /* Inode was written to; update mtime. */
+#define IN_MODIFY 0x2000 /* Modification time update request. */
+#define IN_MODIFIED 0x0008 /* Inode has been modified. */
+#define IN_ACCESSED 0x0010 /* Inode has been accessed. */
+#define IN_RENAME 0x0020 /* Inode is being renamed. */
+#define IN_SHLOCK 0x0040 /* File has shared lock. */
+#define IN_EXLOCK 0x0080 /* File has exclusive lock. */
+#define IN_CLEANING 0x0100 /* LFS: file is being cleaned */
+#define IN_ADIROP 0x0200 /* LFS: dirop in progress */
+#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */
+#define IN_PAGING 0x1000 /* LFS: file is on paging queue */
+
+#if defined(_KERNEL)
+
+/*
+ * The DIP macro is used to access fields in the dinode that are
+ * not cached in the inode itself.
+ */
+#define DIP(ip, field) \
+ (((ip)->i_ump->um_fstype == UFS1) ? \
+ (ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
+
+#define DIP_ASSIGN(ip, field, value) \
+ do { \
+ if ((ip)->i_ump->um_fstype == UFS1) \
+ (ip)->i_ffs1_##field = (value); \
+ else \
+ (ip)->i_ffs2_##field = (value); \
+ } while(0)
+
+#define DIP_ADD(ip, field, value) \
+ do { \
+ if ((ip)->i_ump->um_fstype == UFS1) \
+ (ip)->i_ffs1_##field += (value); \
+ else \
+ (ip)->i_ffs2_##field += (value); \
+ } while(0)
+
+#define SHORTLINK(ip) \
+ (((ip)->i_ump->um_fstype == UFS1) ? \
+ (void *)(ip)->i_ffs1_db : (void *)(ip)->i_ffs2_db)
+
+
+/*
+ * 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. */
+ int in_exists; /* Flag if the block exists. */
+};
+
+/* Convert between inode pointers and vnode pointers. */
+#define VTOI(vp) ((struct inode *)(vp)->v_data)
+#define ITOV(ip) ((ip)->i_vnode)
+
+/* This overlays the fid structure (see fstypes.h). */
+struct ufid {
+ u_int16_t ufid_len; /* Length of structure. */
+ u_int16_t ufid_pad; /* Force 32-bit alignment. */
+ u_int32_t ufid_ino; /* File number (ino). */
+ int32_t ufid_gen; /* Generation number. */
+};
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_INODE_H_ */
--- /dev/null
+/* $NetBSD: quota.h,v 1.28 2011/03/25 10:25:17 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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.
+ *
+ * @(#)quota.h 8.3 (Berkeley) 8/19/94
+ */
+
+#ifndef _UFS_UFS_QUOTA_H_
+#define _UFS_UFS_QUOTA_H_
+
+/*
+ * These definitions are common to the original disk quota implementation
+ * (quota1) and the newer implementation (quota2)
+ */
+
+/*
+ * The following constants define the usage of the quota file array in the
+ * ufsmount structure and dquot array in the inode structure. The semantics
+ * of the elements of these arrays are defined in the routine getinoquota;
+ * the remainder of the quota code treats them generically and need not be
+ * inspected when changing the size of the array.
+ */
+#define MAXQUOTAS 2
+#define USRQUOTA 0 /* element used for user quotas */
+#define GRPQUOTA 1 /* element used for group quotas */
+
+
+#if !defined(HAVE_NBTOOL_CONFIG_H)
+#include <quota/quotaprop.h>
+__inline static int __unused
+ufsclass2qtype(int class)
+{
+ switch(class) {
+ case QUOTA_CLASS_USER:
+ return USRQUOTA;
+ case QUOTA_CLASS_GROUP:
+ return GRPQUOTA;
+ default:
+ return -1;
+ }
+}
+
+static __inline int __unused
+qtype2ufsclass(int type)
+{
+ switch(type) {
+ case USRQUOTA:
+ return QUOTA_CLASS_USER;
+ case GRPQUOTA:
+ return QUOTA_CLASS_GROUP;
+ default:
+ return -1;
+ }
+}
+#endif /* !defined(HAVE_NBTOOL_CONFIG_H) */
+
+#ifdef _KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void dqinit(void);
+void dqreinit(void);
+void dqdone(void);
+__END_DECLS
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_QUOTA_H_ */
--- /dev/null
+/* $NetBSD: quota1.h,v 1.5 2011/11/25 16:55:05 dholland Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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.
+ *
+ * @(#)quota.h 8.3 (Berkeley) 8/19/94
+ */
+
+#ifndef _UFS_UFS_QUOTA1_H_
+#define _UFS_UFS_QUOTA1_H_
+
+#include <sys/quota.h>
+#include <ufs/ufs/quota.h>
+
+/*
+ * These definitions are for the original disk quota implementation, which
+ * is deprecated. the newer implementation is defined in quota2.h
+ * and friends
+ */
+
+/*
+ * Definitions for the default names of the quotas files/quota types.
+ */
+#define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
+}
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits UNIX).
+ *
+ * The following constants define the amount of time given a user before the
+ * soft limits are treated as hard limits (usually resulting in an allocation
+ * failure). The timer is started when the user crosses their soft limit, it
+ * is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME (7*24*60*60) /* seconds in 1 week */
+#define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "operator"
+
+/*
+ * Command definitions for the 'compat_50_quotactl' system call. The commands
+ * are broken into a main command defined below and a subcommand that is used
+ * to convey the type of quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK 0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_QUOTAON 0x0100 /* enable quotas */
+#define Q_QUOTAOFF 0x0200 /* disable quotas */
+#define Q_GETQUOTA 0x0300 /* get limits and usage */
+#define Q_SETQUOTA 0x0400 /* set limits and usage */
+#define Q_SETUSE 0x0500 /* set usage */
+#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number. The setquota system call establishes
+ * the vnode for each quota file (a pointer is retained in the ufsmount
+ * structure).
+ */
+struct dqblk {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ int32_t dqb_btime; /* time limit for excessive disk use */
+ int32_t dqb_itime; /* time limit for excessive files */
+};
+
+/* quota1_subr.c */
+struct quota2_entry;
+void dqblk_to_quotaval(const struct dqblk *, struct quotaval *);
+void quotaval_to_dqblk(const struct quotaval *, struct dqblk *);
+
+#endif /* !_UFS_UFS_QUOTA1_H_ */
--- /dev/null
+/* $NetBSD: quota2.h,v 1.5 2011/06/07 14:56:13 bouyer Exp $ */
+/*-
+ * Copyright (c) 2010 Manuel Bouyer
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _UFS_UFS_QUOTA2_H_
+#define _UFS_UFS_QUOTA2_H_
+#include <ufs/ufs/quota.h>
+#include <quota/quota.h>
+
+
+/* New disk quota implementation. In this implementation, the quota datas
+ * (default values, user limits and current usage) are part of the filesystem
+ * metadata. On FFS, this will be in a hidden, unlinked inode. fsck_ffs is
+ * responsible for checking quotas with the rest of the filesystem integrity,
+ * and quotas metadata are also covered by the filesystem journal if any.
+ * quota enable/disable is done on a filesystem basis via flags in the
+ * superblock
+ */
+
+/*
+ * The quota file is comprised of 2 parts, the header and the entries.
+ * The header contains global informations, and head of list of quota entries.
+ * A quota entry can either be in the free list, or one of the hash lists.
+ */
+
+/* description of a block or inode quota */
+struct quota2_val {
+ uint64_t q2v_hardlimit; /* absolute limit */
+ uint64_t q2v_softlimit; /* overflowable limit */
+ uint64_t q2v_cur; /* current usage */
+ int64_t q2v_time; /* grace expiration date for softlimit overflow */
+ int64_t q2v_grace; /* allowed time for softlimit overflow */
+};
+
+/* NAMES for the above in the plist */
+#define INITQVNAMES_ALL { \
+ QUOTADICT_LIMIT_HARD, \
+ QUOTADICT_LIMIT_SOFT, \
+ QUOTADICT_LIMIT_USAGE, \
+ QUOTADICT_LIMIT_ETIME, \
+ QUOTADICT_LIMIT_GTIME \
+ }
+#define INITQVNAMES_LIMITSONLY { \
+ QUOTADICT_LIMIT_HARD, \
+ QUOTADICT_LIMIT_SOFT, \
+ NULL, \
+ NULL, \
+ QUOTADICT_LIMIT_GTIME \
+ }
+
+#define N_QV 5
+/*
+ * On-disk description of a user or group quota
+ * These entries are keept as linked list, either in one of the hash HEAD,
+ * or in the free list.
+ */
+
+#define N_QL 2
+#define QL_BLOCK 0
+#define QL_FILE 1
+#define INITQLNAMES {QUOTADICT_LTYPE_BLOCK, QUOTADICT_LTYPE_FILE}
+
+struct quota2_entry {
+ /* block & inode limits and status */
+ struct quota2_val q2e_val[N_QL];
+ /* pointer to next entry for this list (offset in the file) */
+ uint64_t q2e_next;
+ /* ownership information */
+ uint32_t q2e_uid;
+ uint32_t q2e_pad;
+};
+
+/* header present at the start of the quota file */
+struct quota2_header {
+ uint32_t q2h_magic_number;
+ uint8_t q2h_type; /* quota type, see below */
+ uint8_t q2h_hash_shift; /* bytes used for hash index */
+ uint16_t q2h_hash_size; /* size of hash table */
+ /* default values applied to new entries */
+ struct quota2_entry q2h_defentry;
+ /* head of free quota2_entry list */
+ uint64_t q2h_free;
+ /* variable-sized hash table */
+ uint64_t q2h_entries[0];
+};
+
+#define Q2_HEAD_MAGIC 0xb746915e
+
+/* superblock flags */
+#define FS_Q2_DO_TYPE(type) (0x01 << (type))
+
+#define off2qindex(hsize, off) (((off) - (hsize)) / sizeof(struct quota2_entry))
+#define qindex2off(hsize, idx) \
+ ((daddr_t)(idx) * sizeof(struct quota2_entry) + (hsize))
+
+/* quota2_subr.c */
+void quota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int);
+void quota2_create_blk0(uint64_t, void *bp, int, int, int);
+void quota2_ufs_rwq2v(const struct quota2_val *, struct quota2_val *, int);
+void quota2_ufs_rwq2e(const struct quota2_entry *, struct quota2_entry *, int);
+
+__inline static int __unused
+quota2_check_limit(struct quota2_val *q2v, uint64_t change, time_t now)
+{
+ return quota_check_limit(q2v->q2v_cur, change, q2v->q2v_softlimit,
+ q2v->q2v_hardlimit, q2v->q2v_time, now);
+}
+#endif /* _UFS_UFS_QUOTA2_H_ */
--- /dev/null
+/* $NetBSD: ufs_bswap.h,v 1.19 2009/10/19 18:41:17 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _UFS_UFS_BSWAP_H_
+#define _UFS_UFS_BSWAP_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_ffs.h"
+#endif
+
+#include <sys/bswap.h>
+
+/* Macros to access UFS flags */
+#ifdef FFS_EI
+#define UFS_MPNEEDSWAP(ump) ((ump)->um_flags & UFS_NEEDSWAP)
+#define UFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED)
+#define UFS_IPNEEDSWAP(ip) UFS_MPNEEDSWAP((ip)->i_ump)
+#else
+#define UFS_MPNEEDSWAP(ump) (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(uint16_t a, int ns)
+{
+ return ((ns) ? bswap16(a) : (a));
+}
+
+static inline u_int32_t
+ufs_rw32(uint32_t a, int ns)
+{
+ return ((ns) ? bswap32(a) : (a));
+}
+
+static inline u_int64_t
+ufs_rw64(uint64_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_ */
--- /dev/null
+/* $NetBSD: ufs_extern.h,v 1.66 2011/07/17 22:07:59 dholland 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.
+ *
+ * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95
+ */
+
+#ifndef _UFS_UFS_EXTERN_H_
+#define _UFS_UFS_EXTERN_H_
+
+#include <sys/mutex.h>
+
+struct buf;
+struct componentname;
+struct direct;
+struct disklabel;
+struct dquot;
+struct fid;
+struct flock;
+struct indir;
+struct inode;
+struct mbuf;
+struct mount;
+struct nameidata;
+struct lwp;
+struct ufid;
+struct ufs_args;
+struct ufs_lookup_results;
+struct ufsmount;
+struct uio;
+struct vattr;
+struct vnode;
+
+extern pool_cache_t ufs_direct_cache; /* memory pool for directs */
+
+__BEGIN_DECLS
+#define ufs_abortop genfs_abortop
+int ufs_access(void *);
+int ufs_advlock(void *);
+int ufs_bmap(void *);
+int ufs_close(void *);
+int ufs_create(void *);
+int ufs_getattr(void *);
+int ufs_inactive(void *);
+#define ufs_fcntl genfs_fcntl
+#define ufs_ioctl genfs_enoioctl
+#define ufs_islocked genfs_islocked
+int ufs_link(void *);
+#define ufs_lock genfs_lock
+int ufs_lookup(void *);
+int ufs_mkdir(void *);
+int ufs_mknod(void *);
+#define ufs_mmap genfs_mmap
+#define ufs_revoke genfs_revoke
+int ufs_open(void *);
+int ufs_pathconf(void *);
+int ufs_print(void *);
+int ufs_readdir(void *);
+int ufs_readlink(void *);
+int ufs_remove(void *);
+int ufs_rename(void *);
+int ufs_rmdir(void *);
+#define ufs_seek genfs_seek
+#define ufs_poll genfs_poll
+int ufs_setattr(void *);
+int ufs_strategy(void *);
+int ufs_symlink(void *);
+#define ufs_unlock genfs_unlock
+int ufs_whiteout(void *);
+int ufsspec_close(void *);
+int ufsspec_read(void *);
+int ufsspec_write(void *);
+
+int ufsfifo_read(void *);
+int ufsfifo_write(void *);
+int ufsfifo_close(void *);
+
+/* ufs_bmap.c */
+typedef bool (*ufs_issequential_callback_t)(const struct ufsmount *,
+ daddr_t, daddr_t);
+int ufs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *,
+ int *, int *, ufs_issequential_callback_t);
+int ufs_getlbns(struct vnode *, daddr_t, struct indir *, int *);
+
+/* ufs_ihash.c */
+void ufs_ihashinit(void);
+void ufs_ihashreinit(void);
+void ufs_ihashdone(void);
+struct vnode *ufs_ihashlookup(dev_t, ino_t);
+struct vnode *ufs_ihashget(dev_t, ino_t, int);
+void ufs_ihashins(struct inode *);
+void ufs_ihashrem(struct inode *);
+
+/* ufs_inode.c */
+int ufs_reclaim(struct vnode *);
+int ufs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int);
+
+/* ufs_lookup.c */
+void ufs_dirbad(struct inode *, doff_t, const char *);
+int ufs_dirbadentry(struct vnode *, struct direct *, int);
+void ufs_makedirentry(struct inode *, struct componentname *,
+ struct direct *);
+int ufs_direnter(struct vnode *, const struct ufs_lookup_results *,
+ struct vnode *, struct direct *,
+ struct componentname *, struct buf *);
+int ufs_dirremove(struct vnode *, const struct ufs_lookup_results *,
+ struct inode *, int, int);
+int ufs_dirrewrite(struct inode *, off_t,
+ struct inode *, ino_t, int, int, int);
+int ufs_dirempty(struct inode *, ino_t, kauth_cred_t);
+int ufs_checkpath(struct inode *, struct inode *, kauth_cred_t);
+int ufs_parentcheck(struct vnode *, struct vnode *, kauth_cred_t,
+ int *, struct vnode **);
+int ufs_blkatoff(struct vnode *, off_t, char **, struct buf **, bool);
+
+/* ufs_quota.c */
+/*
+ * Flags to chkdq() and chkiq()
+ */
+#define FORCE 0x01 /* force usage changes independent of limits */
+void ufsquota_init(struct inode *);
+void ufsquota_free(struct inode *);
+int chkdq(struct inode *, int64_t, kauth_cred_t, int);
+int chkiq(struct inode *, int32_t, kauth_cred_t, int);
+int quota_handle_cmd(struct mount *, struct lwp *, prop_dictionary_t);
+int qsync(struct mount *);
+
+/* ufs_quota1.c */
+int quota1_umount(struct mount *, int);
+
+/* ufs_quota2.c */
+int quota2_umount(struct mount *, int);
+
+/* ufs_vfsops.c */
+void ufs_init(void);
+void ufs_reinit(void);
+void ufs_done(void);
+int ufs_start(struct mount *, int);
+int ufs_root(struct mount *, struct vnode **);
+int ufs_quotactl(struct mount *, prop_dictionary_t);
+int ufs_fhtovp(struct mount *, struct ufid *, struct vnode **);
+
+/* ufs_vnops.c */
+void ufs_vinit(struct mount *, int (**)(void *),
+ int (**)(void *), struct vnode **);
+int ufs_makeinode(int, struct vnode *, const struct ufs_lookup_results *,
+ struct vnode **, struct componentname *);
+int ufs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+void ufs_gop_markupdate(struct vnode *, int);
+
+/*
+ * Snapshot function prototypes.
+ */
+
+void ffs_snapgone(struct inode *);
+
+__END_DECLS
+
+extern kmutex_t ufs_ihash_lock;
+extern kmutex_t ufs_hashlock;
+
+#endif /* !_UFS_UFS_EXTERN_H_ */
--- /dev/null
+/* $NetBSD: ufs_quota.h,v 1.2 2011/03/06 17:08:39 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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_quota.c 8.5 (Berkeley) 5/20/95
+ */
+#include <ufs/ufs/quota1.h>
+#include <ufs/ufs/quota2.h>
+
+/* link to this quota in the quota inode (for QUOTA2) */
+struct dq2_desc {
+ uint64_t dq2_lblkno; /* logical disk block holding this quota */
+ u_int dq2_blkoff; /* offset in disk block holding this quota */
+};
+
+/*
+ * The following structure records disk usage for a user or group on a
+ * filesystem. There is one allocated for each quota that exists on any
+ * filesystem for the current user or group. A cache is kept of recently
+ * used entries.
+ * Field markings and the corresponding locks:
+ * h: dqlock
+ * d: dq_interlock
+ *
+ * Lock order is: dq_interlock -> dqlock
+ * dq_interlock -> dqvp
+ */
+struct dquot {
+ LIST_ENTRY(dquot) dq_hash; /* h: hash list */
+ u_int16_t dq_flags; /* d: flags, see below */
+ u_int16_t dq_type; /* d: quota type of this dquot */
+ u_int32_t dq_cnt; /* h: count of active references */
+ u_int32_t dq_id; /* d: identifier this applies to */
+ struct ufsmount *dq_ump; /* d: filesystem this is taken from */
+ kmutex_t dq_interlock; /* d: lock this dquot */
+ union {
+ struct dqblk dq1_dqb; /* d: actual usage & quotas */
+ struct dq2_desc dq2_desc; /* d: pointer to quota data */
+ } dq_un;
+};
+
+/*
+ * Flag values.
+ */
+#define DQ_MOD 0x04 /* this quota modified since read */
+#define DQ_FAKE 0x08 /* no limits here, just usage */
+#define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */
+/*
+ * Shorthand notation.
+ */
+#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit
+#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit
+#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks
+#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit
+#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit
+#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes
+#define dq_btime dq_un.dq1_dqb.dqb_btime
+#define dq_itime dq_un.dq1_dqb.dqb_itime
+
+#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno
+#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff
+/*
+ * If the system has never checked for a quota for this file, then it is
+ * set to NODQUOT. Once a write attempt is made the inode pointer is set
+ * to reference a dquot structure.
+ */
+#define NODQUOT NULL
+
+extern kmutex_t dqlock;
+extern kcondvar_t dqcv;
+/*
+ * Quota name to error message mapping.
+ */
+const char *quotatypes[MAXQUOTAS];
+
+int getinoquota(struct inode *);
+int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **);
+void dqref(struct dquot *);
+void dqrele(struct vnode *, struct dquot *);
+void dqflush(struct vnode *);
+
+int chkdq1(struct inode *, int64_t, kauth_cred_t, int);
+int chkiq1(struct inode *, int32_t, kauth_cred_t, int);
+int q1sync(struct mount *);
+int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
+int dq1sync(struct vnode *, struct dquot *);
+int quota1_handle_cmd_get(struct ufsmount *, int, int, int, prop_array_t);
+int quota1_handle_cmd_set(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int,
+ const char *);
+int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int);
+
+int chkdq2(struct inode *, int64_t, kauth_cred_t, int);
+int chkiq2(struct inode *, int32_t, kauth_cred_t, int);
+int quota2_handle_cmd_get(struct ufsmount *, int, int, int, prop_array_t);
+int quota2_handle_cmd_set(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota2_handle_cmd_clear(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t);
+int q2sync(struct mount *);
+int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
+int dq2sync(struct vnode *, struct dquot *);
--- /dev/null
+/* $NetBSD: ufs_wapbl.h,v 1.7 2011/09/19 11:18:01 gdt Exp $ */
+
+/*-
+ * Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+
+#ifndef _UFS_UFS_UFS_WAPBL_H_
+#define _UFS_UFS_UFS_WAPBL_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_wapbl.h"
+#endif
+
+/*
+ * Information for the journal location stored in the superblock.
+ * We store the journal version, some flags, the journal location
+ * type, and some location specific "locators" that identify where
+ * the log itself is located.
+ */
+
+/* fs->fs_journal_version */
+#define UFS_WAPBL_VERSION 1
+
+/* fs->fs_journal_location */
+#define UFS_WAPBL_JOURNALLOC_NONE 0
+
+#define UFS_WAPBL_JOURNALLOC_END_PARTITION 1
+#define UFS_WAPBL_EPART_ADDR 0 /* locator slots */
+#define UFS_WAPBL_EPART_COUNT 1
+#define UFS_WAPBL_EPART_BLKSZ 2
+#define UFS_WAPBL_EPART_UNUSED 3
+
+#define UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM 2
+#define UFS_WAPBL_INFS_ADDR 0 /* locator slots */
+#define UFS_WAPBL_INFS_COUNT 1
+#define UFS_WAPBL_INFS_BLKSZ 2
+#define UFS_WAPBL_INFS_INO 3
+
+/* fs->fs_journal_flags */
+#define UFS_WAPBL_FLAGS_CREATE_LOG 0x1
+#define UFS_WAPBL_FLAGS_CLEAR_LOG 0x2
+
+
+/*
+ * The journal size is limited to between 1MB and 64MB.
+ * The default journal size is the filesystem size divided by
+ * the scale factor - this is 1M of journal per 1GB of filesystem
+ * space.
+ *
+ * XXX: Is 64MB too limiting? If user explicitly asks for more, allow it?
+ */
+#define UFS_WAPBL_JOURNAL_SCALE 1024
+#define UFS_WAPBL_MIN_JOURNAL_SIZE (1024 * 1024)
+#define UFS_WAPBL_MAX_JOURNAL_SIZE (64 * 1024 * 1024)
+
+
+#if defined(WAPBL)
+
+#if defined(WAPBL_DEBUG)
+#define WAPBL_DEBUG_INODES
+#endif
+
+#ifdef WAPBL_DEBUG_INODES
+#error Undefine WAPBL_DEBUG_INODES or update the code. Have a nice day.
+#endif
+
+#ifdef WAPBL_DEBUG_INODES
+void ufs_wapbl_verify_inodes(struct mount *, const char *);
+#endif
+
+static __inline int
+ufs_wapbl_begin2(struct mount *mp, struct vnode *vp1, struct vnode *vp2,
+ const char *file, int line)
+{
+ if (mp->mnt_wapbl) {
+ int error;
+
+ if (vp1)
+ vref(vp1);
+ if (vp2)
+ vref(vp2);
+ error = wapbl_begin(mp->mnt_wapbl, file, line);
+ if (error)
+ return error;
+#ifdef WAPBL_DEBUG_INODES
+ if (mp->mnt_wapbl->wl_lock.lk_exclusivecount == 1)
+ ufs_wapbl_verify_inodes(mp, "wapbl_begin");
+#endif
+ }
+ return 0;
+}
+
+static __inline void
+ufs_wapbl_end2(struct mount *mp, struct vnode *vp1, struct vnode *vp2)
+{
+ if (mp->mnt_wapbl) {
+#ifdef WAPBL_DEBUG_INODES
+ if (mp->mnt_wapbl->wl_lock.lk_exclusivecount == 1)
+ ufs_wapbl_verify_inodes(mp, "wapbl_end");
+#endif
+ wapbl_end(mp->mnt_wapbl);
+ if (vp2)
+ vrele(vp2);
+ if (vp1)
+ vrele(vp1);
+ }
+}
+
+#define UFS_WAPBL_BEGIN(mp) \
+ ufs_wapbl_begin2(mp, NULL, NULL, __FUNCTION__, __LINE__)
+#define UFS_WAPBL_BEGIN1(mp, v1) \
+ ufs_wapbl_begin2(mp, v1, NULL, __FUNCTION__, __LINE__)
+#define UFS_WAPBL_END(mp) ufs_wapbl_end2(mp, NULL, NULL)
+#define UFS_WAPBL_END1(mp, v1) ufs_wapbl_end2(mp, v1, NULL)
+
+#define UFS_WAPBL_UPDATE(vp, access, modify, flags) \
+ if ((vp)->v_mount->mnt_wapbl) { \
+ UFS_UPDATE(vp, access, modify, flags); \
+ }
+
+#ifdef UFS_WAPBL_DEBUG_JLOCK
+#define UFS_WAPBL_JLOCK_ASSERT(mp) \
+ if (mp->mnt_wapbl) wapbl_jlock_assert(mp->mnt_wapbl)
+#define UFS_WAPBL_JUNLOCK_ASSERT(mp) \
+ if (mp->mnt_wapbl) wapbl_junlock_assert(mp->mnt_wapbl)
+#else
+#define UFS_WAPBL_JLOCK_ASSERT(mp)
+#define UFS_WAPBL_JUNLOCK_ASSERT(mp)
+#endif
+
+#define UFS_WAPBL_REGISTER_INODE(mp, ino, mode) \
+ if (mp->mnt_wapbl) wapbl_register_inode(mp->mnt_wapbl, ino, mode)
+#define UFS_WAPBL_UNREGISTER_INODE(mp, ino, mode) \
+ if (mp->mnt_wapbl) wapbl_unregister_inode(mp->mnt_wapbl, ino, mode)
+
+#define UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len) \
+ if (mp->mnt_wapbl) wapbl_register_deallocation(mp->mnt_wapbl, blk, len)
+
+#else /* ! WAPBL */
+#define UFS_WAPBL_BEGIN(mp) 0
+#define UFS_WAPBL_BEGIN1(mp, v1) 0
+#define UFS_WAPBL_END(mp) do { } while (0)
+#define UFS_WAPBL_END1(mp, v1)
+#define UFS_WAPBL_UPDATE(vp, access, modify, flags) do { } while (0)
+#define UFS_WAPBL_JLOCK_ASSERT(mp)
+#define UFS_WAPBL_JUNLOCK_ASSERT(mp)
+#define UFS_WAPBL_REGISTER_INODE(mp, ino, mode) do { } while (0)
+#define UFS_WAPBL_UNREGISTER_INODE(mp, ino, mode) do { } while (0)
+#define UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len)
+#endif
+
+#endif /* !_UFS_UFS_UFS_WAPBL_H_ */
--- /dev/null
+/* $NetBSD: ufsmount.h,v 1.37 2011/11/24 15:51:32 ahoka 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.
+ *
+ * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
+ */
+
+#ifndef _UFS_UFS_UFSMOUNT_H_
+#define _UFS_UFS_UFSMOUNT_H_
+
+#include <sys/mount.h> /* struct export_args30 */
+
+/*
+ * Arguments to mount UFS-based filesystems
+ */
+struct ufs_args {
+ char *fspec; /* block special device to mount */
+};
+
+#ifndef __minix
+/*
+ * Arguments to mount MFS
+ */
+struct mfs_args {
+ char *fspec; /* name to export for statfs */
+ struct export_args30 _pad1; /* compat with old userland tools */
+ void * base; /* base of file system in memory */
+ u_long size; /* size of file system */
+};
+#endif
+
+#ifdef _KERNEL
+
+#if defined(_KERNEL_OPT)
+#include "opt_ffs.h"
+#endif
+
+#include <sys/mutex.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+
+struct buf;
+struct inode;
+struct nameidata;
+struct timeval;
+struct uio;
+struct vnode;
+
+/* This structure describes the UFS specific mount structure data. */
+struct ufsmount {
+ struct mount *um_mountp; /* filesystem vfs structure */
+ dev_t um_dev; /* device mounted */
+ struct vnode *um_devvp; /* block device mounted vnode */
+ u_long um_fstype;
+ u_int32_t um_flags; /* UFS-specific flags - see below */
+ union { /* pointer to superblock */
+ struct fs *fs; /* FFS */
+ struct lfs *lfs; /* LFS */
+ struct m_ext2fs *e2fs; /* EXT2FS */
+ struct chfs_mount *chfs; /* CHFS */
+ } ufsmount_u;
+#define um_fs ufsmount_u.fs
+#define um_lfs ufsmount_u.lfs
+#define um_e2fs ufsmount_u.e2fs
+#define um_e2fsb ufsmount_u.e2fs->s_es
+#define um_chfs ufsmount_u.chfs
+
+ /* Extended attribute information. */
+ struct ufs_extattr_per_mount um_extattr;
+
+ struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
+ kauth_cred_t um_cred[MAXQUOTAS]; /* quota file access cred */
+ u_long um_nindir; /* indirect ptrs per block */
+ u_long um_lognindir; /* log2 of um_nindir */
+ u_long um_bptrtodb; /* indir ptr to disk block */
+ u_long um_seqinc; /* inc between seq blocks */
+ kmutex_t um_lock; /* lock on global data */
+ union {
+ struct um_q1 {
+ time_t q1_btime[MAXQUOTAS]; /* block quota time limit */
+ time_t q1_itime[MAXQUOTAS]; /* inode quota time limit */
+ char q1_qflags[MAXQUOTAS]; /* quota specific flags */
+ } um_q1;
+ struct um_q2 {
+ uint64_t q2_bsize; /* block size of quota file */
+ uint64_t q2_bmask; /* mask for above */
+ } um_q2;
+ } um_q;
+#define umq1_btime um_q.um_q1.q1_btime
+#define umq1_itime um_q.um_q1.q1_itime
+#define umq1_qflags um_q.um_q1.q1_qflags
+#define umq2_bsize um_q.um_q2.q2_bsize
+#define umq2_bmask um_q.um_q2.q2_bmask
+
+ void *um_oldfscompat; /* save 4.2 rotbl */
+ int um_maxsymlinklen;
+ int um_dirblksiz;
+ u_int64_t um_maxfilesize;
+ void *um_snapinfo; /* snapshot private data */
+
+ const struct ufs_ops *um_ops;
+};
+
+struct ufs_ops {
+ void (*uo_itimes)(struct inode *ip, const struct timespec *,
+ const struct timespec *, const struct timespec *);
+ int (*uo_update)(struct vnode *, const struct timespec *,
+ const struct timespec *, int);
+ int (*uo_truncate)(struct vnode *, off_t, int, kauth_cred_t);
+ int (*uo_valloc)(struct vnode *, int, kauth_cred_t, struct vnode **);
+ int (*uo_vfree)(struct vnode *, ino_t, int);
+ int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int,
+ struct buf **);
+ void (*uo_unmark_vnode)(struct vnode *);
+};
+
+#define UFS_OPS(vp) (VFSTOUFS((vp)->v_mount)->um_ops)
+
+#define UFS_ITIMES(vp, acc, mod, cre) \
+ (*UFS_OPS(vp)->uo_itimes)(VTOI(vp), (acc), (mod), (cre))
+#define UFS_UPDATE(vp, acc, mod, flags) \
+ (*UFS_OPS(vp)->uo_update)((vp), (acc), (mod), (flags))
+#define UFS_TRUNCATE(vp, off, flags, cr) \
+ (*UFS_OPS(vp)->uo_truncate)((vp), (off), (flags), (cr))
+#define UFS_VALLOC(vp, mode, cr, vpp) \
+ (*UFS_OPS(vp)->uo_valloc)((vp), (mode), (cr), (vpp))
+#define UFS_VFREE(vp, ino, mode) \
+ (*UFS_OPS(vp)->uo_vfree)((vp), (ino), (mode))
+#define UFS_BALLOC(vp, off, size, cr, flags, bpp) \
+ (*UFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (bpp))
+#define UFS_UNMARK_VNODE(vp) \
+ (*UFS_OPS(vp)->uo_unmark_vnode)((vp))
+
+/* UFS-specific flags */
+#define UFS_NEEDSWAP 0x01 /* filesystem metadata need byte-swapping */
+#define UFS_ISAPPLEUFS 0x02 /* filesystem is Apple UFS */
+#define UFS_QUOTA 0x04 /* filesystem has QUOTA (v1) */
+#define UFS_QUOTA2 0x08 /* filesystem has QUOTA2 */
+
+/*
+ * Filesystem types
+ */
+#define UFS1 1
+#define UFS2 2
+
+
+/*
+ * Flags describing the state of quotas.
+ */
+#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */
+#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */
+
+/* Convert mount ptr to ufsmount ptr. */
+#define VFSTOUFS(mp) ((struct ufsmount *)((mp)->mnt_data))
+
+#ifdef APPLE_UFS
+#define UFS_MPISAPPLEUFS(ump) ((ump)->um_flags & UFS_ISAPPLEUFS)
+#else
+#define UFS_MPISAPPLEUFS(ump) (0)
+#endif
+
+/*
+ * Macros to access file system parameters in the ufsmount structure.
+ * Used by ufs_bmap.
+ */
+#define MNINDIR(ump) ((ump)->um_nindir)
+#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb)
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_UFSMOUNT_H_ */
.include <bsd.own.mk>
-SUBDIR= fsck
+SUBDIR= fsck fsck_ext2fs newfs_ext2fs
.include <bsd.subdir.mk>
if (flags & CHECK_PROGRESS)
maxrun = 1;
+#ifdef __minix
+ /* parallel checking heuristic doesn't work for minix currently */
+ maxrun = 1;
+#endif
+
argc -= optind;
argv += optind;
static const char *
getfslab(const char *str)
{
+#ifdef __minix
+ errx(1, "cannot determine vfstype under minix");
+#else
static struct dkwedge_info dkw;
struct disklabel dl;
int fd;
fstypenames[t], str);
return vfstype;
+#endif
}
static void
part2wedge(struct dkwedge_info *dkw, const struct disklabel *lp, const char *s)
{
+#ifdef __minix
+ errx(1, "minix doesn't know about wedges");
+#else
struct stat sb;
const struct partition *pp;
int ptn;
(void)strcpy(dkw->dkw_ptype, DKW_PTYPE_NTFS);
break;
}
+#endif
}
int
--- /dev/null
+# $NetBSD: Makefile,v 1.16 2011/08/06 16:42:41 dholland Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+.include <bsd.own.mk>
+
+PROG= fsck_ext2fs
+MAN= fsck_ext2fs.8
+SRCS= dir.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
+ pass5.c fsutil.c setup.c utilities.c ext2fs_bswap.c
+FSCK= ${NETBSDSRCDIR}/sbin/fsck
+CPPFLAGS+= -I${FSCK}
+.PATH: -I/usr/nbsdsrc/src/sys/ufs/ext2fs ${FSCK}
+
+SYMLINKS+= $(BINDIR)/$(PROG) $(BINDIR)/fsck.ext2
+
+.include <bsd.prog.mk>
+
+LDADD+=-lutil
+DPADD+=${LIBUTIL}
--- /dev/null
+/* $NetBSD: dir.c,v 1.23 2009/10/19 18:41:07 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dir.c 8.5 (Berkeley) 12/8/94";
+#else
+__RCSID("$NetBSD: dir.c,v 1.23 2009/10/19 18:41:07 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+
+const char *lfname = "lost+found";
+int lfmode = 01700;
+struct ext2fs_dirtemplate emptydir = {
+ .dot_ino = 0,
+ .dot_reclen = DIRBLKSIZ,
+};
+struct ext2fs_dirtemplate dirhead = {
+ .dot_ino = 0,
+ .dot_reclen = 12,
+ .dot_namlen = 1,
+ .dot_type = EXT2_FT_DIR,
+ .dot_name = ".",
+ .dotdot_ino = 0,
+ .dotdot_reclen = DIRBLKSIZ - 12,
+ .dotdot_namlen = 2,
+ .dotdot_type = EXT2_FT_DIR,
+ .dotdot_name = "..",
+};
+#undef DIRBLKSIZ
+
+static int expanddir(struct ext2fs_dinode *, char *);
+static void freedir(ino_t, ino_t);
+static struct ext2fs_direct *fsck_readdir(struct inodesc *);
+static struct bufarea *getdirblk(daddr_t, long);
+static int lftempname(char *, ino_t);
+static int mkentry(struct inodesc *);
+static int chgino(struct inodesc *);
+
+/*
+ * Propagate connected state through the tree.
+ */
+void
+propagate(void)
+{
+ struct inoinfo **inpp, *inp, *pinp;
+ struct inoinfo **inpend;
+
+ /*
+ * Create a list of children for each directory.
+ */
+ inpend = &inpsort[inplast];
+ for (inpp = inpsort; inpp < inpend; inpp++) {
+ inp = *inpp;
+ if (inp->i_parent == 0 ||
+ inp->i_number == EXT2_ROOTINO)
+ continue;
+ pinp = getinoinfo(inp->i_parent);
+ inp->i_parentp = pinp;
+ inp->i_sibling = pinp->i_child;
+ pinp->i_child = inp;
+ }
+ inp = getinoinfo(EXT2_ROOTINO);
+ while (inp) {
+ statemap[inp->i_number] = DFOUND;
+ if (inp->i_child &&
+ statemap[inp->i_child->i_number] == DSTATE)
+ inp = inp->i_child;
+ else if (inp->i_sibling)
+ inp = inp->i_sibling;
+ else
+ inp = inp->i_parentp;
+ }
+}
+
+/*
+ * Scan each entry in a directory block.
+ */
+int
+dirscan(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dp;
+ struct bufarea *bp;
+ int dsize, n;
+ long blksiz;
+ char *dbuf = NULL;
+
+ if ((dbuf = malloc(sblock.e2fs_bsize)) == NULL)
+ err(8, "Can't allocate directory block");
+
+ if (idesc->id_type != DATA)
+ errexit("wrong type to dirscan %d", idesc->id_type);
+ if (idesc->id_entryno == 0 &&
+ (idesc->id_filesize & (sblock.e2fs_bsize - 1)) != 0)
+ idesc->id_filesize = roundup(idesc->id_filesize, sblock.e2fs_bsize);
+ blksiz = idesc->id_numfrags * sblock.e2fs_bsize;
+ if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
+ idesc->id_filesize -= blksiz;
+ free(dbuf);
+ return (SKIP);
+ }
+ idesc->id_loc = 0;
+ for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
+ dsize = fs2h16(dp->e2d_reclen);
+ memcpy(dbuf, dp, (size_t)dsize);
+ idesc->id_dirp = (struct ext2fs_direct *)dbuf;
+ if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
+ bp = getdirblk(idesc->id_blkno, blksiz);
+ memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
+ (size_t)dsize);
+ dirty(bp);
+ sbdirty();
+ }
+ if (n & STOP) {
+ free(dbuf);
+ return (n);
+ }
+ }
+ free(dbuf);
+ return (idesc->id_filesize > 0 ? KEEPON : STOP);
+}
+
+/*
+ * get next entry in a directory.
+ */
+static struct ext2fs_direct *
+fsck_readdir(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dp, *ndp;
+ struct bufarea *bp;
+ long size, blksiz, fix, dploc;
+
+ blksiz = idesc->id_numfrags * sblock.e2fs_bsize;
+ bp = getdirblk(idesc->id_blkno, blksiz);
+ if (idesc->id_loc % sblock.e2fs_bsize == 0 && idesc->id_filesize > 0 &&
+ idesc->id_loc < blksiz) {
+ dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+ if (dircheck(idesc, dp))
+ goto dpok;
+ if (idesc->id_fix == IGNORE)
+ return (0);
+ fix = dofix(idesc, "DIRECTORY CORRUPTED");
+ bp = getdirblk(idesc->id_blkno, blksiz);
+ dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+ dp->e2d_reclen = h2fs16(sblock.e2fs_bsize);
+ dp->e2d_ino = 0;
+ dp->e2d_namlen = 0;
+ dp->e2d_type = 0;
+ dp->e2d_name[0] = '\0';
+ if (fix)
+ dirty(bp);
+ idesc->id_loc += sblock.e2fs_bsize;
+ idesc->id_filesize -= sblock.e2fs_bsize;
+ return (dp);
+ }
+dpok:
+ if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
+ return NULL;
+ dploc = idesc->id_loc;
+ dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc);
+ idesc->id_loc += fs2h16(dp->e2d_reclen);
+ idesc->id_filesize -= fs2h16(dp->e2d_reclen);
+ if ((idesc->id_loc % sblock.e2fs_bsize) == 0)
+ return (dp);
+ ndp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+ if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
+ dircheck(idesc, ndp) == 0) {
+ size = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize);
+ idesc->id_loc += size;
+ idesc->id_filesize -= size;
+ if (idesc->id_fix == IGNORE)
+ return (0);
+ fix = dofix(idesc, "DIRECTORY CORRUPTED");
+ bp = getdirblk(idesc->id_blkno, blksiz);
+ dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc);
+ dp->e2d_reclen = h2fs16(fs2h16(dp->e2d_reclen) + size);
+ if (fix)
+ dirty(bp);
+ }
+ return (dp);
+}
+
+/*
+ * Verify that a directory entry is valid.
+ * This is a superset of the checks made in the kernel.
+ */
+int
+dircheck(struct inodesc *idesc, struct ext2fs_direct *dp)
+{
+ int size;
+ char *cp;
+ int spaceleft;
+ u_int16_t reclen = fs2h16(dp->e2d_reclen);
+
+ spaceleft = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize);
+ if (fs2h32(dp->e2d_ino) > maxino ||
+ reclen == 0 ||
+ reclen > spaceleft ||
+ (reclen & 0x3) != 0)
+ return (0);
+ if (dp->e2d_ino == 0)
+ return (1);
+ if (sblock.e2fs.e2fs_rev < E2FS_REV1 ||
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) == 0)
+ if (dp->e2d_type != 0)
+ return (1);
+ size = EXT2FS_DIRSIZ(dp->e2d_namlen);
+ if (reclen < size ||
+ idesc->id_filesize < size /* ||
+ dp->e2d_namlen > EXT2FS_MAXNAMLEN */)
+ return (0);
+ for (cp = dp->e2d_name, size = 0; size < dp->e2d_namlen; size++)
+ if (*cp == '\0' || (*cp++ == '/'))
+ return (0);
+ return (1);
+}
+
+void
+direrror(ino_t ino, const char *errmesg)
+{
+
+ fileerror(ino, ino, errmesg);
+}
+
+void
+fileerror(ino_t cwd, ino_t ino, const char *errmesg)
+{
+ struct ext2fs_dinode *dp;
+ char pathbuf[MAXPATHLEN + 1];
+
+ pwarn("%s ", errmesg);
+ pinode(ino);
+ printf("\n");
+ getpathname(pathbuf, sizeof(pathbuf), cwd, ino);
+ if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino) {
+ pfatal("NAME=%s\n", pathbuf);
+ return;
+ }
+ dp = ginode(ino);
+ if (ftypeok(dp))
+ pfatal("%s=%s\n",
+ (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
+ else
+ pfatal("NAME=%s\n", pathbuf);
+}
+
+void
+adjust(struct inodesc *idesc, short lcnt)
+{
+ struct ext2fs_dinode *dp;
+
+ dp = ginode(idesc->id_number);
+ if (fs2h16(dp->e2di_nlink) == lcnt) {
+ if (linkup(idesc->id_number, (ino_t)0) == 0)
+ clri(idesc, "UNREF", 0);
+ } else {
+ pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
+ ((fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
+ pinode(idesc->id_number);
+ printf(" COUNT %d SHOULD BE %d",
+ fs2h16(dp->e2di_nlink), fs2h16(dp->e2di_nlink) - lcnt);
+ if (preen) {
+ if (lcnt < 0) {
+ printf("\n");
+ pfatal("LINK COUNT INCREASING");
+ }
+ printf(" (ADJUSTED)\n");
+ }
+ if (preen || reply("ADJUST") == 1) {
+ dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) - lcnt);
+ inodirty();
+ }
+ }
+}
+
+static int
+mkentry(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dirp = idesc->id_dirp;
+ struct ext2fs_direct newent;
+ int newlen, oldlen;
+
+ newent.e2d_type = 0; /* XXX gcc */
+ newent.e2d_namlen = strlen(idesc->id_name);
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ newent.e2d_type = inot2ext2dt(typemap[idesc->id_parent]);
+ newlen = EXT2FS_DIRSIZ(newent.e2d_namlen);
+ if (dirp->e2d_ino != 0)
+ oldlen = EXT2FS_DIRSIZ(dirp->e2d_namlen);
+ else
+ oldlen = 0;
+ if (fs2h16(dirp->e2d_reclen) - oldlen < newlen)
+ return (KEEPON);
+ newent.e2d_reclen = h2fs16(fs2h16(dirp->e2d_reclen) - oldlen);
+ dirp->e2d_reclen = h2fs16(oldlen);
+ dirp = (struct ext2fs_direct *)(((char *)dirp) + oldlen);
+ dirp->e2d_ino = h2fs32(idesc->id_parent); /* ino to be entered is in id_parent */
+ dirp->e2d_reclen = newent.e2d_reclen;
+ dirp->e2d_namlen = newent.e2d_namlen;
+ dirp->e2d_type = newent.e2d_type;
+ memcpy(dirp->e2d_name, idesc->id_name, (size_t)(dirp->e2d_namlen));
+ return (ALTERED|STOP);
+}
+
+static int
+chgino(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dirp = idesc->id_dirp;
+ u_int16_t namlen = dirp->e2d_namlen;
+
+ if (strlen(idesc->id_name) != namlen ||
+ strncmp(dirp->e2d_name, idesc->id_name, (int)namlen))
+ return (KEEPON);
+ dirp->e2d_ino = h2fs32(idesc->id_parent);
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ dirp->e2d_type = inot2ext2dt(typemap[idesc->id_parent]);
+ else
+ dirp->e2d_type = 0;
+ return (ALTERED|STOP);
+}
+
+int
+linkup(ino_t orphan, ino_t parentdir)
+{
+ struct ext2fs_dinode *dp;
+ int lostdir;
+ ino_t oldlfdir;
+ struct inodesc idesc;
+ char tempname[BUFSIZ];
+
+ memset(&idesc, 0, sizeof(struct inodesc));
+ dp = ginode(orphan);
+ lostdir = (fs2h16(dp->e2di_mode) & IFMT) == IFDIR;
+ pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
+ pinode(orphan);
+ if (preen && inosize(dp) == 0)
+ return (0);
+ if (preen)
+ printf(" (RECONNECTED)\n");
+ else
+ if (reply("RECONNECT") == 0)
+ return (0);
+ if (lfdir == 0) {
+ dp = ginode(EXT2_ROOTINO);
+ idesc.id_name = lfname;
+ idesc.id_type = DATA;
+ idesc.id_func = findino;
+ idesc.id_number = EXT2_ROOTINO;
+ if ((ckinode(dp, &idesc) & FOUND) != 0) {
+ lfdir = idesc.id_parent;
+ } else {
+ pwarn("NO lost+found DIRECTORY");
+ if (preen || reply("CREATE")) {
+ lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode);
+ if (lfdir != 0) {
+ if (makeentry(EXT2_ROOTINO, lfdir, lfname) != 0) {
+ if (preen)
+ printf(" (CREATED)\n");
+ } else {
+ freedir(lfdir, EXT2_ROOTINO);
+ lfdir = 0;
+ if (preen)
+ printf("\n");
+ }
+ }
+ }
+ }
+ if (lfdir == 0) {
+ pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
+ printf("\n\n");
+ return (0);
+ }
+ }
+ dp = ginode(lfdir);
+ if ((fs2h16(dp->e2di_mode) & IFMT) != IFDIR) {
+ pfatal("lost+found IS NOT A DIRECTORY");
+ if (reply("REALLOCATE") == 0)
+ return (0);
+ oldlfdir = lfdir;
+ if ((lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode)) == 0) {
+ pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+ return (0);
+ }
+ if ((changeino(EXT2_ROOTINO, lfname, lfdir) & ALTERED) == 0) {
+ pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+ return (0);
+ }
+ inodirty();
+ idesc.id_type = ADDR;
+ idesc.id_func = pass4check;
+ idesc.id_number = oldlfdir;
+ adjust(&idesc, lncntp[oldlfdir] + 1);
+ lncntp[oldlfdir] = 0;
+ dp = ginode(lfdir);
+ }
+ if (statemap[lfdir] != DFOUND) {
+ pfatal("SORRY. NO lost+found DIRECTORY\n\n");
+ return (0);
+ }
+ (void)lftempname(tempname, orphan);
+ if (makeentry(lfdir, orphan, tempname) == 0) {
+ pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
+ printf("\n\n");
+ return (0);
+ }
+ lncntp[orphan]--;
+ if (lostdir) {
+ if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
+ parentdir != (ino_t)-1)
+ (void)makeentry(orphan, lfdir, "..");
+ dp = ginode(lfdir);
+ dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) +1);
+ inodirty();
+ lncntp[lfdir]++;
+ pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan);
+ if (parentdir != (ino_t)-1)
+ printf("PARENT WAS I=%llu\n",
+ (unsigned long long)parentdir);
+ if (preen == 0)
+ printf("\n");
+ }
+ return (1);
+}
+
+/*
+ * fix an entry in a directory.
+ */
+int
+changeino(ino_t dir, const char *name, ino_t newnum)
+{
+ struct inodesc idesc;
+
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = DATA;
+ idesc.id_func = chgino;
+ idesc.id_number = dir;
+ idesc.id_fix = DONTKNOW;
+ idesc.id_name = name;
+ idesc.id_parent = newnum; /* new value for name */
+ return (ckinode(ginode(dir), &idesc));
+}
+
+/*
+ * make an entry in a directory
+ */
+int
+makeentry(ino_t parent, ino_t ino, const char *name)
+{
+ struct ext2fs_dinode *dp;
+ struct inodesc idesc;
+ char pathbuf[MAXPATHLEN + 1];
+
+ if ((parent < EXT2_FIRSTINO && parent != EXT2_ROOTINO)
+ || parent >= maxino ||
+ (ino < EXT2_FIRSTINO && ino < EXT2_ROOTINO) || ino >= maxino)
+ return (0);
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = DATA;
+ idesc.id_func = mkentry;
+ idesc.id_number = parent;
+ idesc.id_parent = ino; /* this is the inode to enter */
+ idesc.id_fix = DONTKNOW;
+ idesc.id_name = name;
+ dp = ginode(parent);
+ if (inosize(dp) % sblock.e2fs_bsize) {
+ inossize(dp, roundup(inosize(dp), sblock.e2fs_bsize));
+ inodirty();
+ }
+ if ((ckinode(dp, &idesc) & ALTERED) != 0)
+ return (1);
+ getpathname(pathbuf, sizeof(pathbuf), parent, parent);
+ dp = ginode(parent);
+ if (expanddir(dp, pathbuf) == 0)
+ return (0);
+ return (ckinode(dp, &idesc) & ALTERED);
+}
+
+/*
+ * Attempt to expand the size of a directory
+ */
+static int
+expanddir(struct ext2fs_dinode *dp, char *name)
+{
+ daddr_t lastbn, newblk;
+ struct bufarea *bp;
+ char *firstblk;
+
+ lastbn = lblkno(&sblock, inosize(dp));
+ if (lastbn >= NDADDR - 1 || fs2h32(dp->e2di_blocks[lastbn]) == 0 ||
+ inosize(dp) == 0) {
+ return (0);
+ }
+ if ((newblk = allocblk()) == 0) {
+ return (0);
+ }
+ dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn];
+ dp->e2di_blocks[lastbn] = h2fs32(newblk);
+ inossize(dp, inosize(dp) + sblock.e2fs_bsize);
+ dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) + 1);
+ bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
+ sblock.e2fs_bsize);
+ if (bp->b_errs)
+ goto bad;
+ if ((firstblk = malloc(sblock.e2fs_bsize)) == NULL)
+ err(8, "cannot allocate first block");
+ memcpy(firstblk, bp->b_un.b_buf, sblock.e2fs_bsize);
+ bp = getdirblk(newblk, sblock.e2fs_bsize);
+ if (bp->b_errs) {
+ free(firstblk);
+ goto bad;
+ }
+ memcpy(bp->b_un.b_buf, firstblk, sblock.e2fs_bsize);
+ free(firstblk);
+ dirty(bp);
+ bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
+ sblock.e2fs_bsize);
+ if (bp->b_errs)
+ goto bad;
+ emptydir.dot_reclen = h2fs16(sblock.e2fs_bsize);
+ memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
+ pwarn("NO SPACE LEFT IN %s", name);
+ if (preen)
+ printf(" (EXPANDED)\n");
+ else if (reply("EXPAND") == 0)
+ goto bad;
+ dirty(bp);
+ inodirty();
+ return (1);
+bad:
+ dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1];
+ dp->e2di_blocks[lastbn + 1] = 0;
+ inossize(dp, inosize(dp) - sblock.e2fs_bsize);
+ dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) - 1);
+ freeblk(newblk);
+ return (0);
+}
+
+/*
+ * allocate a new directory
+ */
+int
+allocdir(ino_t parent, ino_t request, int mode)
+{
+ ino_t ino;
+ struct ext2fs_dinode *dp;
+ struct bufarea *bp;
+ struct ext2fs_dirtemplate *dirp;
+
+ ino = allocino(request, IFDIR|mode);
+ dirhead.dot_reclen = h2fs16(12); /* XXX */
+ dirhead.dotdot_reclen = h2fs16(sblock.e2fs_bsize - 12); /* XXX */
+ dirhead.dot_namlen = 1;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ dirhead.dot_type = EXT2_FT_DIR;
+ else
+ dirhead.dot_type = 0;
+ dirhead.dotdot_namlen = 2;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ dirhead.dotdot_type = EXT2_FT_DIR;
+ else
+ dirhead.dotdot_type = 0;
+ dirp = &dirhead;
+ dirp->dot_ino = h2fs32(ino);
+ dirp->dotdot_ino = h2fs32(parent);
+ dp = ginode(ino);
+ bp = getdirblk(fs2h32(dp->e2di_blocks[0]), sblock.e2fs_bsize);
+ if (bp->b_errs) {
+ freeino(ino);
+ return (0);
+ }
+ memcpy(bp->b_un.b_buf, dirp, sizeof(struct ext2fs_dirtemplate));
+ dirty(bp);
+ dp->e2di_nlink = h2fs16(2);
+ inodirty();
+ if (ino == EXT2_ROOTINO) {
+ lncntp[ino] = fs2h16(dp->e2di_nlink);
+ cacheino(dp, ino);
+ return(ino);
+ }
+ if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
+ freeino(ino);
+ return (0);
+ }
+ cacheino(dp, ino);
+ statemap[ino] = statemap[parent];
+ if (statemap[ino] == DSTATE) {
+ lncntp[ino] = fs2h16(dp->e2di_nlink);
+ lncntp[parent]++;
+ }
+ dp = ginode(parent);
+ dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) + 1);
+ inodirty();
+ return (ino);
+}
+
+/*
+ * free a directory inode
+ */
+static void
+freedir(ino_t ino, ino_t parent)
+{
+ struct ext2fs_dinode *dp;
+
+ if (ino != parent) {
+ dp = ginode(parent);
+ dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) - 1);
+ inodirty();
+ }
+ freeino(ino);
+}
+
+/*
+ * generate a temporary name for the lost+found directory.
+ */
+static int
+lftempname(char *bufp, ino_t ino)
+{
+ ino_t in;
+ char *cp;
+ int namlen;
+
+ cp = bufp + 2;
+ for (in = maxino; in > 0; in /= 10)
+ cp++;
+ *--cp = 0;
+ namlen = cp - bufp;
+ in = ino;
+ while (cp > bufp) {
+ *--cp = (in % 10) + '0';
+ in /= 10;
+ }
+ *cp = '#';
+ return (namlen);
+}
+
+/*
+ * Get a directory block.
+ * Insure that it is held until another is requested.
+ */
+static struct bufarea *
+getdirblk(daddr_t blkno, long size)
+{
+
+ if (pdirbp != 0)
+ pdirbp->b_flags &= ~B_INUSE;
+ pdirbp = getdatablk(blkno, size);
+ return (pdirbp);
+}
--- /dev/null
+/* $NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $");
+
+#include <sys/types.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+
+/* These functions are only needed if native byte order is not big endian */
+#if BYTE_ORDER == BIG_ENDIAN
+void
+e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
+{
+
+ /* preserve unused fields */
+ memcpy(new, old, sizeof(struct ext2fs));
+ new->e2fs_icount = bswap32(old->e2fs_icount);
+ new->e2fs_bcount = bswap32(old->e2fs_bcount);
+ new->e2fs_rbcount = bswap32(old->e2fs_rbcount);
+ new->e2fs_fbcount = bswap32(old->e2fs_fbcount);
+ new->e2fs_ficount = bswap32(old->e2fs_ficount);
+ new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock);
+ new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize);
+ new->e2fs_fsize = bswap32(old->e2fs_fsize);
+ new->e2fs_bpg = bswap32(old->e2fs_bpg);
+ new->e2fs_fpg = bswap32(old->e2fs_fpg);
+ new->e2fs_ipg = bswap32(old->e2fs_ipg);
+ new->e2fs_mtime = bswap32(old->e2fs_mtime);
+ new->e2fs_wtime = bswap32(old->e2fs_wtime);
+ new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count);
+ new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count);
+ new->e2fs_magic = bswap16(old->e2fs_magic);
+ new->e2fs_state = bswap16(old->e2fs_state);
+ new->e2fs_beh = bswap16(old->e2fs_beh);
+ new->e2fs_minrev = bswap16(old->e2fs_minrev);
+ new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck);
+ new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv);
+ new->e2fs_creator = bswap32(old->e2fs_creator);
+ new->e2fs_rev = bswap32(old->e2fs_rev);
+ new->e2fs_ruid = bswap16(old->e2fs_ruid);
+ new->e2fs_rgid = bswap16(old->e2fs_rgid);
+ new->e2fs_first_ino = bswap32(old->e2fs_first_ino);
+ new->e2fs_inode_size = bswap16(old->e2fs_inode_size);
+ new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr);
+ new->e2fs_features_compat = bswap32(old->e2fs_features_compat);
+ new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat);
+ new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat);
+ new->e2fs_algo = bswap32(old->e2fs_algo);
+ new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb);
+}
+
+void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
+{
+ int i;
+
+ for (i = 0; i < (size / (int)sizeof(struct ext2_gd)); i++) {
+ new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap);
+ new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap);
+ new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables);
+ new[i].ext2bgd_nbfree = bswap16(old[i].ext2bgd_nbfree);
+ new[i].ext2bgd_nifree = bswap16(old[i].ext2bgd_nifree);
+ new[i].ext2bgd_ndirs = bswap16(old[i].ext2bgd_ndirs);
+ }
+}
+
+void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
+{
+
+ new->e2di_mode = bswap16(old->e2di_mode);
+ new->e2di_uid = bswap16(old->e2di_uid);
+ new->e2di_gid = bswap16(old->e2di_gid);
+ new->e2di_nlink = bswap16(old->e2di_nlink);
+ new->e2di_size = bswap32(old->e2di_size);
+ new->e2di_atime = bswap32(old->e2di_atime);
+ new->e2di_ctime = bswap32(old->e2di_ctime);
+ new->e2di_mtime = bswap32(old->e2di_mtime);
+ new->e2di_dtime = bswap32(old->e2di_dtime);
+ new->e2di_nblock = bswap32(old->e2di_nblock);
+ new->e2di_flags = bswap32(old->e2di_flags);
+ new->e2di_gen = bswap32(old->e2di_gen);
+ new->e2di_facl = bswap32(old->e2di_facl);
+ new->e2di_dacl = bswap32(old->e2di_dacl);
+ new->e2di_faddr = bswap32(old->e2di_faddr);
+ new->e2di_uid_high = bswap16(old->e2di_uid_high);
+ new->e2di_gid_high = bswap16(old->e2di_gid_high);
+ memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
+ (NDADDR + NIADDR) * sizeof(uint32_t));
+}
+#endif
--- /dev/null
+/* $NetBSD: extern.h,v 1.7 2011/06/09 19:57:50 christos Exp $ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ * Copyright (c) 1994 James A. Jegers
+ * 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. 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.
+ */
+
+void adjust(struct inodesc *, short);
+int allocblk(void);
+int allocdir(ino_t, ino_t, int);
+void blkerror(ino_t, const char *, daddr_t);
+int bread(int, char *, daddr_t, long);
+void bufinit(void);
+void bwrite(int, char *, daddr_t, long);
+void cacheino(struct ext2fs_dinode *, ino_t);
+int changeino(ino_t, const char *, ino_t);
+int chkrange(daddr_t, int);
+void ckfini(int);
+int ckinode(struct ext2fs_dinode *, struct inodesc *);
+void clri(struct inodesc *, const char *, int);
+int dircheck(struct inodesc *, struct ext2fs_direct *);
+void direrror(ino_t, const char *);
+int dirscan(struct inodesc *);
+int dofix(struct inodesc *, const char *);
+void fileerror(ino_t, ino_t, const char *);
+int findino(struct inodesc *);
+int findname(struct inodesc *);
+void flush(int, struct bufarea *);
+void freeblk(daddr_t);
+void freeino(ino_t);
+void freeinodebuf(void);
+int ftypeok(struct ext2fs_dinode *);
+void getpathname(char *, size_t, ino_t, ino_t);
+void inocleanup(void);
+void inodirty(void);
+u_int64_t inosize(struct ext2fs_dinode *);
+void inossize(struct ext2fs_dinode *, u_int64_t);
+int linkup(ino_t, ino_t);
+int makeentry(ino_t, ino_t, const char *);
+void pass1(void);
+void pass1b(void);
+void pass2(void);
+void pass3(void);
+void pass4(void);
+int pass1check(struct inodesc *);
+int pass4check(struct inodesc *);
+void pass5(void);
+void pinode(ino_t);
+void propagate(void);
+int reply(const char *);
+void resetinodebuf(void);
+int setup(const char *);
+struct ext2fs_dinode * getnextinode(ino_t);
--- /dev/null
+/* $NetBSD: fsck.h,v 1.15 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ *
+ * @(#)fsck.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ *
+ * @(#)fsck.h 8.1 (Berkeley) 6/5/93
+ */
+
+#define MAXDUP 10 /* limit on dup blks (per inode) */
+#define MAXBAD 10 /* limit on bad blks (per inode) */
+#define MAXBUFSPACE 80*1024 /* maximum space to allocate to buffers */
+#define INOBUFSIZE 128*1024 /* size of buffer to read inodes in pass1 */
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+
+#define USTATE 01 /* inode not allocated */
+#define FSTATE 02 /* inode is file */
+#define DSTATE 03 /* inode is directory */
+#define DFOUND 04 /* directory found during descent */
+#define DCLEAR 05 /* directory is to be cleared */
+#define FCLEAR 06 /* file is to be cleared */
+
+/*
+ * buffer cache structure.
+ */
+struct bufarea {
+ struct bufarea *b_next; /* free list queue */
+ struct bufarea *b_prev; /* free list queue */
+ daddr_t b_bno;
+ int b_size;
+ int b_errs;
+ int b_flags;
+ union {
+ char *b_buf; /* buffer space */
+ /* XXX ondisk32 */
+ int32_t *b_indir; /* indirect block */
+ struct ext2fs *b_fs; /* super block */
+ struct ext2_gd *b_cgd; /* cylinder group descriptor */
+ struct ext2fs_dinode *b_dinode; /* inode block */
+ } b_un;
+ char b_dirty;
+};
+
+#define B_INUSE 1
+
+#define MINBUFS 5 /* minimum number of buffers required */
+struct bufarea bufhead; /* head of list of other blks in filesys */
+struct bufarea sblk; /* file system superblock */
+struct bufarea asblk; /* first alternate superblock */
+struct bufarea *pdirbp; /* current directory contents */
+struct bufarea *pbp; /* current inode block */
+struct bufarea *getdatablk(daddr_t, long);
+struct m_ext2fs sblock;
+
+#define dirty(bp) (bp)->b_dirty = 1
+#define initbarea(bp) \
+ (bp)->b_dirty = 0; \
+ (bp)->b_bno = (daddr_t)-1; \
+ (bp)->b_flags = 0;
+
+#define sbdirty() copyback_sb(&sblk); sblk.b_dirty = 1
+
+enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
+
+struct inodesc {
+ enum fixstate id_fix; /* policy on fixing errors */
+ int (*id_func) /* function to be applied to blocks of inode */
+ (struct inodesc *);
+ ino_t id_number; /* inode number described */
+ ino_t id_parent; /* for DATA nodes, their parent */
+ daddr_t id_blkno; /* current block number being examined */
+ int id_numfrags; /* number of frags contained in block */
+ quad_t id_filesize; /* for DATA nodes, the size of the directory */
+ int id_loc; /* for DATA nodes, current location in dir */
+ int id_entryno; /* for DATA nodes, current entry number */
+ struct ext2fs_direct *id_dirp; /* for DATA nodes, ptr to current entry */
+ const char *id_name; /* for DATA nodes, name to find or enter */
+ char id_type; /* type of descriptor, DATA or ADDR */
+};
+/* file types */
+#define DATA 1
+#define ADDR 2
+
+/*
+ * Linked list of duplicate blocks.
+ *
+ * The list is composed of two parts. The first part of the
+ * list (from duplist through the node pointed to by muldup)
+ * contains a single copy of each duplicate block that has been
+ * found. The second part of the list (from muldup to the end)
+ * contains duplicate blocks that have been found more than once.
+ * To check if a block has been found as a duplicate it is only
+ * necessary to search from duplist through muldup. To find the
+ * total number of times that a block has been found as a duplicate
+ * the entire list must be searched for occurrences of the block
+ * in question. The following diagram shows a sample list where
+ * w (found twice), x (found once), y (found three times), and z
+ * (found once) are duplicate block numbers:
+ *
+ * w -> y -> x -> z -> y -> w -> y
+ * ^ ^
+ * | |
+ * duplist muldup
+ */
+struct dups {
+ struct dups *next;
+ daddr_t dup;
+};
+struct dups *duplist; /* head of dup list */
+struct dups *muldup; /* end of unique duplicate dup block numbers */
+
+/*
+ * Linked list of inodes with zero link counts.
+ */
+struct zlncnt {
+ struct zlncnt *next;
+ ino_t zlncnt;
+};
+struct zlncnt *zlnhead; /* head of zero link count list */
+
+/*
+ * Inode cache data structures.
+ */
+struct inoinfo {
+ struct inoinfo *i_nexthash; /* next entry in hash chain */
+ struct inoinfo *i_child, *i_sibling, *i_parentp;
+ ino_t i_number; /* inode number of this entry */
+ ino_t i_parent; /* inode number of parent */
+ ino_t i_dotdot; /* inode number of `..' */
+ u_int64_t i_isize; /* size of inode */
+ u_int i_numblks; /* size of block array in bytes */
+ /* XXX ondisk32 */
+ int32_t i_blks[1]; /* actually longer */
+} **inphead, **inpsort;
+long numdirs, listmax, inplast;
+
+long dev_bsize; /* computed value of DEV_BSIZE */
+long secsize; /* actual disk sector size */
+char nflag; /* assume a no response */
+char yflag; /* assume a yes response */
+int bflag; /* location of alternate super block */
+int Uflag; /* resolve user names */
+int debug; /* output debugging info */
+int preen; /* just fix normal inconsistencies */
+char havesb; /* superblock has been read */
+char skipclean; /* skip clean file systems if preening */
+int fsmodified; /* 1 => write done to file system */
+int fsreadfd; /* file descriptor for reading file system */
+int fswritefd; /* file descriptor for writing file system */
+int rerun; /* rerun fsck. Only used in non-preen mode */
+
+daddr_t maxfsblock; /* number of blocks in the file system */
+char *blockmap; /* ptr to primary blk allocation map */
+ino_t maxino; /* number of inodes in file system */
+ino_t lastino; /* last inode in use */
+char *statemap; /* ptr to inode state table */
+u_char *typemap; /* ptr to inode type table */
+int16_t *lncntp; /* ptr to link count table */
+
+ino_t lfdir; /* lost & found directory inode number */
+extern const char *lfname; /* lost & found directory name */
+extern int lfmode; /* lost & found directory creation mode */
+
+daddr_t n_blks; /* number of blocks in use */
+daddr_t n_files; /* number of files in use */
+
+#define clearinode(dp) (*(dp) = zino)
+struct ext2fs_dinode zino;
+
+#define setbmap(blkno) setbit(blockmap, blkno)
+#define testbmap(blkno) isset(blockmap, blkno)
+#define clrbmap(blkno) clrbit(blockmap, blkno)
+
+#define STOP 0x01
+#define SKIP 0x02
+#define KEEPON 0x04
+#define ALTERED 0x08
+#define FOUND 0x10
+
+struct ext2fs_dinode *ginode(ino_t);
+struct inoinfo *getinoinfo(ino_t);
+void getblk(struct bufarea *, daddr_t, long);
+ino_t allocino(ino_t, int);
+void copyback_sb(struct bufarea*);
+daddr_t cgoverhead(int); /* overhead per cg */
--- /dev/null
+.\" $NetBSD: fsck_ext2fs.8,v 1.19 2010/02/21 13:26:45 wiz Exp $
+.\"
+.\" Copyright (c) 1980, 1989, 1991, 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.
+.\"
+.\" Copyright (c) 1997 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.
+.\"
+.\" 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.
+.\"
+.\" @(#)fsck.8 8.3 (Berkeley) 11/29/94
+.\"
+.Dd October 9, 2008
+.Dt FSCK_EXT2FS 8
+.Os
+.Sh NAME
+.Nm fsck_ext2fs
+.Nd ext2 File System consistency check and interactive repair
+.Sh SYNOPSIS
+.Nm
+.Op Fl dfnpUy
+.Op Fl b Ar block#
+.Op Fl c Ar level
+.Op Fl m Ar mode
+.Ar filesystem ...
+.Sh DESCRIPTION
+.Nm
+performs interactive filesystem consistency checks and repair for each of
+the filesystems specified on the command line.
+It is normally invoked from
+.Xr fsck 8 .
+.Pp
+The kernel takes care that only a restricted class of innocuous filesystem
+inconsistencies can happen unless hardware or software failures intervene.
+These are limited to the following:
+.Pp
+.Bl -item -compact
+.It
+Unreferenced inodes
+.It
+Link counts in inodes too large
+.It
+Missing blocks in the free map
+.It
+Blocks in the free map also in files
+.It
+Counts in the super-block wrong
+.El
+.Pp
+These are the only inconsistencies that
+.Nm
+in
+.Dq preen
+mode (with the
+.Fl p
+option) will correct; if it encounters other inconsistencies, it exits
+with an abnormal return status.
+For each corrected inconsistency one or more lines will be printed
+identifying the filesystem on which the correction will take place,
+and the nature of the correction.
+After successfully correcting a filesystem,
+.Nm
+will print the number of files on that filesystem
+and the number of used and free blocks.
+.Pp
+If sent a
+.Dv QUIT
+signal,
+.Nm
+will finish the filesystem checks, then exit with an abnormal return status.
+.Pp
+Without the
+.Fl p
+option,
+.Nm
+audits and interactively repairs inconsistent conditions for filesystems.
+If the filesystem is inconsistent the operator is prompted for concurrence
+before each correction is attempted.
+It should be noted that some of the corrective actions which are not
+correctable under the
+.Fl p
+option will result in some loss of data.
+The amount and severity of data lost may be determined from the diagnostic
+output.
+The default action for each consistency correction
+is to wait for the operator to respond
+.Li yes
+or
+.Li no .
+If the operator does not have write permission on the filesystem
+.Nm
+will default to a
+.Fl n
+action.
+.Pp
+The following flags are interpreted by
+.Nm .
+.Bl -tag -width indent
+.It Fl b
+Use the block specified immediately after the flag as
+the super block for the filesystem.
+Block 8193 is usually an alternate super block.
+.It Fl d
+Print debugging output.
+.It Fl f
+Force checking of file systems.
+Normally, if a file system is cleanly unmounted, the kernel will set a
+.Dq clean flag
+in the file system superblock, and
+.Nm
+will not check the file system.
+This option forces
+.Nm
+to check the file system, regardless of the state of the clean flag.
+.It Fl m
+Use the mode specified in octal immediately after the flag as the
+permission bits to use when creating the
+.Pa lost+found
+directory rather than the default 1777.
+In particular, systems that do not wish to have lost files accessible
+by all users on the system should use a more restrictive
+set of permissions such as 700.
+.It Fl n
+Assume a no response to all questions asked by
+.Nm
+except for
+.Ql CONTINUE? ,
+which is assumed to be affirmative;
+do not open the filesystem for writing.
+.It Fl p
+Specify
+.Dq preen
+mode, described above.
+.It Fl U
+Resolve numeric userids to usernames.
+.It Fl y
+Assume a yes response to all questions asked by
+.Nm ;
+this should be used with great caution as this is a free license
+to continue after essentially unlimited trouble has been encountered.
+.El
+.Pp
+Inconsistencies checked are as follows:
+.Bl -enum -offset indent -compact
+.It
+Blocks claimed by more than one inode or the free map.
+.It
+Blocks claimed by an inode outside the range of the filesystem.
+.It
+Incorrect link counts.
+.It
+Size checks:
+.Bl -item -offset indent -compact
+.It
+Directory size not a multiple of filesystem block size.
+.It
+Partially truncated file.
+.El
+.It
+Bad inode format.
+.It
+Blocks not accounted for anywhere.
+.It
+Directory checks:
+.Bl -item -offset indent -compact
+.It
+File pointing to unallocated inode.
+.It
+Inode number out of range.
+.It
+Dot or dot-dot not the first two entries of a directory
+or having the wrong inode number.
+.El
+.It
+Super Block checks:
+.Bl -item -offset indent -compact
+.It
+More blocks for inodes than there are in the filesystem.
+.It
+Bad free block map format.
+.It
+Total free block and/or free inode count incorrect.
+.El
+.El
+.Pp
+Orphaned files and directories (allocated but unreferenced) are,
+with the operator's concurrence, reconnected by
+placing them in the
+.Pa lost+found
+directory.
+The name assigned is the inode number.
+If the
+.Pa lost+found
+directory does not exist, it is created.
+If there is insufficient space its size is increased.
+.Pp
+Because of inconsistencies between the block device and the buffer cache,
+the raw device should always be used.
+.Sh DIAGNOSTICS
+The diagnostics produced by
+.Nm
+are fully enumerated and explained in Appendix A of
+.Rs
+.%T "Fsck \- The UNIX File System Check Program"
+.Re
+.Sh SEE ALSO
+.Xr fs 5 ,
+.Xr fstab 5 ,
+.Xr fsck 8 ,
+.Xr fsdb 8 ,
+.Xr newfs 8 ,
+.Xr reboot 8
--- /dev/null
+/* $NetBSD: inode.c,v 1.31 2010/02/04 23:55:42 christos Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)inode.c 8.5 (Berkeley) 2/8/95";
+#else
+__RCSID("$NetBSD: inode.c,v 1.31 2010/02/04 23:55:42 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+#ifndef SMALL
+#include <pwd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+
+/*
+ * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
+ * here.
+ */
+
+#define fsck_ino_to_fsba(fs, x) \
+ (fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
+ (((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
+
+
+static ino_t startinum;
+
+static int iblock(struct inodesc *, long, u_int64_t);
+
+static int setlarge(void);
+
+static int
+setlarge(void)
+{
+ if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
+ pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
+ return 0;
+ }
+ if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) {
+ if (preen)
+ pwarn("SETTING LARGE FILE INDICATOR\n");
+ else if (!reply("SET LARGE FILE INDICATOR"))
+ return 0;
+ sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE;
+ sbdirty();
+ }
+ return 1;
+}
+
+u_int64_t
+inosize(struct ext2fs_dinode *dp)
+{
+ u_int64_t size = fs2h32(dp->e2di_size);
+
+ if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG)
+ size |= (u_int64_t)fs2h32(dp->e2di_dacl) << 32;
+ if (size > INT32_MAX)
+ (void)setlarge();
+ return size;
+}
+
+void
+inossize(struct ext2fs_dinode *dp, u_int64_t size)
+{
+ if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) {
+ dp->e2di_dacl = h2fs32(size >> 32);
+ if (size > INT32_MAX)
+ if (!setlarge())
+ return;
+ } else if (size > INT32_MAX) {
+ pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
+ (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT);
+ return;
+ }
+ dp->e2di_size = h2fs32(size);
+}
+
+int
+ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
+{
+ u_int32_t *ap;
+ long ret, n, ndb;
+ struct ext2fs_dinode dino;
+ u_int64_t remsize, sizepb;
+ mode_t mode;
+ char pathbuf[MAXPATHLEN + 1];
+
+ if (idesc->id_fix != IGNORE)
+ idesc->id_fix = DONTKNOW;
+ idesc->id_entryno = 0;
+ idesc->id_filesize = inosize(dp);
+ mode = fs2h16(dp->e2di_mode) & IFMT;
+ if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
+ (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
+ return (KEEPON);
+ dino = *dp;
+ ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
+ for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR];
+ ap++,ndb--) {
+ idesc->id_numfrags = 1;
+ if (*ap == 0) {
+ if (idesc->id_type == DATA && ndb > 0) {
+ /* An empty block in a directory XXX */
+ getpathname(pathbuf, sizeof(pathbuf),
+ idesc->id_number, idesc->id_number);
+ pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+ pathbuf);
+ if (reply("ADJUST LENGTH") == 1) {
+ dp = ginode(idesc->id_number);
+ inossize(dp,
+ (ap - &dino.e2di_blocks[0]) *
+ sblock.e2fs_bsize);
+ printf(
+ "YOU MUST RERUN FSCK AFTERWARDS\n");
+ rerun = 1;
+ inodirty();
+ }
+ }
+ continue;
+ }
+ idesc->id_blkno = fs2h32(*ap);
+ if (idesc->id_type == ADDR)
+ ret = (*idesc->id_func)(idesc);
+ else
+ ret = dirscan(idesc);
+ if (ret & STOP)
+ return (ret);
+ }
+ idesc->id_numfrags = 1;
+ remsize = inosize(&dino) - sblock.e2fs_bsize * NDADDR;
+ sizepb = sblock.e2fs_bsize;
+ for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) {
+ if (*ap) {
+ idesc->id_blkno = fs2h32(*ap);
+ ret = iblock(idesc, n, remsize);
+ if (ret & STOP)
+ return (ret);
+ } else {
+ if (idesc->id_type == DATA && remsize > 0) {
+ /* An empty block in a directory XXX */
+ getpathname(pathbuf, sizeof(pathbuf),
+ idesc->id_number, idesc->id_number);
+ pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+ pathbuf);
+ if (reply("ADJUST LENGTH") == 1) {
+ dp = ginode(idesc->id_number);
+ inossize(dp, inosize(dp) - remsize);
+ remsize = 0;
+ printf(
+ "YOU MUST RERUN FSCK AFTERWARDS\n");
+ rerun = 1;
+ inodirty();
+ break;
+ }
+ }
+ }
+ sizepb *= NINDIR(&sblock);
+ remsize -= sizepb;
+ }
+ return (KEEPON);
+}
+
+static int
+iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
+{
+ /* XXX ondisk32 */
+ int32_t *ap;
+ int32_t *aplim;
+ struct bufarea *bp;
+ int i, n, (*func)(struct inodesc *);
+ size_t nif;
+ u_int64_t sizepb;
+ char buf[BUFSIZ];
+ char pathbuf[MAXPATHLEN + 1];
+ struct ext2fs_dinode *dp;
+
+ if (idesc->id_type == ADDR) {
+ func = idesc->id_func;
+ if (((n = (*func)(idesc)) & KEEPON) == 0)
+ return (n);
+ } else
+ func = dirscan;
+ if (chkrange(idesc->id_blkno, idesc->id_numfrags))
+ return (SKIP);
+ bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
+ ilevel--;
+ for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
+ sizepb *= NINDIR(&sblock);
+ if (isize > sizepb * NINDIR(&sblock))
+ nif = NINDIR(&sblock);
+ else
+ nif = howmany(isize, sizepb);
+ if (idesc->id_func == pass1check &&
+ nif < NINDIR(&sblock)) {
+ aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
+ for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
+ if (*ap == 0)
+ continue;
+ (void)snprintf(buf, sizeof(buf),
+ "PARTIALLY TRUNCATED INODE I=%llu",
+ (unsigned long long)idesc->id_number);
+ if (dofix(idesc, buf)) {
+ *ap = 0;
+ dirty(bp);
+ }
+ }
+ flush(fswritefd, bp);
+ }
+ aplim = &bp->b_un.b_indir[nif];
+ for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
+ if (*ap) {
+ idesc->id_blkno = fs2h32(*ap);
+ if (ilevel == 0)
+ n = (*func)(idesc);
+ else
+ n = iblock(idesc, ilevel, isize);
+ if (n & STOP) {
+ bp->b_flags &= ~B_INUSE;
+ return (n);
+ }
+ } else {
+ if (idesc->id_type == DATA && isize > 0) {
+ /* An empty block in a directory XXX */
+ getpathname(pathbuf, sizeof(pathbuf),
+ idesc->id_number, idesc->id_number);
+ pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+ pathbuf);
+ if (reply("ADJUST LENGTH") == 1) {
+ dp = ginode(idesc->id_number);
+ inossize(dp, inosize(dp) - isize);
+ isize = 0;
+ printf(
+ "YOU MUST RERUN FSCK AFTERWARDS\n");
+ rerun = 1;
+ inodirty();
+ bp->b_flags &= ~B_INUSE;
+ return(STOP);
+ }
+ }
+ }
+ isize -= sizepb;
+ }
+ bp->b_flags &= ~B_INUSE;
+ return (KEEPON);
+}
+
+/*
+ * Check that a block in a legal block number.
+ * Return 0 if in range, 1 if out of range.
+ */
+int
+chkrange(daddr_t blk, int cnt)
+{
+ int c, overh;
+
+ if ((unsigned int)(blk + cnt) > maxfsblock)
+ return (1);
+ c = dtog(&sblock, blk);
+ overh = cgoverhead(c);
+ if (blk < sblock.e2fs.e2fs_bpg * c + overh +
+ sblock.e2fs.e2fs_first_dblock) {
+ if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
+ sblock.e2fs.e2fs_first_dblock) {
+ if (debug) {
+ printf("blk %lld < cgdmin %d;",
+ (long long)blk,
+ sblock.e2fs.e2fs_bpg * c + overh +
+ sblock.e2fs.e2fs_first_dblock);
+ printf(" blk + cnt %lld > cgsbase %d\n",
+ (long long)(blk + cnt),
+ sblock.e2fs.e2fs_bpg * c +
+ overh + sblock.e2fs.e2fs_first_dblock);
+ }
+ return (1);
+ }
+ } else {
+ if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
+ sblock.e2fs.e2fs_first_dblock) {
+ if (debug) {
+ printf("blk %lld >= cgdmin %d;",
+ (long long)blk,
+ sblock.e2fs.e2fs_bpg * c + overh +
+ sblock.e2fs.e2fs_first_dblock);
+ printf(" blk + cnt %lld > cgdmax %d\n",
+ (long long)(blk+cnt),
+ sblock.e2fs.e2fs_bpg * (c + 1) +
+ overh + sblock.e2fs.e2fs_first_dblock);
+ }
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * General purpose interface for reading inodes.
+ */
+struct ext2fs_dinode *
+ginode(ino_t inumber)
+{
+ daddr_t iblk;
+ struct ext2fs_dinode *dp;
+
+ if ((inumber < EXT2_FIRSTINO &&
+ inumber != EXT2_ROOTINO &&
+ !(inumber == EXT2_RESIZEINO &&
+ (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
+ || inumber > maxino)
+ errexit("bad inode number %llu to ginode",
+ (unsigned long long)inumber);
+ if (startinum == 0 ||
+ inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
+ iblk = fsck_ino_to_fsba(&sblock, inumber);
+ if (pbp != 0)
+ pbp->b_flags &= ~B_INUSE;
+ pbp = getdatablk(iblk, sblock.e2fs_bsize);
+ startinum =
+ ((inumber - 1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
+ }
+ dp = (struct ext2fs_dinode *)(pbp->b_un.b_buf +
+ EXT2_DINODE_SIZE(&sblock) * ino_to_fsbo(&sblock, inumber));
+
+ return dp;
+}
+
+/*
+ * Special purpose version of ginode used to optimize first pass
+ * over all the inodes in numerical order.
+ */
+ino_t nextino, lastinum;
+long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
+char *inodebuf;
+
+struct ext2fs_dinode *
+getnextinode(ino_t inumber)
+{
+ long size;
+ daddr_t dblk;
+ struct ext2fs_dinode *dp;
+ static char *bp;
+
+ if (inumber != nextino++ || inumber > maxino)
+ errexit("bad inode number %llu to nextinode",
+ (unsigned long long)inumber);
+ if (inumber >= lastinum) {
+ readcnt++;
+ dblk = fsbtodb(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
+ if (readcnt % readpercg == 0) {
+ size = partialsize;
+ lastinum += partialcnt;
+ } else {
+ size = inobufsize;
+ lastinum += fullcnt;
+ }
+ (void)bread(fsreadfd, inodebuf, dblk, size);
+ bp = inodebuf;
+ }
+ dp = (struct ext2fs_dinode *)bp;
+ bp += EXT2_DINODE_SIZE(&sblock);
+
+ return dp;
+}
+
+void
+resetinodebuf(void)
+{
+
+ startinum = 0;
+ nextino = 1;
+ lastinum = 1;
+ readcnt = 0;
+ inobufsize = blkroundup(&sblock, INOBUFSIZE);
+ fullcnt = inobufsize / EXT2_DINODE_SIZE(&sblock);
+ readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
+ partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
+ partialsize = partialcnt * EXT2_DINODE_SIZE(&sblock);
+ if (partialcnt != 0) {
+ readpercg++;
+ } else {
+ partialcnt = fullcnt;
+ partialsize = inobufsize;
+ }
+ if (inodebuf == NULL &&
+ (inodebuf = malloc((unsigned int)inobufsize)) == NULL)
+ errexit("Cannot allocate space for inode buffer");
+ while (nextino < EXT2_ROOTINO)
+ (void)getnextinode(nextino);
+}
+
+void
+freeinodebuf(void)
+{
+
+ if (inodebuf != NULL)
+ free(inodebuf);
+ inodebuf = NULL;
+}
+
+/*
+ * Routines to maintain information about directory inodes.
+ * This is built during the first pass and used during the
+ * second and third passes.
+ *
+ * Enter inodes into the cache.
+ */
+void
+cacheino(struct ext2fs_dinode *dp, ino_t inumber)
+{
+ struct inoinfo *inp;
+ struct inoinfo **inpp;
+ unsigned int blks;
+
+ blks = howmany(inosize(dp), sblock.e2fs_bsize);
+ if (blks > NDADDR)
+ blks = NDADDR + NIADDR;
+ /* XXX ondisk32 */
+ inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
+ if (inp == NULL)
+ return;
+ inpp = &inphead[inumber % numdirs];
+ inp->i_nexthash = *inpp;
+ *inpp = inp;
+ inp->i_child = inp->i_sibling = inp->i_parentp = 0;
+ if (inumber == EXT2_ROOTINO)
+ inp->i_parent = EXT2_ROOTINO;
+ else
+ inp->i_parent = (ino_t)0;
+ inp->i_dotdot = (ino_t)0;
+ inp->i_number = inumber;
+ inp->i_isize = inosize(dp);
+ /* XXX ondisk32 */
+ inp->i_numblks = blks * sizeof(int32_t);
+ memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
+ if (inplast == listmax) {
+ listmax += 100;
+ inpsort = (struct inoinfo **)realloc((char *)inpsort,
+ (unsigned int)listmax * sizeof(struct inoinfo *));
+ if (inpsort == NULL)
+ errexit("cannot increase directory list");
+ }
+ inpsort[inplast++] = inp;
+}
+
+/*
+ * Look up an inode cache structure.
+ */
+struct inoinfo *
+getinoinfo(ino_t inumber)
+{
+ struct inoinfo *inp;
+
+ for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
+ if (inp->i_number != inumber)
+ continue;
+ return (inp);
+ }
+ errexit("cannot find inode %llu", (unsigned long long)inumber);
+ return ((struct inoinfo *)0);
+}
+
+/*
+ * Clean up all the inode cache structure.
+ */
+void
+inocleanup(void)
+{
+ struct inoinfo **inpp;
+
+ if (inphead == NULL)
+ return;
+ for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
+ free(*inpp);
+ free(inphead);
+ free(inpsort);
+ inphead = inpsort = NULL;
+}
+
+void
+inodirty(void)
+{
+
+ dirty(pbp);
+}
+
+void
+clri(struct inodesc *idesc, const char *type, int flag)
+{
+ struct ext2fs_dinode *dp;
+
+ dp = ginode(idesc->id_number);
+ if (flag == 1) {
+ pwarn("%s %s", type,
+ (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
+ pinode(idesc->id_number);
+ }
+ if (preen || reply("CLEAR") == 1) {
+ if (preen)
+ printf(" (CLEARED)\n");
+ n_files--;
+ (void)ckinode(dp, idesc);
+ clearinode(dp);
+ statemap[idesc->id_number] = USTATE;
+ inodirty();
+ }
+}
+
+int
+findname(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dirp = idesc->id_dirp;
+ u_int16_t namlen = dirp->e2d_namlen;
+ /* from utilities.c namebuf[] variable */
+ char *buf = __UNCONST(idesc->id_name);
+ if (namlen > MAXPATHLEN) {
+ /* XXX: Prevent overflow but don't fix */
+ namlen = MAXPATHLEN;
+ }
+
+ if (fs2h32(dirp->e2d_ino) != idesc->id_parent)
+ return (KEEPON);
+ (void)memcpy(buf, dirp->e2d_name, (size_t)namlen);
+ buf[namlen] = '\0';
+ return (STOP|FOUND);
+}
+
+int
+findino(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dirp = idesc->id_dirp;
+ u_int32_t ino = fs2h32(dirp->e2d_ino);
+
+ if (ino == 0)
+ return (KEEPON);
+ if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
+ (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO)
+ && ino <= maxino) {
+ idesc->id_parent = ino;
+ return (STOP|FOUND);
+ }
+ return (KEEPON);
+}
+
+void
+pinode(ino_t ino)
+{
+ struct ext2fs_dinode *dp;
+ struct passwd *pw;
+ uid_t uid;
+
+ printf(" I=%llu ", (unsigned long long)ino);
+ if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
+ return;
+ dp = ginode(ino);
+ uid = fs2h16(dp->e2di_uid);
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0)
+ uid |= fs2h16(dp->e2di_uid_high) << 16;
+ printf(" OWNER=");
+#ifndef SMALL
+ if (Uflag && (pw = getpwuid(uid)) != 0)
+ printf("%s ", pw->pw_name);
+ else
+#endif
+ printf("%u ", (unsigned int)uid);
+ printf("MODE=%o\n", fs2h16(dp->e2di_mode));
+ if (preen)
+ printf("%s: ", cdevname());
+ printf("SIZE=%llu ", (long long)inosize(dp));
+ printf("MTIME=%s ", print_mtime(fs2h32(dp->e2di_mtime)));
+}
+
+void
+blkerror(ino_t ino, const char *type, daddr_t blk)
+{
+
+ pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
+ printf("\n");
+ switch (statemap[ino]) {
+
+ case FSTATE:
+ statemap[ino] = FCLEAR;
+ return;
+
+ case DSTATE:
+ statemap[ino] = DCLEAR;
+ return;
+
+ case FCLEAR:
+ case DCLEAR:
+ return;
+
+ default:
+ errexit("BAD STATE %d TO BLKERR", statemap[ino]);
+ /* NOTREACHED */
+ }
+}
+
+/*
+ * allocate an unused inode
+ */
+ino_t
+allocino(ino_t request, int type)
+{
+ ino_t ino;
+ struct ext2fs_dinode *dp;
+ time_t t;
+
+ if (request == 0)
+ request = EXT2_ROOTINO;
+ else if (statemap[request] != USTATE)
+ return (0);
+ for (ino = request; ino < maxino; ino++) {
+ if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
+ continue;
+ if (statemap[ino] == USTATE)
+ break;
+ }
+ if (ino == maxino)
+ return (0);
+ switch (type & IFMT) {
+ case IFDIR:
+ statemap[ino] = DSTATE;
+ break;
+ case IFREG:
+ case IFLNK:
+ statemap[ino] = FSTATE;
+ break;
+ default:
+ return (0);
+ }
+ dp = ginode(ino);
+ dp->e2di_blocks[0] = h2fs32(allocblk());
+ if (dp->e2di_blocks[0] == 0) {
+ statemap[ino] = USTATE;
+ return (0);
+ }
+ dp->e2di_mode = h2fs16(type);
+ (void)time(&t);
+ dp->e2di_atime = h2fs32(t);
+ dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
+ dp->e2di_dtime = 0;
+ inossize(dp, sblock.e2fs_bsize);
+ dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize));
+ n_files++;
+ inodirty();
+ typemap[ino] = E2IFTODT(type);
+ return (ino);
+}
+
+/*
+ * deallocate an inode
+ */
+void
+freeino(ino_t ino)
+{
+ struct inodesc idesc;
+ struct ext2fs_dinode *dp;
+
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = pass4check;
+ idesc.id_number = ino;
+ dp = ginode(ino);
+ (void)ckinode(dp, &idesc);
+ clearinode(dp);
+ inodirty();
+ statemap[ino] = USTATE;
+ n_files--;
+}
--- /dev/null
+/* $NetBSD: main.c,v 1.37 2011/06/09 19:57:51 christos Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
+#else
+__RCSID("$NetBSD: main.c,v 1.37 2011/06/09 19:57:51 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <fstab.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+volatile sig_atomic_t returntosingle = 0;
+
+
+static int argtoi(int, const char *, const char *, int);
+static int checkfilesys(const char *, char *, long, int);
+static void usage(void) __dead;
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ int ret = FSCK_EXIT_OK;
+
+ ckfinish = ckfini;
+ sync();
+ skipclean = 1;
+ while ((ch = getopt(argc, argv, "b:dfm:npPqUy")) != -1) {
+ switch (ch) {
+ case 'b':
+ skipclean = 0;
+ bflag = argtoi('b', "number", optarg, 10);
+ printf("Alternate super block location: %d\n", bflag);
+ break;
+
+ case 'd':
+ debug++;
+ break;
+
+ case 'f':
+ skipclean = 0;
+ break;
+
+ case 'm':
+ lfmode = argtoi('m', "mode", optarg, 8);
+ if (lfmode &~ 07777)
+ errexit("bad mode to -m: %o", lfmode);
+ printf("** lost+found creation mode %o\n", lfmode);
+ break;
+
+ case 'n':
+ nflag++;
+ yflag = 0;
+ break;
+
+ case 'p':
+ preen++;
+ break;
+
+ case 'P':
+ /* Progress meter not implemented. */
+ break;
+
+ case 'q': /* Quiet not implemented */
+ break;
+
+#ifndef SMALL
+ case 'U':
+ Uflag++;
+ break;
+#endif
+
+ case 'y':
+ yflag++;
+ nflag = 0;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (!argc)
+ usage();
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGINT, catch);
+ if (preen)
+ (void)signal(SIGQUIT, catchquit);
+
+ while (argc-- > 0) {
+ int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0);
+ if (ret < nret)
+ ret = nret;
+ }
+
+ return returntosingle ? FSCK_EXIT_UNRESOLVED : ret;
+}
+
+static int
+argtoi(int flag, const char *req, const char *str, int base)
+{
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errexit("-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+/*
+ * Check the specified filesystem.
+ */
+/* ARGSUSED */
+static int
+checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
+{
+ daddr_t n_bfree;
+ struct dups *dp;
+ struct zlncnt *zlnp;
+ int i;
+
+ if (preen && child)
+ (void)signal(SIGQUIT, voidquit);
+ setcdevname(filesys, preen);
+ if (debug && preen)
+ pwarn("starting\n");
+ switch (setup(filesys)) {
+ case 0:
+ if (preen)
+ pfatal("CAN'T CHECK FILE SYSTEM.");
+ case -1:
+ return FSCK_EXIT_OK;
+ }
+ /*
+ * 1: scan inodes tallying blocks used
+ */
+ if (preen == 0) {
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0) {
+ printf("** Last Mounted on %s\n",
+ sblock.e2fs.e2fs_fsmnt);
+ }
+ if (hotroot())
+ printf("** Root file system\n");
+ printf("** Phase 1 - Check Blocks and Sizes\n");
+ }
+ pass1();
+
+ /*
+ * 1b: locate first references to duplicates, if any
+ */
+ if (duplist) {
+ if (preen)
+ pfatal("INTERNAL ERROR: dups with -p");
+ printf("** Phase 1b - Rescan For More DUPS\n");
+ pass1b();
+ }
+
+ /*
+ * 2: traverse directories from root to mark all connected directories
+ */
+ if (preen == 0)
+ printf("** Phase 2 - Check Pathnames\n");
+ pass2();
+
+ /*
+ * 3: scan inodes looking for disconnected directories
+ */
+ if (preen == 0)
+ printf("** Phase 3 - Check Connectivity\n");
+ pass3();
+
+ /*
+ * 4: scan inodes looking for disconnected files; check reference counts
+ */
+ if (preen == 0)
+ printf("** Phase 4 - Check Reference Counts\n");
+ pass4();
+
+ /*
+ * 5: check and repair resource counts in cylinder groups
+ */
+ if (preen == 0)
+ printf("** Phase 5 - Check Cyl groups\n");
+ pass5();
+
+ /*
+ * print out summary statistics
+ */
+ n_bfree = sblock.e2fs.e2fs_fbcount;
+
+ pwarn("%lld files, %lld used, %lld free\n",
+ (long long)n_files, (long long)n_blks, (long long)n_bfree);
+ if (debug &&
+ /* 9 reserved and unused inodes in FS */
+ (n_files -= maxino - 9 - sblock.e2fs.e2fs_ficount))
+ printf("%lld files missing\n", (long long)n_files);
+ if (debug) {
+ for (i = 0; i < sblock.e2fs_ncg; i++)
+ n_blks += cgoverhead(i);
+ n_blks += sblock.e2fs.e2fs_first_dblock;
+ if (n_blks -= maxfsblock - n_bfree)
+ printf("%lld blocks missing\n", (long long)n_blks);
+ if (duplist != NULL) {
+ printf("The following duplicate blocks remain:");
+ for (dp = duplist; dp; dp = dp->next)
+ printf(" %lld,", (long long)dp->dup);
+ printf("\n");
+ }
+ if (zlnhead != NULL) {
+ printf("The following zero link count inodes remain:");
+ for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
+ printf(" %llu,",
+ (unsigned long long)zlnp->zlncnt);
+ printf("\n");
+ }
+ }
+ zlnhead = (struct zlncnt *)0;
+ duplist = (struct dups *)0;
+ muldup = (struct dups *)0;
+ inocleanup();
+ if (fsmodified) {
+ time_t t;
+ (void)time(&t);
+ sblock.e2fs.e2fs_wtime = t;
+ sblock.e2fs.e2fs_lastfsck = t;
+ sbdirty();
+ }
+ ckfini(1);
+ free(blockmap);
+ free(statemap);
+ free((char *)lncntp);
+ if (!fsmodified)
+ return FSCK_EXIT_OK;
+ if (!preen)
+ printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
+ if (rerun)
+ printf("\n***** PLEASE RERUN FSCK *****\n");
+#ifndef __minix
+ if (hotroot()) {
+ struct statvfs stfs_buf;
+ /*
+ * We modified the root. Do a mount update on
+ * it, unless it is read-write, so we can continue.
+ */
+ if (statvfs("/", &stfs_buf) == 0) {
+ long flags = stfs_buf.f_flag;
+ struct ufs_args args;
+
+ if (flags & MNT_RDONLY) {
+ args.fspec = 0;
+ flags |= MNT_UPDATE | MNT_RELOAD;
+ if (mount(MOUNT_EXT2FS, "/", flags,
+ &args, sizeof args) == 0)
+ return FSCK_EXIT_OK;
+ }
+ }
+ if (!preen)
+ printf("\n***** REBOOT NOW *****\n");
+ sync();
+ return FSCK_EXIT_ROOT_CHANGED;
+ }
+#endif
+ return FSCK_EXIT_OK;
+}
+
+static void
+usage(void)
+{
+
+ (void) fprintf(stderr,
+ "usage: %s [-dfnpUy] [-b block] [-c level] [-m mode] filesystem ...\n",
+ getprogname());
+ exit(FSCK_EXIT_USAGE);
+}
+
--- /dev/null
+/* $NetBSD: pass1.c,v 1.21 2010/02/04 23:55:42 christos Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass1.c,v 1.21 2010/02/04 23:55:42 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+static daddr_t badblk;
+static daddr_t dupblk;
+static void checkinode(ino_t, struct inodesc *);
+
+void
+pass1(void)
+{
+ ino_t inumber;
+ int c, i;
+ size_t j;
+ daddr_t dbase;
+ struct inodesc idesc;
+
+ /*
+ * Set file system reserved blocks in used block map.
+ */
+ for (c = 0; c < sblock.e2fs_ncg; c++) {
+ dbase = c * sblock.e2fs.e2fs_bpg +
+ sblock.e2fs.e2fs_first_dblock;
+ /* Mark the blocks used for the inode table */
+ if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) >= dbase) {
+ for (i = 0; i < sblock.e2fs_itpg; i++)
+ setbmap(
+ fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables)
+ + i);
+ }
+ /* Mark the blocks used for the block bitmap */
+ if (fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap) >= dbase)
+ setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap));
+ /* Mark the blocks used for the inode bitmap */
+ if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap) >= dbase)
+ setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap));
+
+ if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+ cg_has_sb(c)) {
+ /* Mark copuy of SB and descriptors */
+ setbmap(dbase);
+ for (i = 1; i <= sblock.e2fs_ngdb; i++)
+ setbmap(dbase+i);
+ }
+
+
+ if (c == 0) {
+ for(i = 0; i < dbase; i++)
+ setbmap(i);
+ }
+ }
+
+ /*
+ * Find all allocated blocks.
+ */
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = pass1check;
+ inumber = 1;
+ n_files = n_blks = 0;
+ resetinodebuf();
+ for (c = 0; c < sblock.e2fs_ncg; c++) {
+ for (j = 0;
+ j < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount;
+ j++, inumber++) {
+ if (inumber < EXT2_ROOTINO) /* XXX */
+ continue;
+ checkinode(inumber, &idesc);
+ }
+ }
+ freeinodebuf();
+}
+
+static void
+checkinode(ino_t inumber, struct inodesc *idesc)
+{
+ struct ext2fs_dinode *dp;
+ struct zlncnt *zlnp;
+ int ndb, j;
+ mode_t mode;
+
+ dp = getnextinode(inumber);
+ if (inumber < EXT2_FIRSTINO &&
+ inumber != EXT2_ROOTINO &&
+ !(inumber == EXT2_RESIZEINO &&
+ (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
+ return;
+
+ mode = fs2h16(dp->e2di_mode) & IFMT;
+ if (mode == 0 || (dp->e2di_dtime != 0 && dp->e2di_nlink == 0)) {
+ if (mode == 0 && (
+ memcmp(dp->e2di_blocks, zino.e2di_blocks,
+ (NDADDR + NIADDR) * sizeof(u_int32_t)) ||
+ dp->e2di_mode || inosize(dp))) {
+ pfatal("PARTIALLY ALLOCATED INODE I=%llu",
+ (unsigned long long)inumber);
+ if (reply("CLEAR") == 1) {
+ dp = ginode(inumber);
+ clearinode(dp);
+ inodirty();
+ }
+ }
+#ifdef notyet /* it seems that dtime == 0 is valid for a unallocated inode */
+ if (dp->e2di_dtime == 0) {
+ pwarn("DELETED INODE I=%llu HAS A NULL DTIME",
+ (unsigned long long)inumber);
+ if (preen) {
+ printf(" (CORRECTED)\n");
+ }
+ if (preen || reply("CORRECT")) {
+ time_t t;
+ time(&t);
+ dp->e2di_dtime = h2fs32(t);
+ dp = ginode(inumber);
+ inodirty();
+ }
+ }
+#endif
+ statemap[inumber] = USTATE;
+ return;
+ }
+ lastino = inumber;
+ if (dp->e2di_dtime != 0) {
+ pwarn("INODE I=%llu HAS DTIME=%s",
+ (unsigned long long)inumber,
+ print_mtime(fs2h32(dp->e2di_dtime)));
+ if (preen) {
+ printf(" (CORRECTED)\n");
+ }
+ if (preen || reply("CORRECT")) {
+ dp = ginode(inumber);
+ dp->e2di_dtime = 0;
+ inodirty();
+ }
+ }
+ if (inosize(dp) + sblock.e2fs_bsize - 1 < inosize(dp)) {
+ if (debug)
+ printf("bad size %llu:", (unsigned long long)inosize(dp));
+ goto unknown;
+ }
+ if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
+ dp = ginode(inumber);
+ dp->e2di_mode = h2fs16(IFREG|0600);
+ inossize(dp, sblock.e2fs_bsize);
+ inodirty();
+ }
+ ndb = howmany(inosize(dp), sblock.e2fs_bsize);
+ if (ndb < 0) {
+ if (debug)
+ printf("bad size %llu ndb %d:",
+ (unsigned long long)inosize(dp), ndb);
+ goto unknown;
+ }
+ if (mode == IFBLK || mode == IFCHR)
+ ndb++;
+ if (mode == IFLNK) {
+ /*
+ * Fake ndb value so direct/indirect block checks below
+ * will detect any garbage after symlink string.
+ */
+ if (inosize(dp) < EXT2_MAXSYMLINKLEN ||
+ (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) {
+ ndb = howmany(inosize(dp), sizeof(u_int32_t));
+ if (ndb > NDADDR) {
+ j = ndb - NDADDR;
+ for (ndb = 1; j > 1; j--)
+ ndb *= NINDIR(&sblock);
+ ndb += NDADDR;
+ }
+ }
+ }
+ /* Linux puts things in blocks for FIFO, so skip this check */
+ if (mode != IFIFO) {
+ for (j = ndb; j < NDADDR; j++)
+ if (dp->e2di_blocks[j] != 0) {
+ if (debug)
+ printf("bad direct addr: %d\n",
+ fs2h32(dp->e2di_blocks[j]));
+ goto unknown;
+ }
+ for (j = 0, ndb -= NDADDR; ndb > 0; j++)
+ ndb /= NINDIR(&sblock);
+ for (; j < NIADDR; j++) {
+ if (dp->e2di_blocks[j+NDADDR] != 0) {
+ if (debug)
+ printf("bad indirect addr: %d\n",
+ fs2h32(dp->e2di_blocks[j+NDADDR]));
+ goto unknown;
+ }
+ }
+ }
+ if (ftypeok(dp) == 0)
+ goto unknown;
+ if (inumber >= EXT2_FIRSTINO || inumber == EXT2_ROOTINO) {
+ /* Don't count reserved inodes except root */
+ n_files++;
+ }
+ lncntp[inumber] = fs2h16(dp->e2di_nlink);
+ if (dp->e2di_nlink == 0) {
+ zlnp = malloc(sizeof *zlnp);
+ if (zlnp == NULL) {
+ pfatal("LINK COUNT TABLE OVERFLOW");
+ if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ } else {
+ zlnp->zlncnt = inumber;
+ zlnp->next = zlnhead;
+ zlnhead = zlnp;
+ }
+ }
+ if (mode == IFDIR) {
+ if (inosize(dp) == 0)
+ statemap[inumber] = DCLEAR;
+ else
+ statemap[inumber] = DSTATE;
+ cacheino(dp, inumber);
+ } else {
+ statemap[inumber] = FSTATE;
+ }
+ typemap[inumber] = E2IFTODT(mode);
+ badblk = dupblk = 0;
+ idesc->id_number = inumber;
+ (void)ckinode(dp, idesc);
+ idesc->id_entryno *= btodb(sblock.e2fs_bsize);
+ if (fs2h32(dp->e2di_nblock) != (uint32_t)idesc->id_entryno) {
+ pwarn("INCORRECT BLOCK COUNT I=%llu (%d should be %d)",
+ (unsigned long long)inumber, fs2h32(dp->e2di_nblock),
+ idesc->id_entryno);
+ if (preen)
+ printf(" (CORRECTED)\n");
+ else if (reply("CORRECT") == 0)
+ return;
+ dp = ginode(inumber);
+ dp->e2di_nblock = h2fs32(idesc->id_entryno);
+ inodirty();
+ }
+ return;
+unknown:
+ pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
+ statemap[inumber] = FCLEAR;
+ if (reply("CLEAR") == 1) {
+ statemap[inumber] = USTATE;
+ dp = ginode(inumber);
+ clearinode(dp);
+ inodirty();
+ }
+}
+
+int
+pass1check(struct inodesc *idesc)
+{
+ int res = KEEPON;
+ int anyout, nfrags;
+ daddr_t blkno = idesc->id_blkno;
+ struct dups *dlp;
+ struct dups *new;
+
+ if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
+ blkerror(idesc->id_number, "BAD", blkno);
+ if (badblk++ >= MAXBAD) {
+ pwarn("EXCESSIVE BAD BLKS I=%llu",
+ (unsigned long long)idesc->id_number);
+ if (preen)
+ printf(" (SKIPPING)\n");
+ else if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ return (STOP);
+ }
+ }
+ for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+ if (anyout && chkrange(blkno, 1)) {
+ res = SKIP;
+ } else if (!testbmap(blkno)) {
+ n_blks++;
+ setbmap(blkno);
+ } else {
+ blkerror(idesc->id_number, "DUP", blkno);
+ if (dupblk++ >= MAXDUP) {
+ pwarn("EXCESSIVE DUP BLKS I=%llu",
+ (unsigned long long)idesc->id_number);
+ if (preen)
+ printf(" (SKIPPING)\n");
+ else if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ return (STOP);
+ }
+ new = malloc(sizeof(struct dups));
+ if (new == NULL) {
+ pfatal("DUP TABLE OVERFLOW.");
+ if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ return (STOP);
+ }
+ new->dup = blkno;
+ if (muldup == 0) {
+ duplist = muldup = new;
+ new->next = 0;
+ } else {
+ new->next = muldup->next;
+ muldup->next = new;
+ }
+ for (dlp = duplist; dlp != muldup; dlp = dlp->next)
+ if (dlp->dup == blkno)
+ break;
+ if (dlp == muldup && dlp->dup != blkno)
+ muldup = new;
+ }
+ /*
+ * count the number of blocks found in id_entryno
+ */
+ idesc->id_entryno++;
+ }
+ return (res);
+}
--- /dev/null
+/* $NetBSD: pass1b.c,v 1.8 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass1b.c 8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass1b.c,v 1.8 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <string.h>
+#include "fsck.h"
+#include "extern.h"
+
+static int pass1bcheck(struct inodesc *);
+static struct dups *duphead;
+
+void
+pass1b(void)
+{
+ int c;
+ uint32_t i;
+ struct ext2fs_dinode *dp;
+ struct inodesc idesc;
+ ino_t inumber;
+
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = pass1bcheck;
+ duphead = duplist;
+ inumber = 0;
+ for (c = 0; c < sblock.e2fs_ncg; c++) {
+ for (i = 0; i < sblock.e2fs.e2fs_ipg; i++, inumber++) {
+ if ((inumber < EXT2_FIRSTINO) && (inumber != EXT2_ROOTINO))
+ continue;
+ dp = ginode(inumber);
+ if (dp == NULL)
+ continue;
+ idesc.id_number = inumber;
+ if (statemap[inumber] != USTATE &&
+ (ckinode(dp, &idesc) & STOP))
+ return;
+ }
+ }
+}
+
+static int
+pass1bcheck(struct inodesc *idesc)
+{
+ struct dups *dlp;
+ int nfrags, res = KEEPON;
+ daddr_t blkno = idesc->id_blkno;
+
+ for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+ if (chkrange(blkno, 1))
+ res = SKIP;
+ for (dlp = duphead; dlp; dlp = dlp->next) {
+ if (dlp->dup == blkno) {
+ blkerror(idesc->id_number, "DUP", blkno);
+ dlp->dup = duphead->dup;
+ duphead->dup = blkno;
+ duphead = duphead->next;
+ }
+ if (dlp == muldup)
+ break;
+ }
+ if (muldup == 0 || duphead == muldup->next)
+ return (STOP);
+ }
+ return (res);
+}
--- /dev/null
+/* $NetBSD: pass2.c,v 1.15 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass2.c 8.6 (Berkeley) 10/27/94";
+#else
+__RCSID("$NetBSD: pass2.c,v 1.15 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+#include "exitvalues.h"
+
+#define MINDIRSIZE (sizeof (struct ext2fs_dirtemplate))
+
+static int pass2check(struct inodesc *);
+static int blksort(const void *, const void *);
+
+void
+pass2(void)
+{
+ struct ext2fs_dinode *dp;
+ struct inoinfo **inpp, *inp;
+ struct inoinfo **inpend;
+ struct inodesc curino;
+ struct ext2fs_dinode dino;
+ char pathbuf[MAXPATHLEN + 1];
+
+ switch (statemap[EXT2_ROOTINO]) {
+
+ case USTATE:
+ pfatal("ROOT INODE UNALLOCATED");
+ if (reply("ALLOCATE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+ errexit("CANNOT ALLOCATE ROOT INODE");
+ break;
+
+ case DCLEAR:
+ pfatal("DUPS/BAD IN ROOT INODE");
+ if (reply("REALLOCATE")) {
+ freeino(EXT2_ROOTINO);
+ if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+ errexit("CANNOT ALLOCATE ROOT INODE");
+ break;
+ }
+ if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ break;
+
+ case FSTATE:
+ case FCLEAR:
+ pfatal("ROOT INODE NOT DIRECTORY");
+ if (reply("REALLOCATE")) {
+ freeino(EXT2_ROOTINO);
+ if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+ errexit("CANNOT ALLOCATE ROOT INODE");
+ break;
+ }
+ if (reply("FIX") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ dp = ginode(EXT2_ROOTINO);
+ dp->e2di_mode = h2fs16((fs2h16(dp->e2di_mode) & ~IFMT) | IFDIR);
+ inodirty();
+ break;
+
+ case DSTATE:
+ break;
+
+ default:
+ errexit("BAD STATE %d FOR ROOT INODE", statemap[EXT2_ROOTINO]);
+ }
+
+ /*
+ * Sort the directory list into disk block order.
+ */
+ qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
+ /*
+ * Check the integrity of each directory.
+ */
+ memset(&curino, 0, sizeof(struct inodesc));
+ curino.id_type = DATA;
+ curino.id_func = pass2check;
+ inpend = &inpsort[inplast];
+ for (inpp = inpsort; inpp < inpend; inpp++) {
+ inp = *inpp;
+ if (inp->i_isize == 0)
+ continue;
+ if (inp->i_isize < MINDIRSIZE) {
+ direrror(inp->i_number, "DIRECTORY TOO SHORT");
+ inp->i_isize = roundup(MINDIRSIZE, sblock.e2fs_bsize);
+ if (reply("FIX") == 1) {
+ dp = ginode(inp->i_number);
+ inossize(dp, inp->i_isize);
+ inodirty();
+ }
+ } else if ((inp->i_isize & (sblock.e2fs_bsize - 1)) != 0) {
+ getpathname(pathbuf, sizeof(pathbuf), inp->i_number,
+ inp->i_number);
+ pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d",
+ pathbuf, (u_long)inp->i_isize, sblock.e2fs_bsize);
+ if (preen)
+ printf(" (ADJUSTED)\n");
+ inp->i_isize = roundup(inp->i_isize, sblock.e2fs_bsize);
+ if (preen || reply("ADJUST") == 1) {
+ dp = ginode(inp->i_number);
+ inossize(dp, inp->i_isize);
+ inodirty();
+ }
+ }
+ memset(&dino, 0, sizeof(struct ext2fs_dinode));
+ dino.e2di_mode = h2fs16(IFDIR);
+ inossize(&dino, inp->i_isize);
+ memcpy(&dino.e2di_blocks[0], &inp->i_blks[0], (size_t)inp->i_numblks);
+ curino.id_number = inp->i_number;
+ curino.id_parent = inp->i_parent;
+ (void)ckinode(&dino, &curino);
+ }
+ /*
+ * Now that the parents of all directories have been found,
+ * make another pass to verify the value of `..'
+ */
+ for (inpp = inpsort; inpp < inpend; inpp++) {
+ inp = *inpp;
+ if (inp->i_parent == 0 || inp->i_isize == 0)
+ continue;
+ if (inp->i_dotdot == inp->i_parent ||
+ inp->i_dotdot == (ino_t)-1)
+ continue;
+ if (inp->i_dotdot == 0) {
+ inp->i_dotdot = inp->i_parent;
+ fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
+ if (reply("FIX") == 0)
+ continue;
+ (void)makeentry(inp->i_number, inp->i_parent, "..");
+ lncntp[inp->i_parent]--;
+ continue;
+ }
+ fileerror(inp->i_parent, inp->i_number,
+ "BAD INODE NUMBER FOR '..'");
+ if (reply("FIX") == 0)
+ continue;
+ lncntp[inp->i_dotdot]++;
+ lncntp[inp->i_parent]--;
+ inp->i_dotdot = inp->i_parent;
+ (void)changeino(inp->i_number, "..", inp->i_parent);
+ }
+ /*
+ * Mark all the directories that can be found from the root.
+ */
+ propagate();
+}
+
+static int
+pass2check(struct inodesc *idesc)
+{
+ struct ext2fs_direct *dirp = idesc->id_dirp;
+ struct inoinfo *inp;
+ int n, entrysize, ret = 0;
+ struct ext2fs_dinode *dp;
+ const char *errmsg;
+ struct ext2fs_direct proto;
+ char namebuf[MAXPATHLEN + 1];
+ char pathbuf[MAXPATHLEN + 1];
+
+ /*
+ * check for "."
+ */
+ if (idesc->id_entryno != 0)
+ goto chk1;
+ if (fs2h32(dirp->e2d_ino) != 0 && dirp->e2d_namlen == 1 &&
+ dirp->e2d_name[0] == '.') {
+ if (fs2h32(dirp->e2d_ino) != idesc->id_number) {
+ direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
+ dirp->e2d_ino = h2fs32(idesc->id_number);
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)
+ && (dirp->e2d_type != EXT2_FT_DIR)) {
+ direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
+ dirp->e2d_type = EXT2_FT_DIR;
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+ goto chk1;
+ }
+ direrror(idesc->id_number, "MISSING '.'");
+ proto.e2d_ino = h2fs32(idesc->id_number);
+ proto.e2d_namlen = 1;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ proto.e2d_type = EXT2_FT_DIR;
+ else
+ proto.e2d_type = 0;
+ (void)strlcpy(proto.e2d_name, ".", sizeof(proto.e2d_name));
+ entrysize = EXT2FS_DIRSIZ(proto.e2d_namlen);
+ if (fs2h32(dirp->e2d_ino) != 0 && strcmp(dirp->e2d_name, "..") != 0) {
+ pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
+ dirp->e2d_name);
+ } else if (fs2h16(dirp->e2d_reclen) < entrysize) {
+ pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
+ } else if (fs2h16(dirp->e2d_reclen) < 2 * entrysize) {
+ proto.e2d_reclen = dirp->e2d_reclen;
+ memcpy(dirp, &proto, (size_t)entrysize);
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ } else {
+ n = fs2h16(dirp->e2d_reclen) - entrysize;
+ proto.e2d_reclen = h2fs16(entrysize);
+ memcpy(dirp, &proto, (size_t)entrysize);
+ idesc->id_entryno++;
+ lncntp[fs2h32(dirp->e2d_ino)]--;
+ dirp = (struct ext2fs_direct *)((char *)(dirp) + entrysize);
+ memset(dirp, 0, (size_t)n);
+ dirp->e2d_reclen = h2fs16(n);
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+chk1:
+ if (idesc->id_entryno > 1)
+ goto chk2;
+ inp = getinoinfo(idesc->id_number);
+ proto.e2d_ino = h2fs32(inp->i_parent);
+ proto.e2d_namlen = 2;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+ proto.e2d_type = EXT2_FT_DIR;
+ else
+ proto.e2d_type = 0;
+ (void)strlcpy(proto.e2d_name, "..", sizeof(proto.e2d_name));
+ entrysize = EXT2FS_DIRSIZ(2);
+ if (idesc->id_entryno == 0) {
+ n = EXT2FS_DIRSIZ(dirp->e2d_namlen);
+ if (fs2h16(dirp->e2d_reclen) < n + entrysize)
+ goto chk2;
+ proto.e2d_reclen = h2fs16(fs2h16(dirp->e2d_reclen) - n);
+ dirp->e2d_reclen = h2fs16(n);
+ idesc->id_entryno++;
+ lncntp[fs2h32(dirp->e2d_ino)]--;
+ dirp = (struct ext2fs_direct *)((char *)(dirp) + n);
+ memset(dirp, 0, (size_t)fs2h16(proto.e2d_reclen));
+ dirp->e2d_reclen = proto.e2d_reclen;
+ }
+ if (fs2h32(dirp->e2d_ino) != 0 &&
+ dirp->e2d_namlen == 2 &&
+ strncmp(dirp->e2d_name, "..", 2) == 0) {
+ inp->i_dotdot = fs2h32(dirp->e2d_ino);
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)
+ && dirp->e2d_type != EXT2_FT_DIR) {
+ direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
+ dirp->e2d_type = EXT2_FT_DIR;
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+ goto chk2;
+ }
+ if (fs2h32(dirp->e2d_ino) != 0 &&
+ dirp->e2d_namlen == 1 &&
+ strncmp(dirp->e2d_name, ".", 1) != 0) {
+ fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+ pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
+ dirp->e2d_name);
+ inp->i_dotdot = (ino_t)-1;
+ } else if (fs2h16(dirp->e2d_reclen) < entrysize) {
+ fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+ pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
+ inp->i_dotdot = (ino_t)-1;
+ } else if (inp->i_parent != 0) {
+ /*
+ * We know the parent, so fix now.
+ */
+ inp->i_dotdot = inp->i_parent;
+ fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+ proto.e2d_reclen = dirp->e2d_reclen;
+ memcpy(dirp, &proto, (size_t)entrysize);
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+ idesc->id_entryno++;
+ if (fs2h32(dirp->e2d_ino) != 0)
+ lncntp[fs2h32(dirp->e2d_ino)]--;
+ return (ret|KEEPON);
+chk2:
+ if (fs2h32(dirp->e2d_ino) == 0)
+ return (ret|KEEPON);
+ if (dirp->e2d_namlen <= 2 &&
+ dirp->e2d_name[0] == '.' &&
+ idesc->id_entryno >= 2) {
+ if (dirp->e2d_namlen == 1) {
+ direrror(idesc->id_number, "EXTRA '.' ENTRY");
+ dirp->e2d_ino = 0;
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ return (KEEPON | ret);
+ }
+ if (dirp->e2d_name[1] == '.') {
+ direrror(idesc->id_number, "EXTRA '..' ENTRY");
+ dirp->e2d_ino = 0;
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ return (KEEPON | ret);
+ }
+ }
+ idesc->id_entryno++;
+ n = 0;
+ if (fs2h32(dirp->e2d_ino) > maxino ||
+ (fs2h32(dirp->e2d_ino) < EXT2_FIRSTINO &&
+ fs2h32(dirp->e2d_ino) != EXT2_ROOTINO)) {
+ fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), "I OUT OF RANGE");
+ n = reply("REMOVE");
+ } else {
+again:
+ switch (statemap[fs2h32(dirp->e2d_ino)]) {
+ case USTATE:
+ if (idesc->id_entryno <= 2)
+ break;
+ fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), "UNALLOCATED");
+ n = reply("REMOVE");
+ break;
+
+ case DCLEAR:
+ case FCLEAR:
+ if (idesc->id_entryno <= 2)
+ break;
+ if (statemap[fs2h32(dirp->e2d_ino)] == FCLEAR)
+ errmsg = "DUP/BAD";
+ else if (!preen)
+ errmsg = "ZERO LENGTH DIRECTORY";
+ else {
+ n = 1;
+ break;
+ }
+ fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), errmsg);
+ if ((n = reply("REMOVE")) == 1)
+ break;
+ dp = ginode(fs2h32(dirp->e2d_ino));
+ statemap[fs2h32(dirp->e2d_ino)] =
+ (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
+ lncntp[fs2h32(dirp->e2d_ino)] = fs2h16(dp->e2di_nlink);
+ goto again;
+
+ case DSTATE:
+ case DFOUND:
+ inp = getinoinfo(fs2h32(dirp->e2d_ino));
+ if (inp->i_parent != 0 && idesc->id_entryno > 2) {
+ getpathname(pathbuf, sizeof(pathbuf),
+ idesc->id_number, idesc->id_number);
+ getpathname(namebuf, sizeof(namebuf),
+ fs2h32(dirp->e2d_ino),
+ fs2h32(dirp->e2d_ino));
+ pwarn("%s %s %s\n", pathbuf,
+ "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
+ namebuf);
+ if (preen)
+ printf(" (IGNORED)\n");
+ else if ((n = reply("REMOVE")) == 1)
+ break;
+ }
+ if (idesc->id_entryno > 2)
+ inp->i_parent = idesc->id_number;
+ /* fall through */
+
+ case FSTATE:
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_incompat &
+ EXT2F_INCOMPAT_FTYPE) &&
+ dirp->e2d_type !=
+ inot2ext2dt(typemap[fs2h32(dirp->e2d_ino)])) {
+ dirp->e2d_type =
+ inot2ext2dt(typemap[fs2h32(dirp->e2d_ino)]);
+ fileerror(idesc->id_number,
+ fs2h32(dirp->e2d_ino),
+ "BAD TYPE VALUE");
+ if (reply("FIX") == 1)
+ ret |= ALTERED;
+ }
+ lncntp[fs2h32(dirp->e2d_ino)]--;
+ break;
+
+ default:
+ errexit("BAD STATE %d FOR INODE I=%d",
+ statemap[fs2h32(dirp->e2d_ino)], fs2h32(dirp->e2d_ino));
+ }
+ }
+ if (n == 0)
+ return (ret|KEEPON);
+ dirp->e2d_ino = 0;
+ return (ret|KEEPON|ALTERED);
+}
+
+/*
+ * Routine to sort disk blocks.
+ */
+static int
+blksort(const void *inpp1, const void *inpp2)
+{
+ return ((* (const struct inoinfo * const*) inpp1)->i_blks[0] -
+ (* (const struct inoinfo * const*) inpp2)->i_blks[0]);
+}
--- /dev/null
+/* $NetBSD: pass3.c,v 1.7 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass3.c 8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass3.c,v 1.7 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include "fsck.h"
+#include "extern.h"
+
+void
+pass3(void)
+{
+ struct inoinfo **inpp, *inp;
+ ino_t orphan;
+ int loopcnt;
+
+ for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
+ inp = *inpp;
+ if (inp->i_number == EXT2_ROOTINO ||
+ !(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
+ continue;
+ if (statemap[inp->i_number] == DCLEAR)
+ continue;
+ for (loopcnt = 0; ; loopcnt++) {
+ orphan = inp->i_number;
+ if (inp->i_parent == 0 ||
+ statemap[inp->i_parent] != DSTATE ||
+ loopcnt > numdirs)
+ break;
+ inp = getinoinfo(inp->i_parent);
+ }
+ (void)linkup(orphan, inp->i_dotdot);
+ inp->i_parent = inp->i_dotdot = lfdir;
+ lncntp[lfdir]--;
+ statemap[orphan] = DFOUND;
+ propagate();
+ }
+}
--- /dev/null
+/* $NetBSD: pass4.c,v 1.10 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass4.c 8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass4.c,v 1.10 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+
+void
+pass4(void)
+{
+ ino_t inumber;
+ struct zlncnt *zlnp;
+ struct ext2fs_dinode *dp;
+ struct inodesc idesc;
+ int n;
+
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = pass4check;
+ for (inumber = EXT2_ROOTINO; inumber <= lastino; inumber++) {
+ if (inumber < EXT2_FIRSTINO && inumber > EXT2_ROOTINO)
+ continue;
+ idesc.id_number = inumber;
+ switch (statemap[inumber]) {
+
+ case FSTATE:
+ case DFOUND:
+ n = lncntp[inumber];
+ if (n)
+ adjust(&idesc, (short)n);
+ else {
+ for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
+ if (zlnp->zlncnt == inumber) {
+ zlnp->zlncnt = zlnhead->zlncnt;
+ zlnp = zlnhead;
+ zlnhead = zlnhead->next;
+ free((char *)zlnp);
+ clri(&idesc, "UNREF", 1);
+ break;
+ }
+ }
+ break;
+
+ case DSTATE:
+ clri(&idesc, "UNREF", 1);
+ break;
+
+ case DCLEAR:
+ dp = ginode(inumber);
+ if (inosize(dp) == 0) {
+ clri(&idesc, "ZERO LENGTH", 1);
+ break;
+ }
+ /* fall through */
+ case FCLEAR:
+ clri(&idesc, "BAD/DUP", 1);
+ break;
+
+ case USTATE:
+ break;
+
+ default:
+ errexit("BAD STATE %d FOR INODE I=%llu",
+ statemap[inumber], (unsigned long long)inumber);
+ }
+ }
+}
+
+int
+pass4check(struct inodesc *idesc)
+{
+ struct dups *dlp;
+ int nfrags, res = KEEPON;
+ daddr_t blkno = idesc->id_blkno;
+
+ for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+ if (chkrange(blkno, 1)) {
+ res = SKIP;
+ } else if (testbmap(blkno)) {
+ for (dlp = duplist; dlp; dlp = dlp->next) {
+ if (dlp->dup != blkno)
+ continue;
+ dlp->dup = duplist->dup;
+ dlp = duplist;
+ duplist = duplist->next;
+ free((char *)dlp);
+ break;
+ }
+ if (dlp == 0) {
+ clrbmap(blkno);
+ n_blks--;
+ }
+ }
+ }
+ return (res);
+}
--- /dev/null
+/* $NetBSD: pass5.c,v 1.19 2011/08/06 16:42:41 dholland Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass5.c 8.6 (Berkeley) 11/30/94";
+#else
+__RCSID("$NetBSD: pass5.c,v 1.19 2011/08/06 16:42:41 dholland Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <inttypes.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+
+
+static void print_bmap(char *, uint32_t);
+
+void
+pass5(void)
+{
+ int c;
+ struct m_ext2fs *fs = &sblock;
+ daddr_t dbase, dmax;
+ daddr_t d;
+ uint32_t i, j;
+ struct inodesc idesc[3];
+ struct bufarea *ino_bitmap = NULL, *blk_bitmap = NULL;
+ char *ibmap, *bbmap;
+ u_int32_t cs_ndir, cs_nbfree, cs_nifree;
+ char msg[255];
+
+ cs_ndir = 0;
+ cs_nbfree = 0;
+ cs_nifree = 0;
+
+ ibmap = malloc(fs->e2fs_bsize);
+ bbmap = malloc(fs->e2fs_bsize);
+ if (ibmap == NULL || bbmap == NULL) {
+ errexit("out of memory");
+ }
+
+ for (c = 0; c < fs->e2fs_ncg; c++) {
+ u_int32_t nbfree = 0;
+ u_int32_t nifree = 0;
+ u_int32_t ndirs = 0;
+
+ nbfree = 0;
+ nifree = fs->e2fs.e2fs_ipg;
+ ndirs = 0;
+
+ if (blk_bitmap == NULL) {
+ blk_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
+ fs->e2fs_bsize);
+ } else {
+ getblk(blk_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
+ fs->e2fs_bsize);
+ }
+ if (ino_bitmap == NULL) {
+ ino_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
+ fs->e2fs_bsize);
+ } else {
+ getblk(ino_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
+ fs->e2fs_bsize);
+ }
+ memset(bbmap, 0, fs->e2fs_bsize);
+ memset(ibmap, 0, fs->e2fs_bsize);
+ memset(&idesc[0], 0, sizeof idesc);
+ for (i = 0; i < 3; i++) {
+ idesc[i].id_type = ADDR;
+ }
+
+ j = fs->e2fs.e2fs_ipg * c + 1;
+
+ for (i = 0; i < fs->e2fs.e2fs_ipg; j++, i++) {
+ if ((j < EXT2_FIRSTINO) && (j != EXT2_ROOTINO)) {
+ setbit(ibmap, i);
+ nifree--;
+ continue;
+ }
+ if (j > fs->e2fs.e2fs_icount) {
+ setbit(ibmap, i);
+ continue;
+ }
+ switch (statemap[j]) {
+
+ case USTATE:
+ break;
+
+ case DSTATE:
+ case DCLEAR:
+ case DFOUND:
+ ndirs++;
+ /* fall through */
+
+ case FSTATE:
+ case FCLEAR:
+ nifree--;
+ setbit(ibmap, i);
+ break;
+
+ default:
+ errexit("BAD STATE %d FOR INODE I=%"PRIu32,
+ statemap[j], j);
+ }
+ }
+
+ /* fill in unused par of the inode map */
+ for (i = fs->e2fs.e2fs_ipg / NBBY; i < (uint32_t)fs->e2fs_bsize; i++)
+ ibmap[i] = 0xff;
+
+ dbase = c * sblock.e2fs.e2fs_bpg +
+ sblock.e2fs.e2fs_first_dblock;
+ dmax = (c+1) * sblock.e2fs.e2fs_bpg +
+ sblock.e2fs.e2fs_first_dblock;
+
+ for (i = 0, d = dbase;
+ d < dmax;
+ d ++, i ++) {
+ if (testbmap(d) || d >= sblock.e2fs.e2fs_bcount) {
+ setbit(bbmap, i);
+ continue;
+ } else {
+ nbfree++;
+ }
+
+ }
+ cs_nbfree += nbfree;
+ cs_nifree += nifree;
+ cs_ndir += ndirs;
+
+ if (debug && (fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
+ fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
+ fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs)) {
+ printf("summary info for cg %d is %d, %d, %d,"
+ "should be %d, %d, %d\n", c,
+ fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree),
+ fs2h16(fs->e2fs_gd[c].ext2bgd_nifree),
+ fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs),
+ nbfree,
+ nifree,
+ ndirs);
+ }
+ (void)snprintf(msg, sizeof(msg),
+ "SUMMARY INFORMATIONS WRONG FOR CG #%d", c);
+ if ((fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
+ fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
+ fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs) &&
+ dofix(&idesc[0], msg)) {
+ fs->e2fs_gd[c].ext2bgd_nbfree = h2fs16(nbfree);
+ fs->e2fs_gd[c].ext2bgd_nifree = h2fs16(nifree);
+ fs->e2fs_gd[c].ext2bgd_ndirs = h2fs16(ndirs);
+ sbdirty();
+ }
+
+ if (debug && memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize)) {
+ printf("blk_bitmap:\n");
+ print_bmap(blk_bitmap->b_un.b_buf, fs->e2fs_bsize);
+ printf("bbmap:\n");
+ print_bmap(bbmap, fs->e2fs_bsize);
+ }
+
+ (void)snprintf(msg, sizeof(msg),
+ "BLK(S) MISSING IN BIT MAPS #%d", c);
+ if (memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize) &&
+ dofix(&idesc[1], msg)) {
+ memcpy(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize);
+ dirty(blk_bitmap);
+ }
+ if (debug && memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize)) {
+ printf("ino_bitmap:\n");
+ print_bmap(ino_bitmap->b_un.b_buf, fs->e2fs_bsize);
+ printf("ibmap:\n");
+ print_bmap(ibmap, fs->e2fs_bsize);
+ }
+ (void)snprintf(msg, sizeof(msg),
+ "INODE(S) MISSING IN BIT MAPS #%d", c);
+ if (memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize) &&
+ dofix(&idesc[1], msg)) {
+ memcpy(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize);
+ dirty(ino_bitmap);
+ }
+
+ }
+ if (debug && (fs->e2fs.e2fs_fbcount != cs_nbfree ||
+ fs->e2fs.e2fs_ficount != cs_nifree)) {
+ printf("summary info bad in superblock: %d, %d should be %d, %d\n",
+ fs->e2fs.e2fs_fbcount, fs->e2fs.e2fs_ficount,
+ cs_nbfree, cs_nifree);
+ }
+ if ((fs->e2fs.e2fs_fbcount != cs_nbfree ||
+ fs->e2fs.e2fs_ficount != cs_nifree)
+ && dofix(&idesc[0], "SUPERBLK SUMMARY INFORMATION BAD")) {
+ fs->e2fs.e2fs_fbcount = cs_nbfree;
+ fs->e2fs.e2fs_ficount = cs_nifree;
+ sbdirty();
+ }
+ free(ibmap);
+ free(bbmap);
+}
+
+static void
+print_bmap(char *map, uint32_t size)
+{
+ uint32_t i, j;
+
+ i = 0;
+ while (i < size) {
+ printf("%04x: ",i);
+ for (j = 0; j < 16; j++, i++)
+ printf("%02x ", (unsigned char)map[i] & 0xff);
+ printf("\n");
+ }
+}
--- /dev/null
+/* $NetBSD: setup.c,v 1.28 2011/09/16 16:13:18 plunky Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)setup.c 8.5 (Berkeley) 11/23/94";
+#else
+__RCSID("$NetBSD: setup.c,v 1.28 2011/09/16 16:13:18 plunky Exp $");
+#endif
+#endif /* not lint */
+
+#define FSTYPENAMES
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/file.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+void badsb(int, const char *);
+int calcsb(const char *, int, struct m_ext2fs *);
+static struct disklabel *getdisklabel(const char *, int);
+static int readsb(int);
+
+int
+setup(const char *dev)
+{
+ long cg, asked, i;
+ long bmapsize;
+ struct disklabel *lp;
+#ifndef __minix
+ off_t sizepb;
+#else
+ u64_t sizepb;
+#endif
+ struct stat statb;
+ struct m_ext2fs proto;
+ int doskipclean;
+ u_int64_t maxfilesize;
+
+ havesb = 0;
+ fswritefd = -1;
+ doskipclean = skipclean;
+ if (stat(dev, &statb) < 0) {
+ printf("Can't stat %s: %s\n", dev, strerror(errno));
+ return 0;
+ }
+
+#ifndef __minix
+ if (!S_ISCHR(statb.st_mode)) {
+ pfatal("%s is not a character device", dev);
+ if (reply("CONTINUE") == 0)
+ return 0;
+ }
+#endif
+
+ if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
+ printf("Can't open %s: %s\n", dev, strerror(errno));
+ return 0;
+ }
+ if (preen == 0)
+ printf("** %s", dev);
+ if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
+ fswritefd = -1;
+ if (preen)
+ pfatal("NO WRITE ACCESS");
+ printf(" (NO WRITE)");
+ }
+ if (preen == 0)
+ printf("\n");
+ fsmodified = 0;
+ lfdir = 0;
+ initbarea(&sblk);
+ initbarea(&asblk);
+ sblk.b_un.b_buf = malloc(SBSIZE);
+ asblk.b_un.b_buf = malloc(SBSIZE);
+ if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
+ errexit("cannot allocate space for superblock");
+ if ((lp = getdisklabel(NULL, fsreadfd)) != NULL)
+ dev_bsize = secsize = lp->d_secsize;
+ else
+ dev_bsize = secsize = DEV_BSIZE;
+ /*
+ * Read in the superblock, looking for alternates if necessary
+ */
+ if (readsb(1) == 0) {
+ if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
+ return 0;
+ if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
+ return 0;
+ for (cg = 1; cg < proto.e2fs_ncg; cg++) {
+ bflag = fsbtodb(&proto,
+ cg * proto.e2fs.e2fs_bpg +
+ proto.e2fs.e2fs_first_dblock);
+ if (readsb(0) != 0)
+ break;
+ }
+ if (cg >= proto.e2fs_ncg) {
+ printf("%s %s\n%s %s\n%s %s\n",
+ "SEARCH FOR ALTERNATE SUPER-BLOCK",
+ "FAILED. YOU MUST USE THE",
+ "-b OPTION TO FSCK_FFS TO SPECIFY THE",
+ "LOCATION OF AN ALTERNATE",
+ "SUPER-BLOCK TO SUPPLY NEEDED",
+ "INFORMATION; SEE fsck_ext2fs(8).");
+ return 0;
+ }
+ doskipclean = 0;
+ pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
+ }
+ if (debug)
+ printf("state = %d\n", sblock.e2fs.e2fs_state);
+ if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) {
+ if (doskipclean) {
+ pwarn("%sile system is clean; not checking\n",
+ preen ? "f" : "** F");
+ return -1;
+ }
+ if (!preen)
+ pwarn("** File system is already clean\n");
+ }
+ maxfsblock = sblock.e2fs.e2fs_bcount;
+ maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg;
+ sizepb = sblock.e2fs_bsize;
+ maxfilesize = sblock.e2fs_bsize * NDADDR - 1;
+ for (i = 0; i < NIADDR; i++) {
+ sizepb *= NINDIR(&sblock);
+ maxfilesize += sizepb;
+ }
+ /*
+ * Check and potentially fix certain fields in the super block.
+ */
+ if (/* (sblock.e2fs.e2fs_rbcount < 0) || */
+ (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) {
+ pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK",
+ sblock.e2fs.e2fs_rbcount);
+ if (reply("SET TO DEFAULT") == 1) {
+ sblock.e2fs.e2fs_rbcount =
+ sblock.e2fs.e2fs_bcount * MINFREE / 100;
+ sbdirty();
+ dirty(&asblk);
+ }
+ }
+ if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) {
+ pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK",
+ sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg);
+ return 0;
+ }
+ if (asblk.b_dirty && !bflag) {
+ copyback_sb(&asblk);
+ flush(fswritefd, &asblk);
+ }
+ /*
+ * read in the summary info.
+ */
+
+ sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize);
+ if (sblock.e2fs_gd == NULL)
+ errexit("out of memory");
+ asked = 0;
+ for (i = 0; i < sblock.e2fs_ngdb; i++) {
+ if (bread(fsreadfd,
+ (char *)&sblock.e2fs_gd[i * sblock.e2fs_bsize /
+ sizeof(struct ext2_gd)],
+ fsbtodb(&sblock, ((sblock.e2fs_bsize > 1024) ? 0 : 1) +
+ i + 1),
+ sblock.e2fs_bsize) != 0 && !asked) {
+ pfatal("BAD SUMMARY INFORMATION");
+ if (reply("CONTINUE") == 0)
+ exit(FSCK_EXIT_CHECK_FAILED);
+ asked++;
+ }
+ }
+ /*
+ * allocate and initialize the necessary maps
+ */
+ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
+ blockmap = calloc((unsigned int)bmapsize, sizeof(char));
+ if (blockmap == NULL) {
+ printf("cannot alloc %u bytes for blockmap\n",
+ (unsigned int)bmapsize);
+ goto badsblabel;
+ }
+ statemap = calloc((unsigned int)(maxino + 2), sizeof(char));
+ if (statemap == NULL) {
+ printf("cannot alloc %u bytes for statemap\n",
+ (unsigned int)(maxino + 1));
+ goto badsblabel;
+ }
+ typemap = calloc((unsigned int)(maxino + 1), sizeof(char));
+ if (typemap == NULL) {
+ printf("cannot alloc %u bytes for typemap\n",
+ (unsigned int)(maxino + 1));
+ goto badsblabel;
+ }
+ lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t));
+ if (lncntp == NULL) {
+ printf("cannot alloc %u bytes for lncntp\n",
+ (unsigned int)((maxino + 1) * sizeof(int16_t)));
+ goto badsblabel;
+ }
+ for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) {
+ numdirs += fs2h16(sblock.e2fs_gd[cg].ext2bgd_ndirs);
+ }
+ inplast = 0;
+ listmax = numdirs + 10;
+ inpsort = calloc((unsigned int)listmax, sizeof(struct inoinfo *));
+ inphead = calloc((unsigned int)numdirs, sizeof(struct inoinfo *));
+ if (inpsort == NULL || inphead == NULL) {
+ printf("cannot alloc %u bytes for inphead\n",
+ (unsigned int)(numdirs * sizeof(struct inoinfo *)));
+ goto badsblabel;
+ }
+ bufinit();
+ return 1;
+
+badsblabel:
+ ckfini(0);
+ return 0;
+}
+
+/*
+ * Read in the super block and its summary info, convert to host byte order.
+ */
+static int
+readsb(int listerr)
+{
+ daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
+
+ if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0)
+ return 0;
+ sblk.b_bno = super;
+ sblk.b_size = SBSIZE;
+
+ /* Copy the superblock in memory */
+ e2fs_sbload(sblk.b_un.b_fs, &sblock.e2fs);
+
+ /*
+ * run a few consistency checks of the super block
+ */
+ if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) {
+ badsb(listerr, "MAGIC NUMBER WRONG");
+ return 0;
+ }
+ if (sblock.e2fs.e2fs_log_bsize > 2) {
+ badsb(listerr, "BAD LOG_BSIZE");
+ return 0;
+ }
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (!powerof2(sblock.e2fs.e2fs_inode_size) ||
+ sblock.e2fs.e2fs_inode_size < sizeof(struct ext2fs_dinode) ||
+ sblock.e2fs.e2fs_inode_size >
+ (1024 << sblock.e2fs.e2fs_log_bsize))) {
+ badsb(listerr, "BAD INODE_SIZE");
+ return 0;
+ }
+
+ /* compute the dynamic fields of the in-memory sb */
+ /* compute dynamic sb infos */
+ sblock.e2fs_ncg =
+ howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock,
+ sblock.e2fs.e2fs_bpg);
+ /* XXX assume hw bsize = 512 */
+ sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1;
+ sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize;
+ sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize;
+ sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
+ sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
+ sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg,
+ sblock.e2fs_bsize / sizeof(struct ext2_gd));
+ sblock.e2fs_ipb = sblock.e2fs_bsize / EXT2_DINODE_SIZE(&sblock);
+ sblock.e2fs_itpg = howmany(sblock.e2fs.e2fs_ipg, sblock.e2fs_ipb);
+
+ /*
+ * Compute block size that the filesystem is based on,
+ * according to fsbtodb, and adjust superblock block number
+ * so we can tell if this is an alternate later.
+ */
+ super *= dev_bsize;
+ dev_bsize = sblock.e2fs_bsize / fsbtodb(&sblock, 1);
+ sblk.b_bno = super / dev_bsize;
+
+ if (sblock.e2fs_ncg == 1) {
+ /* no alternate superblock; assume it's okay */
+ havesb = 1;
+ return 1;
+ }
+ getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock,
+ (long)SBSIZE);
+ if (asblk.b_errs)
+ return 0;
+ if (bflag) {
+ havesb = 1;
+ return 1;
+ }
+
+ /*
+ * Set all possible fields that could differ, then do check
+ * of whole super block against an alternate super block.
+ * When an alternate super-block is specified this check is skipped.
+ */
+ asblk.b_un.b_fs->e2fs_rbcount = sblk.b_un.b_fs->e2fs_rbcount;
+ asblk.b_un.b_fs->e2fs_fbcount = sblk.b_un.b_fs->e2fs_fbcount;
+ asblk.b_un.b_fs->e2fs_ficount = sblk.b_un.b_fs->e2fs_ficount;
+ asblk.b_un.b_fs->e2fs_mtime = sblk.b_un.b_fs->e2fs_mtime;
+ asblk.b_un.b_fs->e2fs_wtime = sblk.b_un.b_fs->e2fs_wtime;
+ asblk.b_un.b_fs->e2fs_mnt_count = sblk.b_un.b_fs->e2fs_mnt_count;
+ asblk.b_un.b_fs->e2fs_max_mnt_count =
+ sblk.b_un.b_fs->e2fs_max_mnt_count;
+ asblk.b_un.b_fs->e2fs_state = sblk.b_un.b_fs->e2fs_state;
+ asblk.b_un.b_fs->e2fs_beh = sblk.b_un.b_fs->e2fs_beh;
+ asblk.b_un.b_fs->e2fs_lastfsck = sblk.b_un.b_fs->e2fs_lastfsck;
+ asblk.b_un.b_fs->e2fs_fsckintv = sblk.b_un.b_fs->e2fs_fsckintv;
+ asblk.b_un.b_fs->e2fs_ruid = sblk.b_un.b_fs->e2fs_ruid;
+ asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid;
+ asblk.b_un.b_fs->e2fs_block_group_nr =
+ sblk.b_un.b_fs->e2fs_block_group_nr;
+ asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGEFILE;
+ asblk.b_un.b_fs->e2fs_features_rocompat |=
+ sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) ||
+ (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP))) {
+ if (debug) {
+ printf("compat 0x%08x, incompat 0x%08x, compat_ro "
+ "0x%08x\n",
+ sblock.e2fs.e2fs_features_compat,
+ sblock.e2fs.e2fs_features_incompat,
+ sblock.e2fs.e2fs_features_rocompat);
+ }
+ badsb(listerr, "INCOMPATIBLE FEATURE BITS IN SUPER BLOCK");
+ return 0;
+ }
+ if (memcmp(sblk.b_un.b_fs, asblk.b_un.b_fs, SBSIZE)) {
+ if (debug) {
+ u_int32_t *nlp, *olp, *endlp;
+
+ printf("superblock mismatches\n");
+ nlp = (u_int32_t *)asblk.b_un.b_fs;
+ olp = (u_int32_t *)sblk.b_un.b_fs;
+ endlp = olp + (SBSIZE / sizeof(*olp));
+ for ( ; olp < endlp; olp++, nlp++) {
+ if (*olp == *nlp)
+ continue;
+ printf("offset %ld, original %ld, "
+ "alternate %ld\n",
+ (long)(olp - (u_int32_t *)sblk.b_un.b_fs),
+ (long)fs2h32(*olp),
+ (long)fs2h32(*nlp));
+ }
+ }
+ badsb(listerr,
+ "VALUES IN SUPER BLOCK DISAGREE WITH "
+ "THOSE IN FIRST ALTERNATE");
+ return 0;
+ }
+ havesb = 1;
+ return 1;
+}
+
+void
+copyback_sb(struct bufarea *bp)
+{
+ /* Copy the in-memory superblock back to buffer */
+ bp->b_un.b_fs->e2fs_icount = h2fs32(sblock.e2fs.e2fs_icount);
+ bp->b_un.b_fs->e2fs_bcount = h2fs32(sblock.e2fs.e2fs_bcount);
+ bp->b_un.b_fs->e2fs_rbcount = h2fs32(sblock.e2fs.e2fs_rbcount);
+ bp->b_un.b_fs->e2fs_fbcount = h2fs32(sblock.e2fs.e2fs_fbcount);
+ bp->b_un.b_fs->e2fs_ficount = h2fs32(sblock.e2fs.e2fs_ficount);
+ bp->b_un.b_fs->e2fs_first_dblock =
+ h2fs32(sblock.e2fs.e2fs_first_dblock);
+ bp->b_un.b_fs->e2fs_log_bsize = h2fs32(sblock.e2fs.e2fs_log_bsize);
+ bp->b_un.b_fs->e2fs_fsize = h2fs32(sblock.e2fs.e2fs_fsize);
+ bp->b_un.b_fs->e2fs_bpg = h2fs32(sblock.e2fs.e2fs_bpg);
+ bp->b_un.b_fs->e2fs_fpg = h2fs32(sblock.e2fs.e2fs_fpg);
+ bp->b_un.b_fs->e2fs_ipg = h2fs32(sblock.e2fs.e2fs_ipg);
+ bp->b_un.b_fs->e2fs_mtime = h2fs32(sblock.e2fs.e2fs_mtime);
+ bp->b_un.b_fs->e2fs_wtime = h2fs32(sblock.e2fs.e2fs_wtime);
+ bp->b_un.b_fs->e2fs_lastfsck = h2fs32(sblock.e2fs.e2fs_lastfsck);
+ bp->b_un.b_fs->e2fs_fsckintv = h2fs32(sblock.e2fs.e2fs_fsckintv);
+ bp->b_un.b_fs->e2fs_creator = h2fs32(sblock.e2fs.e2fs_creator);
+ bp->b_un.b_fs->e2fs_rev = h2fs32(sblock.e2fs.e2fs_rev);
+ bp->b_un.b_fs->e2fs_mnt_count = h2fs16(sblock.e2fs.e2fs_mnt_count);
+ bp->b_un.b_fs->e2fs_max_mnt_count =
+ h2fs16(sblock.e2fs.e2fs_max_mnt_count);
+ bp->b_un.b_fs->e2fs_magic = h2fs16(sblock.e2fs.e2fs_magic);
+ bp->b_un.b_fs->e2fs_state = h2fs16(sblock.e2fs.e2fs_state);
+ bp->b_un.b_fs->e2fs_beh = h2fs16(sblock.e2fs.e2fs_beh);
+ bp->b_un.b_fs->e2fs_ruid = h2fs16(sblock.e2fs.e2fs_ruid);
+ bp->b_un.b_fs->e2fs_rgid = h2fs16(sblock.e2fs.e2fs_rgid);
+}
+
+void
+badsb(int listerr, const char *s)
+{
+
+ if (!listerr)
+ return;
+ if (preen)
+ printf("%s: ", cdevname());
+ pfatal("BAD SUPER BLOCK: %s\n", s);
+}
+
+/*
+ * Calculate a prototype superblock based on information in the disk label.
+ * When done the cgsblock macro can be calculated and the fs_ncg field
+ * can be used. Do NOT attempt to use other macros without verifying that
+ * their needed information is available!
+ */
+
+int
+calcsb(const char *dev, int devfd, struct m_ext2fs *fs)
+{
+#ifdef __minix
+ errexit("%s: calcsb: can't read disk label under minix", dev);
+#else
+ struct disklabel *lp;
+ struct partition *pp;
+ char *cp;
+
+ cp = strchr(dev, '\0');
+ if (cp-- == dev ||
+ ((*cp < 'a' || *cp > 'h') && !isdigit((unsigned char)*cp))) {
+ pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
+ return 0;
+ }
+ lp = getdisklabel(dev, devfd);
+ if (isdigit((unsigned char)*cp))
+ pp = &lp->d_partitions[0];
+ else
+ pp = &lp->d_partitions[*cp - 'a'];
+ if (pp->p_fstype != FS_EX2FS) {
+ pfatal("%s: NOT LABELED AS A EXT2 FILE SYSTEM (%s)\n",
+ dev, pp->p_fstype < FSMAXTYPES ?
+ fstypenames[pp->p_fstype] : "unknown");
+ return 0;
+ }
+ memset(fs, 0, sizeof(struct m_ext2fs));
+ fs->e2fs_bsize = pp->p_fsize;
+ fs->e2fs.e2fs_log_bsize = pp->p_fsize / 1024;
+ fs->e2fs.e2fs_bcount = (pp->p_size * DEV_BSIZE) / fs->e2fs_bsize;
+ fs->e2fs.e2fs_first_dblock = (fs->e2fs.e2fs_log_bsize == 0) ? 1 : 0;
+ fs->e2fs.e2fs_bpg = fs->e2fs_bsize * NBBY;
+ fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
+ fs->e2fs_qbmask = fs->e2fs_bsize - 1;
+ fs->e2fs_bmask = ~fs->e2fs_qbmask;
+ fs->e2fs_ncg =
+ howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
+ fs->e2fs.e2fs_bpg);
+ fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
+ fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
+ fs->e2fs_bsize / sizeof(struct ext2_gd));
+
+ return 1;
+#endif
+}
+
+static struct disklabel *
+getdisklabel(const char *s, int fd)
+{
+ static struct disklabel lab;
+
+#ifdef __minix
+ if (s == NULL)
+ return NULL;
+ errexit("%s: can't read disk label under minix", s);
+#else
+ if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
+ if (s == NULL)
+ return NULL;
+ pwarn("ioctl (GCINFO): %s\n", strerror(errno));
+ errexit("%s: can't read disk label", s);
+ }
+#endif
+ return &lab;
+}
+
+daddr_t
+cgoverhead(int c)
+{
+ int overh;
+ overh =
+ 1 /* block bitmap */ +
+ 1 /* inode bitmap */ +
+ sblock.e2fs_itpg;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) {
+ if (cg_has_sb(c) == 0)
+ return overh;
+ }
+ overh += 1 /* superblock */ + sblock.e2fs_ngdb;
+ return overh;
+}
--- /dev/null
+/* $NetBSD: utilities.c,v 1.22 2011/06/09 19:57:51 christos Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: utilities.c,v 1.22 2011/06/09 19:57:51 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+#include "exitvalues.h"
+
+long diskreads, totalreads; /* Disk cache statistics */
+
+static void rwerror(const char *, daddr_t);
+
+int
+ftypeok(struct ext2fs_dinode *dp)
+{
+ switch (fs2h16(dp->e2di_mode) & IFMT) {
+
+ case IFDIR:
+ case IFREG:
+ case IFBLK:
+ case IFCHR:
+ case IFLNK:
+ case IFSOCK:
+ case IFIFO:
+ return (1);
+
+ default:
+ if (debug)
+ printf("bad file type 0%o\n", fs2h16(dp->e2di_mode));
+ return (0);
+ }
+}
+
+int
+reply(const char *question)
+{
+ int persevere;
+ char c;
+
+ if (preen)
+ pfatal("INTERNAL ERROR: GOT TO reply()");
+ persevere = !strcmp(question, "CONTINUE");
+ printf("\n");
+ if (!persevere && (nflag || fswritefd < 0)) {
+ printf("%s? no\n\n", question);
+ return (0);
+ }
+ if (yflag || (persevere && nflag)) {
+ printf("%s? yes\n\n", question);
+ return (1);
+ }
+ do {
+ printf("%s? [yn] ", question);
+ (void) fflush(stdout);
+ c = getc(stdin);
+ while (c != '\n' && getc(stdin) != '\n')
+ if (feof(stdin))
+ return (0);
+ } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
+ printf("\n");
+ if (c == 'y' || c == 'Y')
+ return (1);
+ return (0);
+}
+
+/*
+ * Malloc buffers and set up cache.
+ */
+void
+bufinit(void)
+{
+ struct bufarea *bp;
+ long bufcnt, i;
+ char *bufp;
+
+ diskreads = totalreads = 0;
+ pbp = pdirbp = (struct bufarea *)0;
+ bufhead.b_next = bufhead.b_prev = &bufhead;
+ bufcnt = MAXBUFSPACE / sblock.e2fs_bsize;
+ if (bufcnt < MINBUFS)
+ bufcnt = MINBUFS;
+ for (i = 0; i < bufcnt; i++) {
+ bp = malloc(sizeof(struct bufarea));
+ bufp = malloc((size_t)sblock.e2fs_bsize);
+ if (bp == NULL || bufp == NULL) {
+ free(bp);
+ free(bufp);
+ if (i >= MINBUFS)
+ break;
+ errexit("cannot allocate buffer pool");
+ }
+ bp->b_un.b_buf = bufp;
+ bp->b_prev = &bufhead;
+ bp->b_next = bufhead.b_next;
+ bufhead.b_next->b_prev = bp;
+ bufhead.b_next = bp;
+ initbarea(bp);
+ }
+ bufhead.b_size = i; /* save number of buffers */
+}
+
+/*
+ * Manage a cache of directory blocks.
+ */
+struct bufarea *
+getdatablk(daddr_t blkno, long size)
+{
+ struct bufarea *bp;
+
+ for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
+ if (bp->b_bno == fsbtodb(&sblock, blkno))
+ goto foundit;
+ for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
+ if ((bp->b_flags & B_INUSE) == 0)
+ break;
+ if (bp == &bufhead)
+ errexit("deadlocked buffer pool");
+ getblk(bp, blkno, size);
+ diskreads++;
+ /* fall through */
+foundit:
+ totalreads++;
+ bp->b_prev->b_next = bp->b_next;
+ bp->b_next->b_prev = bp->b_prev;
+ bp->b_prev = &bufhead;
+ bp->b_next = bufhead.b_next;
+ bufhead.b_next->b_prev = bp;
+ bufhead.b_next = bp;
+ bp->b_flags |= B_INUSE;
+ return (bp);
+}
+
+void
+getblk(struct bufarea *bp, daddr_t blk, long size)
+{
+ daddr_t dblk;
+
+ dblk = fsbtodb(&sblock, blk);
+ if (bp->b_bno != dblk) {
+ flush(fswritefd, bp);
+ bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
+ bp->b_bno = dblk;
+ bp->b_size = size;
+ }
+}
+
+void
+flush(int fd, struct bufarea *bp)
+{
+ int i;
+
+ if (!bp->b_dirty)
+ return;
+ if (bp->b_errs != 0)
+ pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
+ (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
+ (long long)bp->b_bno);
+ bp->b_dirty = 0;
+ bp->b_errs = 0;
+ bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
+ if (bp != &sblk)
+ return;
+ for (i = 0; i < sblock.e2fs_ngdb; i++) {
+ bwrite(fswritefd, (char *)
+ &sblock.e2fs_gd[i* sblock.e2fs_bsize / sizeof(struct ext2_gd)],
+ fsbtodb(&sblock, ((sblock.e2fs_bsize>1024)?0:1)+i+1),
+ sblock.e2fs_bsize);
+ }
+}
+
+static void
+rwerror(const char *mesg, daddr_t blk)
+{
+
+ if (preen == 0)
+ printf("\n");
+ pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk);
+ if (reply("CONTINUE") == 0)
+ errexit("Program terminated");
+}
+
+void
+ckfini(int markclean)
+{
+ struct bufarea *bp, *nbp;
+ int cnt = 0;
+
+ if (fswritefd < 0) {
+ (void)close(fsreadfd);
+ return;
+ }
+ flush(fswritefd, &sblk);
+ if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
+ !preen && reply("UPDATE STANDARD SUPERBLOCKS")) {
+ sblk.b_bno = SBOFF / dev_bsize;
+ sbdirty();
+ flush(fswritefd, &sblk);
+ copyback_sb(&asblk);
+ asblk.b_dirty = 1;
+ flush(fswritefd, &asblk);
+ }
+ for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
+ cnt++;
+ flush(fswritefd, bp);
+ nbp = bp->b_prev;
+ free(bp->b_un.b_buf);
+ free(bp);
+ }
+ if (bufhead.b_size != cnt)
+ errexit("Panic: lost %d buffers", bufhead.b_size - cnt);
+ pbp = pdirbp = (struct bufarea *)0;
+ if (markclean && (sblock.e2fs.e2fs_state & E2FS_ISCLEAN) == 0) {
+ /*
+ * Mark the file system as clean, and sync the superblock.
+ */
+ if (preen)
+ pwarn("MARKING FILE SYSTEM CLEAN\n");
+ else if (!reply("MARK FILE SYSTEM CLEAN"))
+ markclean = 0;
+ if (markclean) {
+ sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
+ sbdirty();
+ flush(fswritefd, &sblk);
+ }
+ }
+ if (debug)
+ printf("cache missed %ld of %ld (%d%%)\n", diskreads,
+ totalreads, (int)(diskreads * 100 / totalreads));
+ (void)close(fsreadfd);
+ (void)close(fswritefd);
+}
+
+int
+bread(int fd, char *buf, daddr_t blk, long size)
+{
+ char *cp;
+ int i, errs;
+#ifndef __minix
+ off_t offset;
+#else
+ u64_t offset;
+#endif
+
+ offset = blk;
+ offset *= dev_bsize;
+#ifndef __minix
+ if (lseek(fd, offset, 0) < 0)
+ rwerror("SEEK", blk);
+#else
+ if (lseek64(fd, offset, 0, NULL) < 0)
+ rwerror("SEEK", blk);
+#endif
+ else if (read(fd, buf, (int)size) == size)
+ return (0);
+ rwerror("READ", blk);
+#ifndef __minix
+ if (lseek(fd, offset, 0) < 0)
+ rwerror("SEEK", blk);
+#else
+ if (lseek64(fd, offset, 0, NULL) < 0)
+ rwerror("SEEK", blk);
+#endif
+ errs = 0;
+ memset(buf, 0, (size_t)size);
+ printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
+ for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
+ if (read(fd, cp, (int)secsize) != secsize) {
+ (void)lseek(fd, offset + i + secsize, 0);
+ if (secsize != dev_bsize && dev_bsize != 1)
+ printf(" %lld (%lld),",
+ (long long)((blk*dev_bsize + i) / secsize),
+ (long long)(blk + i / dev_bsize));
+ else
+ printf(" %lld,", (long long)(blk +
+ i / dev_bsize));
+ errs++;
+ }
+ }
+ printf("\n");
+ return (errs);
+}
+
+void
+bwrite(int fd, char *buf, daddr_t blk, long size)
+{
+ int i;
+ char *cp;
+#ifndef __minix
+ off_t offset;
+#else
+ u64_t offset;
+#endif
+
+ if (fd < 0)
+ return;
+ offset = blk;
+ offset *= dev_bsize;
+#ifndef __minix
+ if (lseek(fd, offset, 0) < 0)
+ rwerror("SEEK", blk);
+#else
+ if (lseek64(fd, offset, 0, NULL) < 0)
+ rwerror("SEEK", blk);
+#endif
+ else if (write(fd, buf, (int)size) == size) {
+ fsmodified = 1;
+ return;
+ }
+ rwerror("WRITE", blk);
+#ifndef __minix
+ if (lseek(fd, offset, 0) < 0)
+ rwerror("SEEK", blk);
+#else
+ if (lseek64(fd, offset, 0, NULL) < 0)
+ rwerror("SEEK", blk);
+#endif
+ printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
+ for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
+ if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
+ (void)lseek(fd, offset + i + dev_bsize, 0);
+ printf(" %lld,", (long long)(blk + i / dev_bsize));
+ }
+ printf("\n");
+ return;
+}
+
+/*
+ * allocate a data block
+ */
+int
+allocblk(void)
+{
+ int i;
+
+ for (i = 0; i < maxfsblock - 1; i++) {
+ if (testbmap(i))
+ continue;
+ setbmap(i);
+ n_blks++;
+ return (i);
+ }
+ return (0);
+}
+
+/*
+ * Free a previously allocated block
+ */
+void
+freeblk(daddr_t blkno)
+{
+ struct inodesc idesc;
+
+ idesc.id_blkno = blkno;
+ idesc.id_numfrags = 1;
+ (void)pass4check(&idesc);
+}
+
+/*
+ * Find a pathname
+ */
+void
+getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino)
+{
+ int len;
+ char *cp;
+ struct inodesc idesc;
+ static int busy = 0;
+
+ if (curdir == ino && ino == EXT2_ROOTINO) {
+ (void)strlcpy(namebuf, "/", namebuflen);
+ return;
+ }
+ if (busy ||
+ (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
+ (void)strlcpy(namebuf, "?", namebuflen);
+ return;
+ }
+ busy = 1;
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = DATA;
+ idesc.id_fix = IGNORE;
+ cp = &namebuf[MAXPATHLEN - 1];
+ *cp = '\0';
+ if (curdir != ino) {
+ idesc.id_parent = curdir;
+ goto namelookup;
+ }
+ while (ino != EXT2_ROOTINO) {
+ idesc.id_number = ino;
+ idesc.id_func = findino;
+ idesc.id_name = "..";
+ if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
+ break;
+ namelookup:
+ idesc.id_number = idesc.id_parent;
+ idesc.id_parent = ino;
+ idesc.id_func = findname;
+ idesc.id_name = namebuf;
+ if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
+ break;
+ len = strlen(namebuf);
+ cp -= len;
+ memcpy(cp, namebuf, (size_t)len);
+ *--cp = '/';
+ if (cp < &namebuf[EXT2FS_MAXNAMLEN])
+ break;
+ ino = idesc.id_number;
+ }
+ busy = 0;
+ if (ino != EXT2_ROOTINO)
+ *--cp = '?';
+ memcpy(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
+}
+
+/*
+ * determine whether an inode should be fixed.
+ */
+int
+dofix(struct inodesc *idesc, const char *msg)
+{
+
+ switch (idesc->id_fix) {
+
+ case DONTKNOW:
+ if (idesc->id_type == DATA)
+ direrror(idesc->id_number, msg);
+ else
+ pwarn("%s", msg);
+ if (preen) {
+ printf(" (SALVAGED)\n");
+ idesc->id_fix = FIX;
+ return (ALTERED);
+ }
+ if (reply("SALVAGE") == 0) {
+ idesc->id_fix = NOFIX;
+ return (0);
+ }
+ idesc->id_fix = FIX;
+ return (ALTERED);
+
+ case FIX:
+ return (ALTERED);
+
+ case NOFIX:
+ case IGNORE:
+ return (0);
+
+ default:
+ errexit("UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
+ }
+ /* NOTREACHED */
+}
--- /dev/null
+# $NetBSD: Makefile,v 1.3 2009/06/05 21:52:31 haad Exp $
+# @(#)Makefile 8.2 (Berkeley) 3/27/94
+
+WARNS?= 3 # XXX: sign-compare issues
+
+.include <bsd.own.mk>
+
+PROG= newfs_ext2fs
+SRCS= newfs_ext2fs.c mke2fs.c ext2fs_bswap.c partutil.c
+MAN= newfs_ext2fs.8
+
+FSCK=${NETBSDSRCDIR}/sbin/fsck
+MYFSCK=${NETBSDSRCDIR}/sbin/fsck_ext2fs
+CPPFLAGS+=-I${.CURDIR} -I${FSCK}
+
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+LDADD+=-lprop
+DPADD+=${LIBPROP}
+
+SYMLINKS+= $(BINDIR)/$(PROG) $(BINDIR)/newfs_ext2 \
+ $(BINDIR)/$(PROG) $(BINDIR)/mkfs.ext2
+
+.PATH: ${FSCK} ${MYFSCK} #${NETBSDSRCDIR}/sys/ufs/ext2fs
+
+.include <bsd.prog.mk>
--- /dev/null
+/* $NetBSD: extern.h,v 1.4 2009/10/21 01:07:46 snj 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.
+ */
+
+/* XXX should be in <sys/ufs/ext2fs.h> */
+#define EXT2_LOG_MAXBSIZE 12
+#define EXT2_MAXBSIZE (1 << EXT2_LOG_MAXBSIZE)
+
+/* prototypes */
+void mke2fs(const char *, int, int);
+
+/* variables set up by front end. */
+extern int Nflag; /* run mkfs without writing file system */
+extern int Oflag; /* format as an 4.3BSD file system */
+extern int verbosity; /* amount of printf() output */
+extern int64_t fssize; /* file system size */
+extern uint16_t inodesize; /* bytes per inode */
+extern uint sectorsize; /* sector size */
+extern uint fsize; /* fragment size */
+extern uint bsize; /* block size */
+extern uint minfree; /* free space threshold */
+extern uint num_inodes; /* number of inodes (overrides density) */
+extern char *volname; /* volume name */
--- /dev/null
+/* $NetBSD: mke2fs.c,v 1.14 2010/09/10 15:51:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2007 Izumi Tsutsui. 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1997 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.
+ *
+ * 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.
+ */
+
+/* mmap/munmap are used in this file just to allocate/free memory
+ * so these functions are ok.
+ */
+#define mmap minix_mmap
+#define munmap minix_munmap
+
+/*
+ * mke2fs.c: "re-invent (dumb but non-GPLed) wheel as a fun project"
+ *
+ * In spite of this name, there is no piece of code
+ * derived from GPLed e2fsprogs written for Linux.
+ * I referred them only to see how each structure
+ * member should be initialized.
+ *
+ * Reference:
+ * - All NetBSD sources under src/sys/ufs/ext2fs and src/sbin/fsck_ext2fs
+ * - Ext2fs Home Page
+ * http://e2fsprogs.sourceforge.net/ext2.html
+ * - Design and Implementation of the Second Extended Filesystem
+ * http://e2fsprogs.sourceforge.net/ext2intro.html
+ * - Linux Documentation "The Second Extended Filesystem"
+ * http://www.kernel.org/doc/Documentation/filesystems/ext2.txt
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95";
+#else
+__RCSID("$NetBSD: mke2fs.c,v 1.14 2010/09/10 15:51:20 tsutsui Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <sys/ioctl.h>
+
+#define _MINIX
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <uuid.h>
+#include <assert.h>
+#include <minix/termios.h>
+
+#include "extern.h"
+
+static void initcg(uint);
+static void zap_old_sblock(daddr_t);
+static uint cgoverhead(uint);
+static int fsinit(const struct timeval *);
+static int makedir(struct ext2fs_direct *, int);
+static void copy_dir(struct ext2fs_direct *, struct ext2fs_direct *);
+static void init_resizeino(const struct timeval *);
+static uint32_t alloc(uint32_t, uint16_t);
+static void iput(struct ext2fs_dinode *, ino_t);
+static void rdfs(daddr_t, int, void *);
+static void wtfs(daddr_t, int, void *);
+static int ilog2(uint);
+static int skpc(int, size_t, uint8_t *);
+
+/* XXX: some of these macro should be into <ufs/ext2fs/ext2fs.h>? */
+#define EXT2_DEF_MAX_MNT_COUNT 20
+#define EXT2_DEF_FSCKINTV (180 * 24 * 60 * 60) /* 180 days */
+#define EXT2_RESERVED_INODES (EXT2_FIRSTINO - 1)
+#define EXT2_UMASK 0755
+
+#define EXT2_INO_INDEX(ino) ((ino) - 1) /* no inode zero */
+
+#define EXT2_LOSTFOUNDSIZE 16384
+#define EXT2_LOSTFOUNDINO EXT2_FIRSTINO /* XXX: not quite */
+#define EXT2_LOSTFOUNDUMASK 0700
+
+#define EXT2_RESIZEINOUMASK 0600
+
+#define NBLOCK_SUPERBLOCK 1
+#define NBLOCK_BLOCK_BITMAP 1
+#define NBLOCK_INODE_BITMAP 1
+
+#define cgbase(fs, c) \
+ ((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * (c))
+
+
+/*
+ * ext2fs super block and group descriptor structures
+ *
+ * We don't have to use or setup whole in-memory m_ext2fs structure,
+ * but prepare it to use several macro defined in kernel headers.
+ */
+union {
+ struct m_ext2fs m_ext2fs;
+ char pad[SBSIZE];
+} ext2fsun;
+#define sblock ext2fsun.m_ext2fs
+#define gd ext2fsun.m_ext2fs.e2fs_gd
+
+static uint8_t *iobuf; /* for superblock and group descriptors */
+static int iobufsize;
+
+static uint8_t buf[MAXBSIZE]; /* for initcg() and makedir() ops */
+
+static int fsi = -1, fso = -1;
+
+void
+mke2fs(const char *fsys, int fi, int fo)
+{
+ struct timeval tv;
+ int64_t minfssize;
+ uint bcount, fbcount, ficount;
+ uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg;
+ uint minblocks_per_cg, blocks_lastcg;
+ uint ncg, cylno, sboff;
+ uuid_t uuid;
+ uint32_t uustat;
+ int i, len, col, delta, fld_width, max_cols;
+ struct winsize winsize;
+
+ gettimeofday(&tv, NULL);
+ fsi = fi;
+ fso = fo;
+
+ /*
+ * collect and verify the block and fragment sizes
+ */
+ if (!powerof2(bsize)) {
+ errx(EXIT_FAILURE,
+ "block size must be a power of 2, not %u\n",
+ bsize);
+ }
+ if (!powerof2(fsize)) {
+ errx(EXIT_FAILURE,
+ "fragment size must be a power of 2, not %u\n",
+ fsize);
+ }
+ if (fsize < sectorsize) {
+ errx(EXIT_FAILURE,
+ "fragment size %u is too small, minimum is %u\n",
+ fsize, sectorsize);
+ }
+ if (bsize < MINBSIZE) {
+ errx(EXIT_FAILURE,
+ "block size %u is too small, minimum is %u\n",
+ bsize, MINBSIZE);
+ }
+ if (bsize > EXT2_MAXBSIZE) {
+ errx(EXIT_FAILURE,
+ "block size %u is too large, maximum is %u\n",
+ bsize, MAXBSIZE);
+ }
+ if (bsize != fsize) {
+ /*
+ * There is no fragment support on current ext2fs (yet?),
+ * but some kernel code refers fsize or fpg as bsize or bpg
+ * and Linux seems to set the same values to them.
+ */
+ errx(EXIT_FAILURE,
+ "block size (%u) can't be different from "
+ "fragment size (%u)\n",
+ bsize, fsize);
+ }
+
+ /* variable inodesize is REV1 feature */
+ if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE) {
+ errx(EXIT_FAILURE, "GOOD_OLD_REV file system format"
+ " doesn't support %d byte inode\n", inodesize);
+ }
+
+ sblock.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE;
+ /* Umm, why not e2fs_log_fsize? */
+ sblock.e2fs.e2fs_fsize = ilog2(fsize) - LOG_MINBSIZE;
+
+ sblock.e2fs_bsize = bsize;
+ sblock.e2fs_bshift = sblock.e2fs.e2fs_log_bsize + LOG_MINBSIZE;
+ sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
+ sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
+ sblock.e2fs_fsbtodb = ilog2(sblock.e2fs_bsize) - ilog2(sectorsize);
+ sblock.e2fs_ipb = sblock.e2fs_bsize / inodesize;
+
+ /*
+ * Ext2fs preserves BBSIZE (1024 bytes) space at the top for
+ * bootloader (though it is not enough at all for our bootloader).
+ * If bsize == BBSIZE we have to preserve one block.
+ * If bsize > BBSIZE, the first block already contains BBSIZE space
+ * before superblock because superblock is allocated at SBOFF and
+ * bsize is a power of two (i.e. 2048 bytes or more).
+ */
+ sblock.e2fs.e2fs_first_dblock = (sblock.e2fs_bsize > BBSIZE) ? 0 : 1;
+ minfssize = fsbtodb(&sblock,
+ sblock.e2fs.e2fs_first_dblock +
+ NBLOCK_SUPERBLOCK +
+ 1 /* at least one group descriptor */ +
+ NBLOCK_BLOCK_BITMAP +
+ NBLOCK_INODE_BITMAP +
+ 1 /* at least one inode table block */ +
+ 1 /* at least one data block for rootdir */ +
+ 1 /* at least one data block for data */
+ ); /* XXX and more? */
+
+ if (fssize < minfssize)
+ errx(EXIT_FAILURE, "Filesystem size %" PRId64
+ " < minimum size of %" PRId64 "\n", fssize, minfssize);
+
+ bcount = dbtofsb(&sblock, fssize);
+
+ /*
+ * While many people claim that ext2fs is a (bad) clone of ufs/ffs,
+ * it isn't actual ffs so maybe we should call it "block group"
+ * as their native name rather than ffs derived "cylinder group."
+ * But we'll use the latter here since other kernel sources use it.
+ * (I also agree "cylinder" based allocation is obsolete though)
+ */
+
+ /* maybe "simple is the best" */
+ blocks_per_cg = sblock.e2fs_bsize * NBBY;
+
+ ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg);
+ blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);
+
+ /* check range of inode number */
+ if (num_inodes < EXT2_FIRSTINO)
+ num_inodes = EXT2_FIRSTINO; /* needs reserved inodes + 1 */
+ if (num_inodes > UINT16_MAX * ncg)
+ num_inodes = UINT16_MAX * ncg; /* ext2bgd_nifree is uint16_t */
+
+ inodes_per_cg = num_inodes / ncg;
+ iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize);
+
+ /* Check that the last cylinder group has enough space for inodes */
+ minblocks_per_cg =
+ NBLOCK_BLOCK_BITMAP +
+ NBLOCK_INODE_BITMAP +
+ iblocks_per_cg +
+ 1; /* at least one data block */
+ if (Oflag == 0 || cg_has_sb(ncg - 1) != 0)
+ minblocks_per_cg += NBLOCK_SUPERBLOCK + blocks_gd;
+
+ blocks_lastcg = bcount - sblock.e2fs.e2fs_first_dblock -
+ blocks_per_cg * (ncg - 1);
+ if (blocks_lastcg < minblocks_per_cg) {
+ /*
+ * Since we make all the cylinder groups the same size, the
+ * last will only be small if there are more than one
+ * cylinder groups. If the last one is too small to store
+ * filesystem data, just kill it.
+ *
+ * XXX: Does fsck_ext2fs(8) properly handle this case?
+ */
+ bcount -= blocks_lastcg;
+ ncg--;
+ blocks_lastcg = blocks_per_cg;
+ blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);
+ inodes_per_cg = num_inodes / ncg;
+ }
+ /* roundup inodes_per_cg to make it use whole inode table blocks */
+ inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb);
+ num_inodes = inodes_per_cg * ncg;
+ iblocks_per_cg = inodes_per_cg / sblock.e2fs_ipb;
+
+ /* XXX: probably we should check these adjusted values again */
+
+ sblock.e2fs.e2fs_bcount = bcount;
+ sblock.e2fs.e2fs_icount = num_inodes;
+
+ sblock.e2fs_ncg = ncg;
+ sblock.e2fs_ngdb = blocks_gd;
+ sblock.e2fs_itpg = iblocks_per_cg;
+
+ sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * minfree / 100;
+ /* e2fs_fbcount will be accounted later */
+ /* e2fs_ficount will be accounted later */
+
+ sblock.e2fs.e2fs_bpg = blocks_per_cg;
+ sblock.e2fs.e2fs_fpg = blocks_per_cg;
+
+ sblock.e2fs.e2fs_ipg = inodes_per_cg;
+
+ sblock.e2fs.e2fs_mtime = 0;
+ sblock.e2fs.e2fs_wtime = tv.tv_sec;
+ sblock.e2fs.e2fs_mnt_count = 0;
+ /* XXX: should add some entropy to avoid checking all fs at once? */
+ sblock.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT;
+
+ sblock.e2fs.e2fs_magic = E2FS_MAGIC;
+ sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
+ sblock.e2fs.e2fs_beh = E2FS_BEH_DEFAULT;
+ sblock.e2fs.e2fs_minrev = 0;
+ sblock.e2fs.e2fs_lastfsck = tv.tv_sec;
+ sblock.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV;
+
+ /*
+ * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper,
+ * but the purpose of this newfs_ext2fs(8) command is to provide
+ * a filesystem which can be recognized by firmware on some
+ * Linux based appliances that can load bootstrap files only from
+ * (their native) ext2fs, and anyway we will (and should) try to
+ * act like them as much as possible.
+ *
+ * Anyway, I hope that all newer such boxes will keep their support
+ * for the "GOOD_OLD_REV" ext2fs.
+ */
+ sblock.e2fs.e2fs_creator = E2FS_OS_LINUX;
+
+ if (Oflag == 0) {
+ sblock.e2fs.e2fs_rev = E2FS_REV0;
+ sblock.e2fs.e2fs_features_compat = 0;
+ sblock.e2fs.e2fs_features_incompat = 0;
+ sblock.e2fs.e2fs_features_rocompat = 0;
+ } else {
+ sblock.e2fs.e2fs_rev = E2FS_REV1;
+ /*
+ * e2fsprogs say "REV1" is "dynamic" so
+ * it isn't quite a version and maybe it means
+ * "extended from REV0 so check compat features."
+ *
+ * XXX: We don't have any native tool to activate
+ * the EXT2F_COMPAT_RESIZE feature and
+ * fsck_ext2fs(8) might not fix structures for it.
+ */
+ sblock.e2fs.e2fs_features_compat = EXT2F_COMPAT_RESIZE;
+ sblock.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE;
+ sblock.e2fs.e2fs_features_rocompat =
+ EXT2F_ROCOMPAT_SPARSESUPER | EXT2F_ROCOMPAT_LARGEFILE;
+ }
+
+ sblock.e2fs.e2fs_ruid = geteuid();
+ sblock.e2fs.e2fs_rgid = getegid();
+
+ sblock.e2fs.e2fs_first_ino = EXT2_FIRSTINO;
+ sblock.e2fs.e2fs_inode_size = inodesize;
+
+ /* e2fs_block_group_nr is set on writing superblock to each group */
+
+ uuid_create(&uuid, &uustat);
+ if (uustat != uuid_s_ok)
+ errx(EXIT_FAILURE, "Failed to generate uuid\n");
+ uuid_enc_le(sblock.e2fs.e2fs_uuid, &uuid);
+ if (volname != NULL) {
+ if (strlen(volname) > sizeof(sblock.e2fs.e2fs_vname))
+ errx(EXIT_FAILURE, "Volume name is too long");
+ strlcpy(sblock.e2fs.e2fs_vname, volname,
+ sizeof(sblock.e2fs.e2fs_vname));
+ }
+
+ sblock.e2fs.e2fs_fsmnt[0] = '\0';
+ sblock.e2fs_fsmnt[0] = '\0';
+
+ sblock.e2fs.e2fs_algo = 0; /* XXX unsupported? */
+ sblock.e2fs.e2fs_prealloc = 0; /* XXX unsupported? */
+ sblock.e2fs.e2fs_dir_prealloc = 0; /* XXX unsupported? */
+
+ /* calculate blocks for reserved group descriptors for resize */
+ sblock.e2fs.e2fs_reserved_ngdb = 0;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0) {
+ uint64_t target_blocks;
+ uint target_ncg, target_ngdb, reserved_ngdb;
+
+ /* reserve descriptors for size as 1024 times as current */
+ target_blocks =
+ (sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock)
+ * 1024ULL;
+ /* number of blocks must be in uint32_t */
+ if (target_blocks > UINT32_MAX)
+ target_blocks = UINT32_MAX;
+ target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg);
+ target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg,
+ sblock.e2fs_bsize);
+ /*
+ * Reserved group descriptor blocks are preserved as
+ * the second level double indirect reference blocks in
+ * the EXT2_RESIZEINO inode, so the maximum number of
+ * the blocks is NINDIR(fs).
+ * (see also descriptions in init_resizeino() function)
+ *
+ * We check a number including current e2fs_ngdb here
+ * because they will be moved into reserved gdb on
+ * possible future size shrink, though e2fsprogs don't
+ * seem to care about it.
+ */
+ if (target_ngdb > NINDIR(&sblock))
+ target_ngdb = NINDIR(&sblock);
+
+ reserved_ngdb = target_ngdb - sblock.e2fs_ngdb;
+
+ /* make sure reserved_ngdb fits in the last cg */
+ if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1))
+ reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1);
+ if (reserved_ngdb == 0) {
+ /* if no space for reserved gdb, disable the feature */
+ sblock.e2fs.e2fs_features_compat &=
+ ~EXT2F_COMPAT_RESIZE;
+ }
+ sblock.e2fs.e2fs_reserved_ngdb = reserved_ngdb;
+ }
+
+ /*
+ * Initialize group descriptors
+ */
+ gd = malloc(sblock.e2fs_ngdb * bsize);
+ if (gd == NULL)
+ errx(EXIT_FAILURE, "Can't allocate descriptors buffer");
+ memset(gd, 0, sblock.e2fs_ngdb * bsize);
+
+ fbcount = 0;
+ ficount = 0;
+ for (cylno = 0; cylno < ncg; cylno++) {
+ uint boffset;
+
+ boffset = cgbase(&sblock, cylno);
+ if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+ cg_has_sb(cylno)) {
+ boffset += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb;
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_compat &
+ EXT2F_COMPAT_RESIZE) != 0)
+ boffset += sblock.e2fs.e2fs_reserved_ngdb;
+ }
+ gd[cylno].ext2bgd_b_bitmap = boffset;
+ boffset += NBLOCK_BLOCK_BITMAP;
+ gd[cylno].ext2bgd_i_bitmap = boffset;
+ boffset += NBLOCK_INODE_BITMAP;
+ gd[cylno].ext2bgd_i_tables = boffset;
+ if (cylno == (ncg - 1))
+ gd[cylno].ext2bgd_nbfree =
+ blocks_lastcg - cgoverhead(cylno);
+ else
+ gd[cylno].ext2bgd_nbfree =
+ sblock.e2fs.e2fs_bpg - cgoverhead(cylno);
+ fbcount += gd[cylno].ext2bgd_nbfree;
+ gd[cylno].ext2bgd_nifree = sblock.e2fs.e2fs_ipg;
+ if (cylno == 0) {
+ /* take reserved inodes off nifree */
+ gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES;
+ }
+ ficount += gd[cylno].ext2bgd_nifree;
+ gd[cylno].ext2bgd_ndirs = 0;
+ }
+ sblock.e2fs.e2fs_fbcount = fbcount;
+ sblock.e2fs.e2fs_ficount = ficount;
+
+ /*
+ * Dump out summary information about file system.
+ */
+ if (verbosity > 0) {
+ printf("%s: %u.%1uMB (%" PRId64 " sectors) "
+ "block size %u, fragment size %u\n",
+ fsys,
+ (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)),
+ (uint)((uint64_t)bcount * bsize -
+ rounddown((uint64_t)bcount * bsize, 1024 * 1024))
+ / 1024 / 100,
+ fssize, bsize, fsize);
+ printf("\tusing %u block groups of %u.0MB, %u blks, "
+ "%u inodes.\n",
+ ncg, bsize * sblock.e2fs.e2fs_bpg / (1024 * 1024),
+ sblock.e2fs.e2fs_bpg, sblock.e2fs.e2fs_ipg);
+ }
+
+ /*
+ * allocate space for superblock and group descriptors
+ */
+ iobufsize = (NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb) * sblock.e2fs_bsize;
+ iobuf = mmap(0, iobufsize, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (iobuf == NULL)
+ errx(EXIT_FAILURE, "Cannot allocate I/O buffer\n");
+ memset(iobuf, 0, iobufsize);
+
+ /*
+ * We now start writing to the filesystem
+ */
+
+ if (!Nflag) {
+ static const uint pbsize[] = { 1024, 2048, 4096, 0 };
+ uint pblock, epblock;
+ /*
+ * 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)
+ errx(EXIT_FAILURE, "Preposterous size %" PRId64 "\n",
+ fssize);
+ wtfs(fssize - 1, sectorsize, iobuf);
+
+ /*
+ * Ensure there is nothing that looks like a filesystem
+ * superblock anywhere other than where ours will be.
+ * If fsck_ext2fs finds the wrong one all hell breaks loose!
+ *
+ * XXX: needs to check how fsck_ext2fs programs even
+ * on other OSes determine alternate superblocks
+ */
+ for (i = 0; pbsize[i] != 0; i++) {
+ epblock = (uint64_t)bcount * bsize / pbsize[i];
+ for (pblock = ((pbsize[i] == SBSIZE) ? 1 : 0);
+ pblock < epblock;
+ pblock += pbsize[i] * NBBY /* bpg */)
+ zap_old_sblock((daddr_t)pblock *
+ pbsize[i] / sectorsize);
+ }
+ }
+
+ if (verbosity >= 3)
+ printf("super-block backups (for fsck_ext2fs -b #) at:\n");
+ /* If we are printing more than one line of numbers, line up columns */
+ fld_width = verbosity < 4 ? 1 : snprintf(NULL, 0, "%" PRIu64,
+ (uint64_t)cgbase(&sblock, ncg - 1));
+ /* Get terminal width */
+ if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0)
+ max_cols = winsize.ws_col;
+ else
+ max_cols = 80;
+ if (Nflag && verbosity == 3)
+ /* Leave space to add " ..." after one row of numbers */
+ max_cols -= 4;
+#define BASE 0x10000 /* For some fixed-point maths */
+ col = 0;
+ delta = verbosity > 2 ? 0 : max_cols * BASE / ncg;
+ for (cylno = 0; cylno < ncg; cylno++) {
+ fflush(stdout);
+ initcg(cylno);
+ if (verbosity < 2)
+ continue;
+ /* the first one is a master, not backup */
+ if (cylno == 0)
+ continue;
+ /* skip if this cylinder doesn't have a backup */
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) != 0 &&
+ cg_has_sb(cylno) == 0)
+ continue;
+
+ if (delta > 0) {
+ if (Nflag)
+ /* No point doing dots for -N */
+ break;
+ /* Print dots scaled to end near RH margin */
+ for (col += delta; col > BASE; col -= BASE)
+ printf(".");
+ continue;
+ }
+ /* Print superblock numbers */
+ len = printf(" %*" PRIu64 "," + !col, fld_width,
+ (uint64_t)cgbase(&sblock, cylno));
+ col += len;
+ if (col + len < max_cols)
+ /* Next number fits */
+ continue;
+ /* Next number won't fit, need a newline */
+ if (verbosity <= 3) {
+ /* Print dots for subsequent cylinder groups */
+ delta = sblock.e2fs_ncg - cylno - 1;
+ if (delta != 0) {
+ if (Nflag) {
+ printf(" ...");
+ break;
+ }
+ delta = max_cols * BASE / delta;
+ }
+ }
+ col = 0;
+ printf("\n");
+ }
+#undef BASE
+ if (col > 0)
+ printf("\n");
+ if (Nflag)
+ return;
+
+ /*
+ * Now construct the initial file system,
+ */
+ if (fsinit(&tv) == 0)
+ errx(EXIT_FAILURE, "Error making filesystem");
+ /*
+ * Write out the superblock and group descriptors
+ */
+ sblock.e2fs.e2fs_block_group_nr = 0;
+ sboff = 0;
+ if (cgbase(&sblock, 0) == 0) {
+ /*
+ * If the first block contains the boot block sectors,
+ * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE)
+ * we have to preserve data in it.
+ */
+ sboff = SBOFF;
+ }
+ e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff));
+ e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize),
+ sizeof(struct ext2_gd) * sblock.e2fs_ncg);
+ wtfs(fsbtodb(&sblock, cgbase(&sblock, 0)) + sboff / sectorsize,
+ iobufsize - sboff, iobuf + sboff);
+
+ munmap(iobuf, iobufsize);
+}
+
+/*
+ * Initialize a cylinder (block) group.
+ */
+void
+initcg(uint cylno)
+{
+ uint nblcg, i, j, sboff;
+ struct ext2fs_dinode *dp;
+
+ /*
+ * Make a copy of the superblock and group descriptors.
+ */
+ if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+ cg_has_sb(cylno)) {
+ sblock.e2fs.e2fs_block_group_nr = cylno;
+ sboff = 0;
+ if (cgbase(&sblock, cylno) == 0) {
+ /* preserve data in bootblock in cg0 */
+ sboff = SBOFF;
+ }
+ e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff));
+ e2fs_cgsave(gd, (struct ext2_gd *)(iobuf +
+ sblock.e2fs_bsize * NBLOCK_SUPERBLOCK),
+ sizeof(struct ext2_gd) * sblock.e2fs_ncg);
+ /* write superblock and group descriptor backups */
+ wtfs(fsbtodb(&sblock, cgbase(&sblock, cylno)) +
+ sboff / sectorsize, iobufsize - sboff, iobuf + sboff);
+ }
+
+ /*
+ * Initialize block bitmap.
+ */
+ memset(buf, 0, sblock.e2fs_bsize);
+ if (cylno == (sblock.e2fs_ncg - 1)) {
+ /* The last group could have less blocks than e2fs_bpg. */
+ nblcg = sblock.e2fs.e2fs_bcount -
+ cgbase(&sblock, sblock.e2fs_ncg - 1);
+ for (i = nblcg; i < roundup(nblcg, NBBY); i++)
+ setbit(buf, i);
+ memset(&buf[i / NBBY], ~0U, sblock.e2fs.e2fs_bpg - i);
+ }
+ /* set overhead (superblock, group descriptor etc.) blocks used */
+ for (i = 0; i < cgoverhead(cylno) / NBBY; i++)
+ buf[i] = ~0;
+ i = i * NBBY;
+ for (; i < cgoverhead(cylno); i++)
+ setbit(buf, i);
+ wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_b_bitmap), sblock.e2fs_bsize,
+ buf);
+
+ /*
+ * Initialize inode bitmap.
+ *
+ * Assume e2fs_ipg is a multiple of NBBY since
+ * it's a multiple of e2fs_ipb (as we did above).
+ * Note even (possibly smaller) the last group has the same e2fs_ipg.
+ */
+ assert(!(sblock.e2fs.e2fs_ipg % NBBY));
+ i = sblock.e2fs.e2fs_ipg / NBBY;
+ memset(buf, 0, i);
+ assert(sblock.e2fs_bsize >= i);
+ memset(buf + i, ~0U, sblock.e2fs_bsize - i);
+ if (cylno == 0) {
+ /* mark reserved inodes */
+ for (i = 1; i < EXT2_FIRSTINO; i++)
+ setbit(buf, EXT2_INO_INDEX(i));
+ }
+ wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_bitmap), sblock.e2fs_bsize,
+ buf);
+
+ /*
+ * Initialize inode tables.
+ *
+ * Just initialize generation numbers for NFS security.
+ * XXX: sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_valloc() seems
+ * to override these generated numbers.
+ */
+ memset(buf, 0, sblock.e2fs_bsize);
+ for (i = 0; i < sblock.e2fs_itpg; i++) {
+ for (j = 0; j < sblock.e2fs_ipb; j++) {
+ dp = (struct ext2fs_dinode *)(buf + inodesize * j);
+ /* h2fs32() just for consistency */
+ dp->e2di_gen = h2fs32(arc4random());
+ }
+ wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_tables + i),
+ sblock.e2fs_bsize, buf);
+ }
+}
+
+/*
+ * Zap possible lingering old superblock data
+ */
+static void
+zap_old_sblock(daddr_t sec)
+{
+ static daddr_t cg0_data;
+ uint32_t oldfs[SBSIZE / sizeof(uint32_t)];
+ static const struct fsm {
+ uint32_t offset;
+ uint32_t magic;
+ uint32_t mask;
+ } fs_magics[] = {
+ {offsetof(struct ext2fs, e2fs_magic) / 4, E2FS_MAGIC, 0xffff},
+ {offsetof(struct ext2fs, e2fs_magic) / 4,
+ E2FS_MAGIC << 16, 0xffff0000},
+ {14, 0xef530000, 0xffff0000}, /* EXT2FS (big) */
+ {0x55c / 4, 0x00011954, ~0U}, /* FS_UFS1_MAGIC */
+ {0x55c / 4, 0x19540119, ~0U}, /* FS_UFS2_MAGIC */
+ {0, 0x70162, ~0U}, /* LFS_MAGIC */
+ {.offset = ~0U},
+ };
+ const struct fsm *fsm;
+
+ if (Nflag)
+ return;
+
+ /* don't override data before superblock */
+ if (sec < SBOFF / sectorsize)
+ return;
+
+ if (cg0_data == 0) {
+ cg0_data =
+ ((daddr_t)sblock.e2fs.e2fs_first_dblock + cgoverhead(0)) *
+ sblock.e2fs_bsize / sectorsize;
+ }
+
+ /* Ignore anything that is beyond our filesystem */
+ if (sec >= fssize)
+ return;
+ /* Zero anything inside our filesystem... */
+ if (sec >= sblock.e2fs.e2fs_first_dblock * bsize / sectorsize) {
+ /* ...unless we will write that area anyway */
+ if (sec >= cg0_data)
+ /* assume iobuf is zero'ed here */
+ wtfs(sec, roundup(SBSIZE, sectorsize), iobuf);
+ return;
+ }
+
+ /*
+ * The sector might contain boot code, so we must validate it
+ *
+ * XXX: ext2fs won't preserve data after SBOFF,
+ * but first_dblock could have a different value.
+ */
+ rdfs(sec, sizeof(oldfs), &oldfs);
+ for (fsm = fs_magics;; fsm++) {
+ uint32_t v;
+ if (fsm->mask == 0)
+ return;
+ v = oldfs[fsm->offset];
+ if ((v & fsm->mask) == fsm->magic ||
+ (bswap32(v) & fsm->mask) == fsm->magic)
+ break;
+ }
+
+ /* Just zap the magic number */
+ oldfs[fsm->offset] = 0;
+ wtfs(sec, sizeof(oldfs), &oldfs);
+}
+
+/*
+ * uint cgoverhead(uint c)
+ *
+ * Return a number of reserved blocks on the specified group.
+ * XXX: should be shared with src/sbin/fsck_ext2fs/setup.c
+ */
+uint
+cgoverhead(uint c)
+{
+ uint overh;
+
+ overh = NBLOCK_BLOCK_BITMAP + NBLOCK_INODE_BITMAP + sblock.e2fs_itpg;
+
+ if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+ cg_has_sb(c) != 0) {
+ overh += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb;
+
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_compat &
+ EXT2F_COMPAT_RESIZE) != 0)
+ overh += sblock.e2fs.e2fs_reserved_ngdb;
+ }
+
+ return overh;
+}
+
+/*
+ * Initialize the file system
+ */
+
+#define LOSTDIR /* e2fsck complains if there is no lost+found */
+
+#define PREDEFDIR 2
+
+#ifdef LOSTDIR
+#define PREDEFROOTDIR (PREDEFDIR + 1)
+#else
+#define PREDEFROOTDIR PREDEFDIR
+#endif
+
+struct ext2fs_direct root_dir[] = {
+ { EXT2_ROOTINO, 0, 1, 0, "." },
+ { EXT2_ROOTINO, 0, 2, 0, ".." },
+#ifdef LOSTDIR
+ { EXT2_LOSTFOUNDINO, 0, 10, 0, "lost+found" },
+#endif
+};
+
+#ifdef LOSTDIR
+struct ext2fs_direct lost_found_dir[] = {
+ { EXT2_LOSTFOUNDINO, 0, 1, 0, "." },
+ { EXT2_ROOTINO, 0, 2, 0, ".." },
+};
+struct ext2fs_direct pad_dir = { 0, sizeof(struct ext2fs_direct), 0, 0, "" };
+#endif
+
+int
+fsinit(const struct timeval *tv)
+{
+ struct ext2fs_dinode node;
+#ifdef LOSTDIR
+ uint i, nblks_lostfound, blk;
+#endif
+
+ /*
+ * Initialize the inode for the resizefs feature
+ */
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0)
+ init_resizeino(tv);
+
+ /*
+ * Initialize the node
+ */
+
+#ifdef LOSTDIR
+ /*
+ * Create the lost+found directory
+ */
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) {
+ lost_found_dir[0].e2d_type = EXT2_FT_DIR;
+ lost_found_dir[1].e2d_type = EXT2_FT_DIR;
+ }
+ (void)makedir(lost_found_dir, __arraycount(lost_found_dir));
+
+ /* prepare a bit large directory for preserved files */
+ nblks_lostfound = EXT2_LOSTFOUNDSIZE / sblock.e2fs_bsize;
+ /* ...but only with direct blocks */
+ if (nblks_lostfound > NDADDR)
+ nblks_lostfound = NDADDR;
+
+ memset(&node, 0, sizeof(node));
+ node.e2di_mode = EXT2_IFDIR | EXT2_LOSTFOUNDUMASK;
+ node.e2di_uid = geteuid();
+ node.e2di_size = sblock.e2fs_bsize * nblks_lostfound;
+ node.e2di_atime = tv->tv_sec;
+ node.e2di_ctime = tv->tv_sec;
+ node.e2di_mtime = tv->tv_sec;
+ node.e2di_gid = getegid();
+ node.e2di_nlink = PREDEFDIR;
+ /* e2di_nblock is a number of disk blocks, not ext2fs blocks */
+ node.e2di_nblock = fsbtodb(&sblock, nblks_lostfound);
+ node.e2di_blocks[0] = alloc(sblock.e2fs_bsize, node.e2di_mode);
+ if (node.e2di_blocks[0] == 0) {
+ printf("%s: can't allocate block for lost+found\n", __func__);
+ return 0;
+ }
+ for (i = 1; i < nblks_lostfound; i++) {
+ blk = alloc(sblock.e2fs_bsize, 0);
+ if (blk == 0) {
+ printf("%s: can't allocate blocks for lost+found\n",
+ __func__);
+ return 0;
+ }
+ node.e2di_blocks[i] = blk;
+ }
+ wtfs(fsbtodb(&sblock, node.e2di_blocks[0]), sblock.e2fs_bsize, buf);
+ pad_dir.e2d_reclen = sblock.e2fs_bsize;
+ for (i = 1; i < nblks_lostfound; i++) {
+ memset(buf, 0, sblock.e2fs_bsize);
+ copy_dir(&pad_dir, (struct ext2fs_direct *)buf);
+ wtfs(fsbtodb(&sblock, node.e2di_blocks[i]), sblock.e2fs_bsize,
+ buf);
+ }
+ iput(&node, EXT2_LOSTFOUNDINO);
+#endif
+ /*
+ * create the root directory
+ */
+ memset(&node, 0, sizeof(node));
+ if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+ sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) {
+ root_dir[0].e2d_type = EXT2_FT_DIR;
+ root_dir[1].e2d_type = EXT2_FT_DIR;
+#ifdef LOSTDIR
+ root_dir[2].e2d_type = EXT2_FT_DIR;
+#endif
+ }
+ node.e2di_mode = EXT2_IFDIR | EXT2_UMASK;
+ node.e2di_uid = geteuid();
+ node.e2di_size = makedir(root_dir, __arraycount(root_dir));
+ node.e2di_atime = tv->tv_sec;
+ node.e2di_ctime = tv->tv_sec;
+ node.e2di_mtime = tv->tv_sec;
+ node.e2di_gid = getegid();
+ node.e2di_nlink = PREDEFROOTDIR;
+ /* e2di_nblock is a number of disk block, not ext2fs block */
+ node.e2di_nblock = fsbtodb(&sblock, 1);
+ node.e2di_blocks[0] = alloc(node.e2di_size, node.e2di_mode);
+ if (node.e2di_blocks[0] == 0) {
+ printf("%s: can't allocate block for root dir\n", __func__);
+ return 0;
+ }
+ wtfs(fsbtodb(&sblock, node.e2di_blocks[0]), sblock.e2fs_bsize, buf);
+ iput(&node, EXT2_ROOTINO);
+ return 1;
+}
+
+/*
+ * Construct a set of directory entries in "buf".
+ * return size of directory.
+ */
+int
+makedir(struct ext2fs_direct *protodir, int entries)
+{
+ uint8_t *cp;
+ uint i, spcleft;
+ uint dirblksiz;
+
+ dirblksiz = sblock.e2fs_bsize;
+ memset(buf, 0, dirblksiz);
+ spcleft = dirblksiz;
+ for (cp = buf, i = 0; i < entries - 1; i++) {
+ protodir[i].e2d_reclen = EXT2FS_DIRSIZ(protodir[i].e2d_namlen);
+ copy_dir(&protodir[i], (struct ext2fs_direct *)cp);
+ cp += protodir[i].e2d_reclen;
+ spcleft -= protodir[i].e2d_reclen;
+ }
+ protodir[i].e2d_reclen = spcleft;
+ copy_dir(&protodir[i], (struct ext2fs_direct *)cp);
+ return dirblksiz;
+}
+
+/*
+ * Copy a direntry to a buffer, in fs byte order
+ */
+static void
+copy_dir(struct ext2fs_direct *dir, struct ext2fs_direct *dbuf)
+{
+
+ memcpy(dbuf, dir, EXT2FS_DIRSIZ(dir->e2d_namlen));
+ dbuf->e2d_ino = h2fs32(dir->e2d_ino);
+ dbuf->e2d_reclen = h2fs16(dir->e2d_reclen);
+}
+
+/*
+ * void init_resizeino(const struct timeval *tv);
+ *
+ * Initialize the EXT2_RESEIZE_INO inode to preserve
+ * reserved group descriptor blocks for future growth of this ext2fs.
+ */
+void
+init_resizeino(const struct timeval *tv)
+{
+ struct ext2fs_dinode node;
+ uint64_t isize;
+ uint32_t *dindir_block, *reserved_gdb;
+ uint nblock, i, cylno, n;
+
+ memset(&node, 0, sizeof(node));
+
+ /*
+ * Note this function only prepares required structures for
+ * future resize. It's a quite different work to implement
+ * a utility like resize_ext2fs(8) which handles actual
+ * resize ops even on offline.
+ *
+ * Anyway, I'm not sure if there is any documentation about
+ * this resize ext2fs feature and related data structures,
+ * and I've written this function based on things what I see
+ * on some existing implementation and real file system data
+ * created by existing tools. To be honest, they are not
+ * so easy to read, so I will try to implement it here without
+ * any dumb optimization for people who would eventually
+ * work on "yet another wheel" like resize_ext2fs(8).
+ */
+
+ /*
+ * I'm not sure what type is appropriate for this inode.
+ * The release notes of e2fsprogs says they changed e2fsck to allow
+ * IFREG for RESIZEINO since a certain resize tool used it. Hmm.
+ */
+ node.e2di_mode = EXT2_IFREG | EXT2_RESIZEINOUMASK;
+ node.e2di_uid = geteuid();
+ node.e2di_atime = tv->tv_sec;
+ node.e2di_ctime = tv->tv_sec;
+ node.e2di_mtime = tv->tv_sec;
+ node.e2di_gid = getegid();
+ node.e2di_nlink = 1;
+
+ /*
+ * To preserve the reserved group descriptor blocks,
+ * EXT2_RESIZEINO uses only double indirect reference
+ * blocks in its inode entries.
+ *
+ * All entries for direct, single indirect and triple
+ * indirect references are left zero'ed. Maybe it's safe
+ * because no write operation will happen with this inode.
+ *
+ * We have to allocate a block for the first level double
+ * indirect reference block. Indexes of inode entries in
+ * this first level dindirect block are corresponding to
+ * indexes of group descriptors including both used (e2fs_ngdb)
+ * and reserved (e2fs_reserved_ngdb) group descriptor blocks.
+ *
+ * Inode entries of indexes for used (e2fs_ngdb) descriptors are
+ * left zero'ed. Entries for reserved (e2fs_reserved_ngdb) ones
+ * have block numbers of actual reserved group descriptors
+ * allocated at block group zero. This means e2fs_reserved_ngdb
+ * blocks are reserved as the second level dindirect reference
+ * blocks, and they actually contain block numbers of indirect
+ * references. It may be safe since they don't have to keep any
+ * data yet.
+ *
+ * Each these second dindirect blocks (i.e. reserved group
+ * descriptor blocks in the first block group) should have
+ * block numbers of its backups in all other block groups.
+ * I.e. reserved_ngdb[0] block in block group 0 contains block
+ * numbers of resreved_ngdb[0] from group 1 through (e2fs_ncg - 1).
+ * The number of backups can be determined by the
+ * EXT2_ROCOMPAT_SPARSESUPER feature and cg_has_sb() macro
+ * as done in the above initcg() function.
+ */
+
+ /* set e2di_size which occupies whole blocks through DINDIR blocks */
+ isize = (uint64_t)sblock.e2fs_bsize * NDADDR +
+ (uint64_t)sblock.e2fs_bsize * NINDIR(&sblock) +
+ (uint64_t)sblock.e2fs_bsize * NINDIR(&sblock) * NINDIR(&sblock);
+ if (isize > UINT32_MAX &&
+ (sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_LARGEFILE) == 0) {
+ /* XXX should enable it here and update all backups? */
+ errx(EXIT_FAILURE, "%s: large_file rocompat feature is "
+ "required to enable resize feature for this filesystem\n",
+ __func__);
+ }
+ /* upper 32bit is stored into e2di_dacl on REV1 feature */
+ node.e2di_size = isize & UINT32_MAX;
+ node.e2di_dacl = isize >> 32;
+
+#define SINGLE 0 /* index of single indirect block */
+#define DOUBLE 1 /* index of double indirect block */
+#define TRIPLE 2 /* index of triple indirect block */
+
+ /* zero out entries for direct references */
+ for (i = 0; i < NDADDR; i++)
+ node.e2di_blocks[i] = 0;
+ /* also zero out entries for single and triple indirect references */
+ node.e2di_blocks[NDADDR + SINGLE] = 0;
+ node.e2di_blocks[NDADDR + TRIPLE] = 0;
+
+ /* allocate a block for the first level double indirect reference */
+ node.e2di_blocks[NDADDR + DOUBLE] =
+ alloc(sblock.e2fs_bsize, node.e2di_mode);
+ if (node.e2di_blocks[NDADDR + DOUBLE] == 0)
+ errx(EXIT_FAILURE, "%s: Can't allocate a dindirect block",
+ __func__);
+
+ /* account this first block */
+ nblock = fsbtodb(&sblock, 1);
+
+ /* allocate buffer to set data in the dindirect block */
+ dindir_block = malloc(sblock.e2fs_bsize);
+ if (dindir_block == NULL)
+ errx(EXIT_FAILURE,
+ "%s: Can't allocate buffer for a dindirect block",
+ __func__);
+
+ /* allocate buffer to set data in the group descriptor blocks */
+ reserved_gdb = malloc(sblock.e2fs_bsize);
+ if (reserved_gdb == NULL)
+ errx(EXIT_FAILURE,
+ "%s: Can't allocate buffer for group descriptor blocks",
+ __func__);
+
+ /*
+ * Setup block entries in the first level dindirect blocks
+ */
+ for (i = 0; i < sblock.e2fs_ngdb; i++) {
+ /* no need to handle used group descriptor blocks */
+ dindir_block[i] = 0;
+ }
+ for (; i < sblock.e2fs_ngdb + sblock.e2fs.e2fs_reserved_ngdb; i++) {
+ /*
+ * point reserved group descriptor block in the first
+ * (i.e. master) block group
+ *
+ * XXX: e2fsprogs seem to use "(i % NINDIR(&sblock))" here
+ * to store maximum NINDIR(&sblock) reserved gdbs.
+ * I'm not sure what will be done on future filesystem
+ * shrink in that case on their way.
+ */
+ if (i >= NINDIR(&sblock))
+ errx(EXIT_FAILURE, "%s: too many reserved "
+ "group descriptors (%u) for resize inode",
+ __func__, sblock.e2fs.e2fs_reserved_ngdb);
+ dindir_block[i] =
+ h2fs32(cgbase(&sblock, 0) + NBLOCK_SUPERBLOCK + i);
+
+ /*
+ * Setup block entries in the second dindirect blocks
+ * (which are primary reserved group descriptor blocks)
+ * to point their backups.
+ */
+ for (n = 0, cylno = 1; cylno < sblock.e2fs_ncg; cylno++) {
+ /* skip block groups without backup */
+ if ((sblock.e2fs.e2fs_features_rocompat &
+ EXT2F_ROCOMPAT_SPARSESUPER) != 0 &&
+ cg_has_sb(cylno) == 0)
+ continue;
+
+ if (n >= NINDIR(&sblock))
+ errx(EXIT_FAILURE, "%s: too many block groups "
+ "for the resize feature", __func__);
+ /*
+ * These blocks are already reserved in
+ * initcg() so no need to use alloc() here.
+ */
+ reserved_gdb[n++] = h2fs32(cgbase(&sblock, cylno) +
+ NBLOCK_SUPERBLOCK + i);
+ nblock += fsbtodb(&sblock, 1);
+ }
+ for (; n < NINDIR(&sblock); n++)
+ reserved_gdb[n] = 0;
+
+ /* write group descriptor block as the second dindirect refs */
+ wtfs(fsbtodb(&sblock, fs2h32(dindir_block[i])),
+ sblock.e2fs_bsize, reserved_gdb);
+ nblock += fsbtodb(&sblock, 1);
+ }
+ for (; i < NINDIR(&sblock); i++) {
+ /* leave trailing entries unallocated */
+ dindir_block[i] = 0;
+ }
+ free(reserved_gdb);
+
+ /* finally write the first level dindirect block */
+ wtfs(fsbtodb(&sblock, node.e2di_blocks[NDADDR + DOUBLE]),
+ sblock.e2fs_bsize, dindir_block);
+ free(dindir_block);
+
+ node.e2di_nblock = nblock;
+ iput(&node, EXT2_RESIZEINO);
+}
+
+/*
+ * uint32_t alloc(uint32_t size, uint16_t mode)
+ *
+ * Allocate a block (from cylinder group 0)
+ * Reference: src/sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_alloccg()
+ */
+uint32_t
+alloc(uint32_t size, uint16_t mode)
+{
+ uint32_t loc, bno;
+ uint8_t *bbp;
+ uint len, map, i;
+
+ if (gd[0].ext2bgd_nbfree == 0)
+ return 0;
+
+ if (size > sblock.e2fs_bsize)
+ return 0;
+
+ bbp = malloc(sblock.e2fs_bsize);
+ if (bbp == NULL)
+ return 0;
+ rdfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap), sblock.e2fs_bsize, bbp);
+
+ /* XXX: kernel uses e2fs_fpg here */
+ len = sblock.e2fs.e2fs_bpg / NBBY;
+
+#if 0 /* no need block allocation for root or lost+found dir */
+ for (loc = 0; loc < len; loc++) {
+ if (bbp[loc] == 0) {
+ bno = loc * NBBY;
+ goto gotit;
+ }
+ }
+#endif
+
+ loc = skpc(~0U, len, bbp);
+ if (loc == 0)
+ return 0;
+ loc = len - loc;
+ map = bbp[loc];
+ bno = loc * NBBY;
+ for (i = 0; i < NBBY; i++, bno++) {
+ if ((map & (1 << i)) == 0)
+ goto gotit;
+ }
+ return 0;
+
+ gotit:
+ if (isset(bbp, bno))
+ errx(EXIT_FAILURE, "%s: inconsistent bitmap\n", __func__);
+
+ setbit(bbp, bno);
+ wtfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap), sblock.e2fs_bsize, bbp);
+ free(bbp);
+ /* XXX: modified group descriptors won't be written into backups */
+ gd[0].ext2bgd_nbfree--;
+ if ((mode & EXT2_IFDIR) != 0)
+ gd[0].ext2bgd_ndirs++;
+ sblock.e2fs.e2fs_fbcount--;
+
+ return sblock.e2fs.e2fs_first_dblock + bno;
+}
+
+/*
+ * void iput(struct ext2fs_dinode *ip, ino_t ino)
+ *
+ * Put an inode entry into the corresponding table.
+ */
+static void
+iput(struct ext2fs_dinode *ip, ino_t ino)
+{
+ daddr_t d;
+ uint c, i;
+ struct ext2fs_dinode *dp;
+ uint8_t *bp;
+
+ bp = malloc(sblock.e2fs_bsize);
+ if (bp == NULL)
+ errx(EXIT_FAILURE, "%s: can't allocate buffer for inode\n",
+ __func__);
+
+ /*
+ * Reserved inodes are allocated and accounted in initcg()
+ * so skip checks of the bitmap and allocation for them.
+ */
+ if (ino >= EXT2_FIRSTINO) {
+ c = ino_to_cg(&sblock, ino);
+
+ /* sanity check */
+ if (gd[c].ext2bgd_nifree == 0)
+ errx(EXIT_FAILURE,
+ "%s: no free inode %" PRIu64 " in block group %u\n",
+ __func__, (uint64_t)ino, c);
+
+ /* update inode bitmap */
+ rdfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap),
+ sblock.e2fs_bsize, bp);
+
+ /* more sanity */
+ if (isset(bp, EXT2_INO_INDEX(ino)))
+ errx(EXIT_FAILURE, "%s: inode %" PRIu64
+ " already in use\n", __func__, (uint64_t)ino);
+ setbit(bp, EXT2_INO_INDEX(ino));
+ wtfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap),
+ sblock.e2fs_bsize, bp);
+ gd[c].ext2bgd_nifree--;
+ sblock.e2fs.e2fs_ficount--;
+ }
+
+ if (ino >= sblock.e2fs.e2fs_ipg * sblock.e2fs_ncg)
+ errx(EXIT_FAILURE, "%s: inode value out of range (%" PRIu64
+ ").\n", __func__, (uint64_t)ino);
+
+ /* update an inode entry in the table */
+ d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
+ rdfs(d, sblock.e2fs_bsize, bp);
+
+ dp = (struct ext2fs_dinode *)(bp +
+ inodesize * ino_to_fsbo(&sblock, ino));
+ e2fs_isave(ip, dp);
+ /* e2fs_i_bswap() doesn't swap e2di_blocks addrs */
+ if ((ip->e2di_mode & EXT2_IFMT) != EXT2_IFLNK) {
+ for (i = 0; i < NDADDR + NIADDR; i++)
+ dp->e2di_blocks[i] = h2fs32(ip->e2di_blocks[i]);
+ }
+ /* h2fs32() just for consistency */
+ dp->e2di_gen = h2fs32(arc4random());
+
+ wtfs(d, sblock.e2fs_bsize, bp);
+ free(bp);
+}
+
+/*
+ * Read a block from the file system
+ */
+void
+rdfs(daddr_t bno, int size, void *bf)
+{
+ int n;
+#ifndef __minix
+ off_t offset;
+#else
+ u64_t offset;
+#endif
+
+ offset = bno;
+#ifndef __minix
+ n = pread(fsi, bf, size, offset * sectorsize);
+#else
+ n = pread64(fsi, bf, size, offset * sectorsize);
+#endif
+ if (n != size)
+ err(EXIT_FAILURE, "%s: read error for sector %" PRId64,
+ __func__, (int64_t)bno);
+}
+
+/*
+ * Write a block to the file system
+ */
+void
+wtfs(daddr_t bno, int size, void *bf)
+{
+ int n;
+#ifndef __minix
+ off_t offset;
+#else
+ u64_t offset;
+#endif
+
+ if (Nflag)
+ return;
+ offset = bno;
+ errno = 0;
+#ifndef __minix
+ n = pwrite(fso, bf, size, offset * sectorsize);
+#else
+ n = pwrite64(fso, bf, size, offset * sectorsize);
+#endif
+ if (n != size)
+ err(EXIT_FAILURE, "%s: write error for sector %" PRId64,
+ __func__, (int64_t)bno);
+}
+
+int
+ilog2(uint val)
+{
+
+ if (val == 0 || !powerof2(val))
+ errx(EXIT_FAILURE, "%s: %u is not a power of 2\n",
+ __func__, val);
+
+ return ffs(val) - 1;
+}
+
+/*
+ * int skpc(int mask, size_t size, uint8_t *cp)
+ *
+ * Locate an unsigned character of value mask inside cp[].
+ * (from src/sys/lib/libkern/skpc.c)
+ */
+int
+skpc(int mask, size_t size, uint8_t *cp)
+{
+ uint8_t *end;
+
+ end = &cp[size];
+ while (cp < end && *cp == (uint8_t)mask)
+ cp++;
+
+ return end - cp;
+}
--- /dev/null
+.\" $NetBSD: newfs_ext2fs.8,v 1.11 2010/02/25 13:09:17 tsutsui Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 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.
+.\"
+.\" @(#)newfs.8 8.6 (Berkeley) 5/3/95
+.\"
+.Dd March 1, 2009
+.Dt NEWFS_EXT2FS 8
+.Os
+.Sh NAME
+.Nm newfs_ext2fs
+.Nd construct a new ext2 file system
+.Sh SYNOPSIS
+.Nm
+.Op Fl FINZ
+.Op Fl b Ar block-size
+.Op Fl D Ar inodesize
+.Op Fl f Ar frag-size
+.Op Fl i Ar bytes-per-inode
+.Op Fl m Ar free-space
+.Op Fl n Ar inodes
+.Op Fl O Ar filesystem-format
+.Op Fl S Ar sector-size
+.Op Fl s Ar size
+.Op Fl V Ar verbose
+.Op Fl v Ar volname
+.Ar special
+.Sh DESCRIPTION
+.Nm
+is used to initialize and clear ext2 file systems before first use.
+Before running
+.Nm
+the disk must be labeled using
+.Xr disklabel 8 .
+.Nm
+builds a file system on the specified special device
+basing its defaults on the information in the disk label.
+Typically the defaults are reasonable, however
+.Nm
+has numerous options to allow the defaults to be selectively overridden.
+.Pp
+Options with numeric arguments may contain an optional (case-insensitive)
+suffix:
+.Bl -tag -width 3n -offset indent -compact
+.It b
+Bytes; causes no modification.
+(Default)
+.It k
+Kilo; multiply the argument by 1024.
+.It m
+Mega; multiply the argument by 1048576.
+.It g
+Giga; multiply the argument by 1073741824.
+.El
+.Pp
+The following options define the general layout policies.
+.Bl -tag -width Fl
+.It Fl b Ar block-size
+The block size of the file system, in bytes.
+It must be a power of two.
+The smallest allowable size is 1024 bytes.
+The default size depends upon the size of the file system:
+.Pp
+.Bl -tag -width "file system size" -compact -offset indent
+.It Sy "file system size"
+.Ar block-size
+.It \*[Lt]= 512 MB
+1 KB
+.It \*[Gt] 512 MB
+4 KB
+.El
+.It Fl D Ar inodesize
+Set the inode size.
+Defaults to 128, and can also be set to 256 for
+compatibility with ext4.
+.It Fl F
+Create a file system image in
+.Ar special .
+The file system size needs to be specified with
+.Dq Fl s Ar size .
+No attempts to use or update the disk label will be made.
+.It Fl f Ar frag-size
+The fragment size of the file system in bytes.
+It must be the same with blocksize because the current ext2fs
+implementation doesn't support fragmentation.
+.It Fl I
+Do not require that the file system type listed in the disk label is
+.Ql Linux\ Ext2 .
+.It Fl i Ar bytes-per-inode
+This specifies the density of inodes in the file system.
+If fewer inodes are desired, a larger number should be used;
+to create more inodes a smaller number should be given.
+.It Fl m Ar free-space
+The percentage of space reserved from normal users; the minimum free
+space threshold.
+The default value used is 5%.
+.It Fl N
+Causes the file system parameters to be printed out
+without really creating the file system.
+.It Fl n Ar inodes
+This specifies the number of inodes for the file system.
+If both
+.Fl i
+and
+.Fl n
+are specified then
+.Fl n
+takes precedence.
+The default number of inodes is calculated from a number of blocks in
+the file system.
+.It Fl O Ar filesystem-format
+Select the filesystem-format.
+.Bl -tag -width 3n -offset indent -compact
+.It 0
+.Ql GOOD_OLD_REV ;
+this option is primarily used to build root file systems that can be
+understood by old or dumb firmwares for bootstrap.
+(default)
+.It 1
+.Ql DYNAMIC_REV ;
+various extended (and sometimes incompatible) features are enabled
+(though not all features are supported on
+.Nx ) .
+Currently only the following features are supported:
+.Bl -tag -width "SPARSESUPER" -offset indent -compact
+.It RESIZE
+Prepare some reserved structures which enable future file system resizing.
+.It FTYPE
+Store file types in directory entries to improve performance.
+.It SPARSESUPER
+Prepare superblock backups for the
+.Xr fsck_ext2fs 8
+utility on not all but sparse block groups.
+.It LARGEFILE
+Enable files larger than 2G bytes.
+.El
+.El
+.It Fl s Ar size
+The size of the file system in sectors.
+An
+.Sq s
+suffix will be interpreted as the number of sectors (the default).
+All other suffixes are interpreted as per other numeric arguments,
+except that the number is converted into sectors by dividing by the
+sector size (as specified by
+.Fl S Ar secsize )
+after suffix interpretation.
+.Pp
+If no
+.Fl s Ar size
+is specified then the filesystem size defaults to that of the partition, or,
+if
+.Fl F
+is specified, the existing file.
+.Pp
+If
+.Ar size
+is negative the specified size is subtracted from the default size
+(reserving space at the end of the partition).
+.It Fl V Ar verbose
+This controls the amount of information written to stdout:
+.Bl -tag -width 3n -offset indent -compact
+.It 0
+No output.
+.It 1
+Overall size and cylinder group details.
+.It 2
+A progress bar (dots ending at right hand margin).
+.It 3
+The first few super-block backup sector numbers are displayed before the
+progress bar.
+.It 4
+All the super-block backup sector numbers are displayed (no progress bar).
+.El
+The default is 3.
+If
+.Fl N
+is specified
+.Nm
+stops before outputting the progress bar.
+.It Fl v Ar volname
+This specifies a volume name for the file system.
+.It Fl Z
+Pre-zeros the file system image created with
+.Fl F .
+This is necessary if the image is to be used by
+.Xr vnd 4
+(which doesn't support file systems with
+.Sq holes ) .
+.El
+.Pp
+The following option overrides the standard sizes for the disk geometry.
+The default value is taken from the disk label.
+Changing this default is useful only when using
+.Nm
+to build a file system whose raw image will eventually be used on a
+different type of disk than the one on which it is initially created
+(for example on a write-once disk).
+Note that changing this value from its default will make it impossible for
+.Xr fsck_ext2fs 8
+to find the alternative superblocks if the standard superblock is lost.
+.Bl -tag -width Fl
+.It Fl S Ar sector-size
+The size of a sector in bytes (almost never anything but 512).
+Defaults to 512.
+.El
+.Sh NOTES
+There is no option to specify the metadata byte order on the file system
+to be created because the native ext2 file system is always little endian
+even on big endian hosts.
+.Pp
+The file system is created with
+.Sq random
+inode generation numbers to improve NFS security.
+.Pp
+The owner and group IDs of the root node and reserved blocks of the new
+file system are set to the effective UID and GID of the user initializing
+the file system.
+.Pp
+For the
+.Nm
+command to succeed,
+the disk label should first be updated such that the fstype field for the
+partition is set to
+.Ql Linux\ Ext2 ,
+unless
+.Fl F
+or
+.Fl I
+is used.
+.Pp
+.\" To create and populate a filesystem image within a file use the
+.\" .Xr makefs 8
+.\" utility.
+.\" .Pp
+The partition size is found using
+.Xr fstat 2 ,
+not by inspecting the disk label.
+The block size and fragment size will be written back to the disk label
+only if the last character of
+.Ar special
+references the same partition as the minor device number.
+.Sh SEE ALSO
+.Xr fstat 2 ,
+.Xr disklabel 5 ,
+.Xr disktab 5 ,
+.Xr fs 5 ,
+.Xr disklabel 8 ,
+.Xr diskpart 8 ,
+.\" .Xr dumpfs 8 ,
+.\" .Xr format 8 ,
+.Xr fsck_ext2fs 8 ,
+.\" .Xr makefs 8 ,
+.Xr mount 8 ,
+.Xr mount_ext2fs 8 ,
+.Xr newfs 8
+.Rs
+.%A Remy Card
+.%A Theodore Ts'o
+.%A Stephen Tweedie
+.%T "Design and Implementation of the Second Extended Filesystem"
+.%J "The Proceedings of the First Dutch International Symposium on Linux"
+.%U http://e2fsprogs.sourceforge.net/ext2intro.html
+.Re
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Nx 5.0 .
+.Sh AUTHORS
+The
+.Nm
+command was written by
+.An Izumi Tsutsui
+.Aq tsutsui@NetBSD.org .
+.Sh BUGS
+The
+.Nm
+command is still experimental and there are few sanity checks.
+.Pp
+The
+.Nm
+command doesn't have options to specify each REV1 file system feature
+independently.
+.Pp
+The
+.Nm
+command doesn't support the bad block list accounted by the bad blocks inode.
+.Pp
+Many newer ext2 file system features (especially journaling) are
+not supported yet.
+.Pp
+Some features in file systems created by the
+.Nm
+command might not be recognized properly by the
+.Xr fsck_ext2fs 8
+utility.
+.Pp
+There is no native tool in the
+.Nx
+distribution for resizing ext2 file systems yet.
--- /dev/null
+/* $NetBSD: newfs_ext2fs.c,v 1.8 2009/03/02 10:38:13 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 1983, 1989, 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)newfs.c 8.13 (Berkeley) 5/1/95";
+#else
+__RCSID("$NetBSD: newfs_ext2fs.c,v 1.8 2009/03/02 10:38:13 tsutsui Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * newfs: friendly front end to mke2fs
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+
+#include <disktab.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <mntopts.h>
+
+#include <minix/partition.h>
+
+#include "extern.h"
+#include "partutil.h"
+
+static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *);
+static void usage(void) __dead;
+
+/*
+ * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults,
+ * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
+ * L_DFL_*.
+ */
+#define SMALL_FSSIZE ((4 * 1024 * 1024) / sectorsize) /* 4MB */
+#define S_DFL_BSIZE 1024
+#define MEDIUM_FSSIZE ((512 * 1024 * 1024) / sectorsize) /* 512MB */
+#define M_DFL_BSIZE 1024
+#define L_DFL_BSIZE 4096
+
+/*
+ * Each file system has a number of inodes statically allocated.
+ * We allocate one inode slot per 2, 4, or 8 blocks, expecting this
+ * to be far more than we will ever need.
+ */
+#define S_DFL_NINODE(blocks) ((blocks) / 8)
+#define M_DFL_NINODE(blocks) ((blocks) / 4)
+#define L_DFL_NINODE(blocks) ((blocks) / 2)
+
+/*
+ * Default sector size.
+ */
+#define DFL_SECSIZE 512
+
+int Nflag; /* run without writing file system */
+int Oflag = 0; /* format as conservative REV0 by default */
+int verbosity; /* amount of printf() output */
+#define DEFAULT_VERBOSITY 3 /* 4 is traditional behavior of newfs(8) */
+int64_t fssize; /* file system size */
+uint sectorsize; /* bytes/sector */
+uint16_t inodesize = EXT2_REV0_DINODE_SIZE; /* inode size */
+uint fsize = 0; /* fragment size */
+uint bsize = 0; /* block size */
+uint minfree = MINFREE; /* free space threshold */
+uint density; /* number of bytes per inode */
+uint num_inodes; /* number of inodes (overrides density) */
+char *volname = NULL; /* volume name */
+
+#ifndef __minix
+static char *disktype = NULL;
+#endif
+static char device[MAXPATHLEN];
+
+static const char lmsg[] = "%s: can't read disk label";
+
+int
+main(int argc, char *argv[])
+{
+#ifndef __minix
+ struct disk_geom geo;
+ struct dkwedge_info dkw;
+ struct statvfs *mp;
+ char *s2;
+ int len, n;
+#else
+ u64_t minix_fssize;
+#endif
+ struct stat sb;
+ int ch, fsi, fso, Fflag, Iflag, Zflag;
+ char *cp, *s1, *special;
+ const char *opstring;
+ int byte_sized;
+ uint blocks; /* number of blocks */
+
+ cp = NULL;
+ fso = -1;
+ Fflag = Iflag = Zflag = 0;
+ verbosity = -1;
+ opstring = "D:FINO:S:V:Zb:f:i:l:m:n:s:v:B:";
+ byte_sized = 0;
+ while ((ch = getopt(argc, argv, opstring)) != -1)
+ switch (ch) {
+ case 'D':
+ inodesize = (uint16_t)strtol(optarg, &s1, 0);
+ if (*s1 || (inodesize != 128 && inodesize != 256))
+ errx(1, "Bad inode size %d "
+ "(only 128 and 256 supported)", inodesize);
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+#ifndef __minix
+ case 'I':
+ Iflag = 1;
+ break;
+#endif
+ case 'N':
+ Nflag = 1;
+ if (verbosity == -1)
+ verbosity = DEFAULT_VERBOSITY;
+ break;
+ case 'O':
+ Oflag = strsuftoi64("format", optarg, 0, 1, NULL);
+ break;
+ case 'S':
+ /*
+ * XXX:
+ * non-512 byte sectors almost certainly don't work.
+ */
+ sectorsize = strsuftoi64("sector size",
+ optarg, 512, 65536, NULL);
+ if (!powerof2(sectorsize))
+ errx(EXIT_FAILURE,
+ "sector size `%s' is not a power of 2.",
+ optarg);
+ break;
+ case 'V':
+ verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL);
+ break;
+#ifndef __minix
+ case 'Z':
+ Zflag = 1;
+ break;
+#endif
+ case 'B':
+ case 'b':
+ bsize = strsuftoi64("block size",
+ optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
+ break;
+ case 'f':
+ fsize = strsuftoi64("fragment size",
+ optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
+ break;
+ case 'i':
+ density = strsuftoi64("bytes per inode",
+ optarg, 1, INT_MAX, NULL);
+ break;
+ case 'm':
+ minfree = strsuftoi64("free space %",
+ optarg, 0, 99, NULL);
+ break;
+ case 'n':
+ num_inodes = strsuftoi64("number of inodes",
+ optarg, 1, INT_MAX, NULL);
+ break;
+ case 's':
+ fssize = strsuftoi64("file system size",
+ optarg, INT64_MIN, INT64_MAX, &byte_sized);
+ break;
+ case 'v':
+ volname = optarg;
+ if (volname[0] == '\0')
+ errx(EXIT_FAILURE,
+ "Volume name cannot be zero length");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (verbosity == -1)
+ /* Default to showing cg info */
+ verbosity = DEFAULT_VERBOSITY;
+
+ if (argc != 1)
+ usage();
+
+ memset(&sb, 0, sizeof(sb));
+#ifndef __minix
+ memset(&dkw, 0, sizeof(dkw));
+#endif
+ special = argv[0];
+ if (Fflag) {
+ int fl;
+ /*
+ * It's a file system image
+ * no label, use fixed default for sectorsize.
+ */
+ if (sectorsize == 0)
+ sectorsize = DFL_SECSIZE;
+
+ /* creating image in a regular file */
+ if (Nflag)
+ fl = O_RDONLY;
+ else {
+ if (fssize > 0)
+ fl = O_RDWR | O_CREAT;
+ else
+ fl = O_RDWR;
+ }
+ fsi = open(special, fl, 0777);
+ if (fsi == -1)
+ err(EXIT_FAILURE, "can't open file %s", special);
+ if (fstat(fsi, &sb) == -1)
+ err(EXIT_FAILURE, "can't fstat opened %s", special);
+ if (!Nflag)
+ fso = fsi;
+ } else { /* !Fflag */
+ fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0);
+ special = device;
+ if (fsi < 0 || fstat(fsi, &sb) == -1)
+ err(EXIT_FAILURE, "%s: open for read", special);
+
+#ifndef __minix
+ if (!Nflag) {
+ fso = open(special, O_WRONLY, 0);
+ if (fso < 0)
+ err(EXIT_FAILURE,
+ "%s: open for write", special);
+
+ /* Bail if target special is mounted */
+ n = getmntinfo(&mp, MNT_NOWAIT);
+ if (n == 0)
+ err(EXIT_FAILURE, "%s: getmntinfo", special);
+
+ len = sizeof(_PATH_DEV) - 1;
+ s1 = special;
+ if (strncmp(_PATH_DEV, s1, len) == 0)
+ s1 += len;
+
+ while (--n >= 0) {
+ s2 = mp->f_mntfromname;
+ if (strncmp(_PATH_DEV, s2, len) == 0) {
+ s2 += len - 1;
+ *s2 = 'r';
+ }
+ if (strcmp(s1, s2) == 0 ||
+ strcmp(s1, &s2[1]) == 0)
+ errx(EXIT_FAILURE,
+ "%s is mounted on %s",
+ special, mp->f_mntonname);
+ ++mp;
+ }
+ }
+
+ if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1)
+ errx(EXIT_FAILURE, lmsg, special);
+
+ if (sectorsize == 0) {
+ sectorsize = geo.dg_secsize;
+ if (sectorsize <= 0)
+ errx(EXIT_FAILURE, "no default sector size");
+ }
+
+ if (dkw.dkw_parent[0]) {
+ if (dkw.dkw_size == 0)
+ errx(EXIT_FAILURE,
+ "%s partition is unavailable", special);
+
+ if (!Iflag) {
+ static const char m[] =
+ "%s partition type is not `%s' (or use -I)";
+ if (strcmp(dkw.dkw_ptype, DKW_PTYPE_EXT2FS))
+ errx(EXIT_FAILURE, m,
+ special, "Linux Ext2");
+ }
+ }
+#else
+ {
+ fso = open(special, O_WRONLY, 0);
+ if (fso < 0)
+ err(EXIT_FAILURE,
+ "%s: open for write", special);
+
+ if(minix_sizeup(special, &minix_fssize) < 0)
+ errx(EXIT_FAILURE, "minix_sizeup failed");
+
+ fssize = minix_fssize;
+ byte_sized = 1;
+
+ if (sectorsize == 0)
+ sectorsize = 512;
+ }
+#endif
+ }
+
+ if (byte_sized)
+ fssize /= sectorsize;
+#ifndef __minix
+ if (fssize <= 0) {
+ if (sb.st_size != 0)
+ fssize += sb.st_size / sectorsize;
+ else
+ fssize += dkw.dkw_size;
+ if (fssize <= 0)
+ errx(EXIT_FAILURE,
+ "Unable to determine file system size");
+ }
+
+ if (dkw.dkw_parent[0] && fssize > dkw.dkw_size)
+ errx(EXIT_FAILURE,
+ "size %" PRIu64 " exceeds maximum file system size on "
+ "`%s' of %" PRIu64 " sectors",
+ fssize, special, dkw.dkw_size);
+#endif
+
+ printf("fssize = %lld %d-byte sectors\n", fssize, sectorsize);
+
+ /* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */
+ if (Fflag && fso != -1
+ && ftruncate(fso, (off_t)fssize * sectorsize) == -1)
+ err(1, "can't ftruncate %s to %" PRId64, special, fssize);
+
+#ifndef __minix
+ if (Zflag && fso != -1) { /* pre-zero (and de-sparce) the file */
+ char *buf;
+ int bufsize, i;
+ off_t bufrem;
+
+ struct statvfs sfs;
+ if (fstatvfs(fso, &sfs) == -1) {
+ warn("can't fstatvfs `%s'", special);
+ bufsize = 8192;
+ } else
+ bufsize = sfs.f_iosize;
+
+ if ((buf = calloc(1, bufsize)) == NULL)
+ err(1, "can't malloc buffer of %d",
+ bufsize);
+ bufrem = fssize * sectorsize;
+ if (verbosity > 0)
+ printf("Creating file system image in `%s', "
+ "size %" PRId64 " bytes, in %d byte chunks.\n",
+ special, (signed long long) bufrem, bufsize);
+ while (bufrem > 0) {
+ i = write(fso, buf, MIN(bufsize, bufrem));
+ if (i == -1)
+ err(1, "writing image");
+ bufrem -= i;
+ }
+ free(buf);
+ }
+#endif
+
+ /* Sort out fragment and block sizes */
+ if (bsize == 0) {
+ bsize = fsize;
+ if (bsize == 0) {
+ if (fssize < SMALL_FSSIZE)
+ bsize = S_DFL_BSIZE;
+ else if (fssize < MEDIUM_FSSIZE)
+ bsize = M_DFL_BSIZE;
+ else
+ bsize = L_DFL_BSIZE;
+ }
+ }
+
+ if (fsize == 0)
+ fsize = bsize;
+
+ blocks = fssize * sectorsize / bsize;
+
+ fssize = (u64_t) blocks * bsize / sectorsize;
+
+ if (num_inodes == 0) {
+ if (density != 0)
+ num_inodes = fssize / density;
+ else {
+ if (fssize < SMALL_FSSIZE)
+ num_inodes = S_DFL_NINODE(blocks);
+ else if (fssize < MEDIUM_FSSIZE)
+ num_inodes = M_DFL_NINODE(blocks);
+ else
+ num_inodes = L_DFL_NINODE(blocks);
+ }
+ }
+ mke2fs(special, fsi, fso);
+
+ if (fsi != -1)
+ close(fsi);
+ if (fso != -1 && fso != fsi)
+ close(fso);
+ exit(EXIT_SUCCESS);
+}
+
+static int64_t
+strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max,
+ int *num_suffix)
+{
+ int64_t result, r1;
+ int shift = 0;
+ char *ep;
+
+ errno = 0;
+ r1 = strtoll(arg, &ep, 10);
+ if (ep[0] != '\0' && ep[1] != '\0')
+ errx(EXIT_FAILURE,
+ "%s `%s' is not a valid number.", desc, arg);
+ switch (ep[0]) {
+ case '\0':
+ case 's':
+ case 'S':
+ if (num_suffix != NULL)
+ *num_suffix = 0;
+ break;
+ case 'g':
+ case 'G':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'm':
+ case 'M':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'k':
+ case 'K':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'b':
+ case 'B':
+ if (num_suffix != NULL)
+ *num_suffix = 1;
+ break;
+ default:
+ errx(EXIT_FAILURE,
+ "`%s' is not a valid suffix for %s.", ep, desc);
+ }
+ result = r1 << shift;
+ if (errno == ERANGE || result >> shift != r1)
+ errx(EXIT_FAILURE,
+ "%s `%s' is too large to convert.", desc, arg);
+ if (result < min)
+ errx(EXIT_FAILURE,
+ "%s `%s' (%" PRId64 ") is less than the minimum (%"
+ PRId64 ").", desc, arg, result, min);
+ if (result > max)
+ errx(EXIT_FAILURE,
+ "%s `%s' (%" PRId64 ") is greater than the maximum (%"
+ PRId64 ").", desc, arg, result, max);
+ return result;
+}
+
+static const char help_strings[] =
+ "\t-b bsize\tblock size\n"
+ "\t-D inodesize\tsize of an inode in bytes (128 or 256)\n"
+ "\t-F \t\tcreate file system image in regular file\n"
+ "\t-f fsize\tfragment size\n"
+ "\t-I \t\tdo not check that the file system type is `Linux Ext2'\n"
+ "\t-i density\tnumber of bytes per inode\n"
+ "\t-m minfree\tminimum free space %\n"
+ "\t-N \t\tdo not create file system, just print out parameters\n"
+ "\t-n inodes\tnumber of inodes (overrides -i density)\n"
+ "\t-O N\t\tfilesystem revision: 0 ==> REV0, 1 ==> REV1 (default 0)\n"
+ "\t-S secsize\tsector size\n"
+ "\t-s fssize\tfile system size (sectors)\n"
+ "\t-V verbose\toutput verbosity: 0 ==> none, 4 ==> max\n"
+ "\t-v volname\text2fs volume name\n"
+ "\t-Z \t\tpre-zero the image file\n";
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+ "usage: %s [ fsoptions ] special-device\n", getprogname());
+ fprintf(stderr, "where fsoptions are:\n");
+ fprintf(stderr, "%s", help_strings);
+
+ exit(EXIT_FAILURE);
+}