import netbsd ext2fs fsck and newfs

This commit is contained in:
Ben Gras 2011-12-22 17:54:36 +01:00
parent 4d4057d8a2
commit 94715d8e54
61 changed files with 14958 additions and 5 deletions

View file

@ -23,6 +23,10 @@ TOTALMB="`expr 3 + $USRKB / 1024 + $ROOTMB`"
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?"
@ -459,17 +463,17 @@ if [ "$nohome" = 0 ]
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
@ -504,7 +508,7 @@ ln -s /usr/log /mnt/var/log
# 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.

View file

@ -10,6 +10,10 @@
#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 */

View file

@ -180,6 +180,7 @@ struct disklabel {
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 */
@ -199,6 +200,7 @@ struct disklabel {
#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

View file

@ -38,6 +38,31 @@ __RCSID("$NetBSD: uuid_create.c,v 1.1 2004/09/13 21:44:54 thorpej Exp $");
#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:

View file

@ -24,6 +24,20 @@ INCS= a.out.h aio.h ar.h assert.h atomic.h \
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 \

View file

@ -0,0 +1,768 @@
/* $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__ */

View file

@ -0,0 +1,53 @@
/* $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_ */

View file

@ -0,0 +1,136 @@
/* $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__ */

View file

@ -0,0 +1,84 @@
/* $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_ */

View file

@ -0,0 +1,97 @@
/* $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__ */

318
nbsd_include/ufs/chfs/ebh.h Normal file
View file

@ -0,0 +1,318 @@
/* $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_ */

View file

@ -0,0 +1,116 @@
/* $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_ */

View file

@ -0,0 +1,88 @@
/* $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_ */

View file

@ -0,0 +1,200 @@
/*-
* 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__ */

View file

@ -0,0 +1,372 @@
/* $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_ */

View file

@ -0,0 +1,186 @@
/* $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_ */

View file

@ -0,0 +1,180 @@
/* $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_ */

View file

@ -0,0 +1,179 @@
/* $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_ */

View file

@ -0,0 +1,211 @@
/* $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_ */

752
nbsd_include/ufs/ffs/fs.h Normal file
View file

@ -0,0 +1,752 @@
/* $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_ */

1156
nbsd_include/ufs/lfs/lfs.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,287 @@
/* $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_ */

View file

@ -0,0 +1,79 @@
/* $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_ */

View file

@ -0,0 +1,91 @@
/* $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_ */

View file

@ -0,0 +1,180 @@
/* $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_ */

160
nbsd_include/ufs/ufs/dir.h Normal file
View file

@ -0,0 +1,160 @@
/* $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_ */

View file

@ -0,0 +1,129 @@
/* $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_ */

View file

@ -0,0 +1,128 @@
/* $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_ */

View file

@ -0,0 +1,300 @@
/* $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_ */

View file

@ -0,0 +1,97 @@
/* $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_ */

View file

@ -0,0 +1,111 @@
/* $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_ */

View file

@ -0,0 +1,131 @@
/* $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_ */

View file

@ -0,0 +1,80 @@
/* $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_ */

View file

@ -0,0 +1,188 @@
/* $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_ */

View file

@ -0,0 +1,130 @@
/* $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 *);

View file

@ -0,0 +1,178 @@
/* $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_ */

View file

@ -0,0 +1,197 @@
/* $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_ */

View file

@ -2,6 +2,6 @@
.include <bsd.own.mk>
SUBDIR= fsck
SUBDIR= fsck fsck_ext2fs newfs_ext2fs
.include <bsd.subdir.mk>

View file

@ -183,6 +183,11 @@ main(int argc, char *argv[])
if (flags & CHECK_PROGRESS)
maxrun = 1;
#ifdef __minix
/* parallel checking heuristic doesn't work for minix currently */
maxrun = 1;
#endif
argc -= optind;
argv += optind;
@ -552,6 +557,9 @@ mangle(char *opts, int *argcp, const char ** volatile *argvp, int *maxargcp)
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;
@ -589,6 +597,7 @@ getfslab(const char *str)
fstypenames[t], str);
return vfstype;
#endif
}

View file

@ -92,6 +92,9 @@ dict2geom(struct disk_geom *geo, prop_dictionary_t dict)
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;
@ -150,6 +153,7 @@ part2wedge(struct dkwedge_info *dkw, const struct disklabel *lp, const char *s)
(void)strcpy(dkw->dkw_ptype, DKW_PTYPE_NTFS);
break;
}
#endif
}
int

19
sbin/fsck_ext2fs/Makefile Normal file
View file

@ -0,0 +1,19 @@
# $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}

723
sbin/fsck_ext2fs/dir.c Normal file
View file

@ -0,0 +1,723 @@
/* $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);
}

View file

@ -0,0 +1,121 @@
/* $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

73
sbin/fsck_ext2fs/extern.h Normal file
View file

@ -0,0 +1,73 @@
/* $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);

238
sbin/fsck_ext2fs/fsck.h Normal file
View file

@ -0,0 +1,238 @@
/* $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 */

View file

@ -0,0 +1,253 @@
.\" $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

736
sbin/fsck_ext2fs/inode.c Normal file
View file

@ -0,0 +1,736 @@
/* $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--;
}

358
sbin/fsck_ext2fs/main.c Normal file
View file

@ -0,0 +1,358 @@
/* $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);
}

394
sbin/fsck_ext2fs/pass1.c Normal file
View file

@ -0,0 +1,394 @@
/* $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);
}

130
sbin/fsck_ext2fs/pass1b.c Normal file
View file

@ -0,0 +1,130 @@
/* $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);
}

470
sbin/fsck_ext2fs/pass2.c Normal file
View file

@ -0,0 +1,470 @@
/* $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]);
}

100
sbin/fsck_ext2fs/pass3.c Normal file
View file

@ -0,0 +1,100 @@
/* $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();
}
}

164
sbin/fsck_ext2fs/pass4.c Normal file
View file

@ -0,0 +1,164 @@
/* $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);
}

277
sbin/fsck_ext2fs/pass5.c Normal file
View file

@ -0,0 +1,277 @@
/* $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");
}
}

559
sbin/fsck_ext2fs/setup.c Normal file
View file

@ -0,0 +1,559 @@
/* $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;
}

View file

@ -0,0 +1,527 @@
/* $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 */
}

View file

@ -0,0 +1,27 @@
# $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>

View file

@ -0,0 +1,45 @@
/* $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 */

1459
sbin/newfs_ext2fs/mke2fs.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,326 @@
.\" $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.

View file

@ -0,0 +1,530 @@
/* $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);
}