> Date: Mon, 18 Jul 2016 11:52:15 +0300 > From: Artturi Alm <[email protected]> > > iHi, > > optimistic as always, this would be one item off the list making me own > this shit.:) octeon might benefit also, but haven't tested on one. > didn't figure out how to make a proper diff for ports/sysutils/u-boot/ > against cvs, so here is diff to be applied directly on top of recent > u-boot master. whacked out of sys/lib/libsa/.
Having ffs support in u-boot would indeed be useful. That said, the recommended way to load OpenBSD kernels is through the efiboot bootloader as it will provide the kernel with initial entropy. Ultimately this code should be contributed back upstream. We don't really want to maintain large patches like this in the ports tree. Cheers, Mark > diff --git a/cmd/Kconfig b/cmd/Kconfig > index d69b817..deaf9f3 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -689,6 +689,12 @@ config CMD_FAT > help > Support for the FAT fs > > +config CMD_FFS > + bool "FFS command support" > + default y > + help > + Support for the FFS fs > + > config CMD_FS_GENERIC > bool "filesystem commands" > help > diff --git a/cmd/Makefile b/cmd/Makefile > index a1731be..7c45710 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -53,6 +53,7 @@ obj-$(CONFIG_HUSH_PARSER) += exit.o > obj-$(CONFIG_CMD_EXT4) += ext4.o > obj-$(CONFIG_CMD_EXT2) += ext2.o > obj-$(CONFIG_CMD_FAT) += fat.o > +obj-$(CONFIG_CMD_FFS) += ffs.o > obj-$(CONFIG_CMD_FDC) += fdc.o > obj-$(CONFIG_CMD_FDT) += fdt.o > obj-$(CONFIG_CMD_FITUPD) += fitupd.o > diff --git a/cmd/ffs.c b/cmd/ffs.c > new file mode 100644 > index 0000000..d0536bd > --- /dev/null > +++ b/cmd/ffs.c > @@ -0,0 +1,67 @@ > +/* > + * (C) Copyright 2002 > + * Richard Jones, [email protected] > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +/* > + * Boot support > + */ > +#include <common.h> > +#include <blk.h> > +#include <command.h> > +#include <s_record.h> > +#include <net.h> > +#include <ata.h> > +#include <asm/io.h> > +#include <mapmem.h> > +#include <part.h> > +#include <fs.h> > +#include <ffs.h> > + > +int do_ffs_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + return do_size(cmdtp, flag, argc, argv, FS_TYPE_FFS); > +} > + > +U_BOOT_CMD( > + ffssize, 4, 0, do_ffs_size, > + "determine a file's size", > + "<interface> <dev[:part]> <filename>\n" > + " - Find file 'filename' from 'dev' on 'interface'\n" > + " and determine its size." > +); > + > +int do_ffs_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + return do_load(cmdtp, flag, argc, argv, FS_TYPE_FFS); > +} > + > + > +U_BOOT_CMD( > + ffsload, 7, 0, do_ffs_fsload, > + "load binary file from a ufs filesystem", > + "<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n" > + " - Load binary file 'filename' from 'dev' on 'interface'\n" > + " to address 'addr' from ffs filesystem.\n" > + " 'pos' gives the file position to start loading from.\n" > + " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n" > + " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n" > + " the load stops on end of file.\n" > + " If either 'pos' or 'bytes' are not aligned to\n" > + " ARCH_DMA_MINALIGN then a misaligned buffer warning will\n" > + " be printed and performance will suffer for the load." > +); > + > +static int do_ffs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const > argv[]) > +{ > + return do_ls(cmdtp, flag, argc, argv, FS_TYPE_FFS); > +} > + > +U_BOOT_CMD( > + ffsls, 4, 1, do_ffs_ls, > + "list files in a directory (default /)", > + "<interface> [<dev[:part]>] [directory]\n" > + " - list files from 'dev' on 'interface' in a 'directory'" > +); > diff --git a/fs/Makefile b/fs/Makefile > index 51d06fc..7e53006 100644 > --- a/fs/Makefile > +++ b/fs/Makefile > @@ -16,6 +16,7 @@ obj-$(CONFIG_CMD_CBFS) += cbfs/ > obj-$(CONFIG_CMD_CRAMFS) += cramfs/ > obj-$(CONFIG_FS_EXT4) += ext4/ > obj-y += fat/ > +obj-$(CONFIG_CMD_FFS) += ffs/ > obj-$(CONFIG_CMD_JFFS2) += jffs2/ > obj-$(CONFIG_CMD_REISER) += reiserfs/ > obj-$(CONFIG_SANDBOX) += sandbox/ > diff --git a/fs/ffs/Makefile b/fs/ffs/Makefile > new file mode 100644 > index 0000000..ff1e371 > --- /dev/null > +++ b/fs/ffs/Makefile > @@ -0,0 +1 @@ > +obj-y := ufs.o > diff --git a/fs/ffs/dinode.h b/fs/ffs/dinode.h > new file mode 100644 > index 0000000..5ad69be > --- /dev/null > +++ b/fs/ffs/dinode.h > @@ -0,0 +1,156 @@ > +/* $OpenBSD: dinode.h,v 1.18 2013/05/30 19:19:09 guenther Exp $ */ > +/* $NetBSD: dinode.h,v 1.7 1995/06/15 23:22:48 cgd 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.9 (Berkeley) 3/29/95 > + */ > + > +#ifndef _UFS_DINODE_H_ > +#define _UFS_DINODE_H_ > + > +/* > + * UFS directories use 32bit inode numbers internally, regardless > + * of what the system on top of it uses. > + */ > +typedef u_int32_t ufsino_t; > + > +/* > + * 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 ((ufsino_t)2) > + > +/* > + * 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 /* External addresses in inode > */ > +#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). */ > + 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. */ > + int32_t di_spare[2]; /* 120: Reserved; currently unused */ > +}; > + > +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. */ > + int64_t di_spare[3]; /* 232: 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 di_shortlink di_db > + > +#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t)) > +#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t)) > + > +#define MAXSYMLINKLEN(ip) \ > + ((ip)->i_ump->um_fstype == UM_UFS1) ? \ > + MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2 > + > +/* File permissions. */ > +#define IEXEC 0000100 /* Executable. */ > +#define IWRITE 0000200 /* Writeable. */ > +#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 /* _UFS_DINODE_H_ */ > diff --git a/fs/ffs/dir.h b/fs/ffs/dir.h > new file mode 100644 > index 0000000..64ddb02 > --- /dev/null > +++ b/fs/ffs/dir.h > @@ -0,0 +1,156 @@ > +/* $OpenBSD: dir.h,v 1.11 2009/01/31 21:21:45 grange Exp $ */ > +/* $NetBSD: dir.h,v 1.8 1996/03/09 19:42:41 scottr 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 > + */ > + > +#ifndef _DIR_H_ > +#define _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 > + * with null bytes. All names are guaranteed null terminated. > + * The maximum length of a name in a directory is 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. > + */ > +#define DIRBLKSIZ DEV_BSIZE > +#define MAXNAMLEN 255 > + > +struct direct { > + u_int32_t d_ino; /* 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[MAXNAMLEN + 1];/* name with length <= 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 > + > +/* > + * 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) \ > + ((offsetof(struct direct, d_name) + \ > + ((namlen)+1)*sizeof(((struct direct *)0)->d_name[0]) + 3) & ~3) > +#if (BYTE_ORDER == LITTLE_ENDIAN) > +#define DIRSIZ(oldfmt, dp) \ > + ((oldfmt) ? \ > + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_type+1 + 3) &~ 3)) > : \ > + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ > 3))) > +#else > +#define DIRSIZ(oldfmt, dp) \ > + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) > +#endif > +#define OLDDIRFMT 1 > +#define NEWDIRFMT 0 > + > +/* > + * Template for manipulating directories. Should use struct direct's, > + * but the name field is 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 /* !_DIR_H_ */ > diff --git a/fs/ffs/fs.h b/fs/ffs/fs.h > new file mode 100644 > index 0000000..43c5c8a > --- /dev/null > +++ b/fs/ffs/fs.h > @@ -0,0 +1,592 @@ > +/* $OpenBSD: fs.h,v 1.41 2015/01/20 18:08:16 deraadt Exp $ */ > +/* $NetBSD: fs.h,v 1.6 1995/04/12 21:21:02 mycroft 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 > + */ > + > +/* > + * 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. > + * > + * 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 8192 > +#define SBSIZE 8192 > +#define BBOFF ((off_t)(0)) > +#define SBOFF ((off_t)(BBOFF + BBSIZE)) > +#define BBLOCK ((daddr_t)(0)) > +#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) > +#define SBLOCK_UFS1 8192 > +#define SBLOCK_UFS2 65536 > +#define SBLOCK_PIGGY 262144 > +#define SBLOCKSIZE 8192 > +#define SBLOCKSEARCH \ > + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_PIGGY, -1 } > + > +/* > + * 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 > + * addressible; 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. > + */ > + > +#define MAXFRAG 8 > + > +/* > + * 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 file system is kept in fs_volname. > + * MAXVOLLEN defines the length of the buffer allocated. > + */ > +#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 three > + * 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, > + * and the third points to an array that tracks the creation of new > + * directories. > + */ > +#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 > + > +/* > + * 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. With 5% free space, > + * fragmentation is not a problem, so we choose to optimize for time. > + */ > +#define MINFREE 5 > +#define DEFAULTOPT FS_OPTTIME > + > +/* > + * The directory preference algorithm(dirpref) 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 */ > + > +/* > + * Size of superblock space reserved for snapshots. > + */ > +#define FSMAXSNAP 20 > + > +/* > + * 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. > + */ > +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 / frags */ > + int32_t fs_cblkno; /* offset of cyl-block / frags */ > + int32_t fs_iblkno; /* offset of inode-blocks / frags */ > + int32_t fs_dblkno; /* offset of first data / frags */ > + int32_t fs_cgoffset; /* cylinder group offset in cylinder */ > + int32_t fs_cgmask; /* used to calc mod fs_ntrak */ > + int32_t fs_ffs1_time; /* last time written */ > + int32_t fs_ffs1_size; /* # of blocks in fs / frags */ > + int32_t fs_ffs1_dsize; /* # of data blocks in fs */ > + int32_t fs_ncg; /* # of cylinder groups */ > + int32_t fs_bsize; /* size of basic blocks / bytes */ > + int32_t fs_fsize; /* size of frag blocks / bytes */ > + int32_t fs_frag; /* # of frags in a block in fs */ > +/* these are configuration parameters */ > + int32_t fs_minfree; /* minimum percentage of free blocks */ > + int32_t fs_rotdelay; /* # of ms for optimal next block */ > + int32_t fs_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 # of frags */ > +/* these are configuration parameters */ > + int32_t fs_maxcontig; /* max # of contiguous blks */ > + int32_t fs_maxbpg; /* max # 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_csmask; /* csum block offset (now unused) */ > + int32_t fs_csshift; /* csum block number (now unused) */ > + int32_t fs_nindir; /* value of NINDIR */ > + int32_t fs_inopb; /* inodes per file system block */ > + int32_t fs_nspf; /* DEV_BSIZE sectors per frag */ > +/* yet another configuration parameter */ > + int32_t fs_optim; /* optimization preference, see below */ > +/* these fields are derived from the hardware */ > + int32_t fs_npsect; /* DEV_BSIZE sectors/track + spares */ > + int32_t fs_interleave; /* DEV_BSIZE sector interleave */ > + int32_t fs_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 filesystem id */ > +/* sizes determined by number of cylinder groups and their sizes */ > + int32_t fs_ffs1_csaddr; /* blk addr of cyl grp summary area */ > + int32_t fs_cssize; /* cyl grp summary area size / bytes */ > + int32_t fs_cgsize; /* cyl grp block size / bytes */ > +/* these fields are derived from the hardware */ > + int32_t fs_ntrak; /* tracks per cylinder */ > + int32_t fs_nsect; /* DEV_BSIZE sectors per track */ > + int32_t fs_spc; /* DEV_BSIZE sectors per cylinder */ > +/* this comes from the disk driver partitioning */ > + int32_t fs_ncyl; /* cylinders in file system */ > +/* these fields can be computed from the others */ > + int32_t fs_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_ffs1_cstotal; /* cylinder summary information */ > +/* these fields are cleared at mount time */ > + int8_t fs_fmod; /* super block modified flag */ > + int8_t fs_clean; /* file system is clean flag */ > + int8_t fs_ronly; /* mounted read-only flag */ > + int8_t fs_ffs1_flags; /* see FS_ below */ > + u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ > + u_char fs_volname[MAXVOLLEN]; /* volume name */ > + u_int64_t fs_swuid; /* system-wide uid */ > + int32_t fs_pad; /* due to alignment of fs_swuid */ > +/* these fields retain the current block allocation info */ > + int32_t fs_cgrotor; /* last cg searched */ > + 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; /* reserved for snapshots */ > + int32_t fs_cpc; /* cyl per cycle in postbl */ > +/* this area is only allocated if fs_ffs1_flags & FS_FLAGS_UPDATED */ > + int32_t fs_maxbsize; /* maximum blocking factor permitted */ > + int64_t fs_spareconf64[17]; /* old rotation block list head */ > + int64_t fs_sblockloc; /* offset of standard super block */ > + struct csum_total fs_cstotal; /* cylinder summary information */ > + int64_t fs_time; /* time last 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];/* space reserved for snapshots */ > +/* 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_sparecon[26]; /* reserved for future constants */ > + u_int32_t fs_flags; /* see FS_ flags below */ > + int32_t fs_fscktime; /* last time fsck(8)ed */ > + int32_t fs_contigsumsize; /* size of cluster summary array */ > + int32_t fs_maxsymlinklen; /* max length of an internal symlink */ > + int32_t fs_inodefmt; /* format of on-disk inodes */ > + u_int64_t fs_maxfilesize; /* maximum representable file size */ > + int64_t fs_qbmask; /* ~fs_bmask - for use with quad size */ > + int64_t fs_qfmask; /* ~fs_fmask - for use with quad size */ > + int32_t fs_state; /* validate fs_clean field */ > + int32_t fs_postblformat; /* format of positional layout tables */ > + int32_t fs_nrpos; /* number of rotational positions */ > + int32_t fs_postbloff; /* (u_int16) rotation block list head */ > + int32_t fs_rotbloff; /* (u_int8) blocks for each rotation */ > + int32_t fs_magic; /* magic number */ > + u_int8_t fs_space[1]; /* list of blocks for each rotation */ > +/* actually longer */ > +}; > + > +/* > + * Filesystem identification > + */ > +#define FS_MAGIC 0x011954 /* the fast filesystem magic > number */ > +#define FS_UFS1_MAGIC 0x011954 /* the fast filesystem magic > number */ > +#define FS_UFS2_MAGIC 0x19540119 /* UFS fast filesystem magic > number */ > +#define FS_OKAY 0x7c269d38 /* superblock checksum */ > +#define FS_42INODEFMT -1 /* 4.2BSD inode format */ > +#define FS_44INODEFMT 2 /* 4.4BSD inode format */ > + > +/* > + * Filesystem 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 */ > + > +/* > + * Filesystem flags. > + */ > +#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ > +#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ > +/* > + * The following flag is used to detect a FFS1 file system that had its flags > + * moved to the new (FFS2) location for compatibility. > + */ > +#define FS_FLAGS_UPDATED 0x80 /* file system has FFS2-like flags */ > + > +/* > + * Rotational layout table format types > + */ > +#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table > format */ > +#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ > +/* > + * Macros for access to superblock array structures > + */ > +#define fs_rotbl(fs) \ > + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ > + ? ((fs)->fs_space) \ > + : ((u_int8_t *)((u_int8_t *)(fs) + (fs)->fs_rotbloff))) > + > +/* > + * 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(fs) \ > + /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ > + /* blktot size */ (fs)->fs_cpg * sizeof(int32_t) + \ > + /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16_t) + \ > + /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ > + /* block map */ howmany((fs)->fs_fpg, NBBY) + \ > + /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ > + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ > + /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) > + > +/* > + * 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_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[MAXFRAG]; /* counts of available frags */ > + int32_t cg_btotoff; /* (int32) block totals per cylinder */ > + int32_t cg_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_ffs2_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_ffs2_time; /* time last written */ > + int64_t cg_sparecon64[3]; /* reserved for future use */ > +/* actually longer */ > +}; > + > +/* > + * Macros for access to cylinder group array structures > + */ > +#define cg_blktot(cgp) \ > + (((cgp)->cg_magic != CG_MAGIC) \ > + ? (((struct ocg *)(cgp))->cg_btot) \ > + : ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_btotoff))) > +#define cg_blks(fs, cgp, cylno) \ > + (((cgp)->cg_magic != CG_MAGIC) \ > + ? (((struct ocg *)(cgp))->cg_b[cylno]) \ > + : ((int16_t *)((u_int8_t *)(cgp) + \ > + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) > +#define cg_inosused(cgp) \ > + (((cgp)->cg_magic != CG_MAGIC) \ > + ? (((struct ocg *)(cgp))->cg_iused) \ > + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff))) > +#define cg_blksfree(cgp) \ > + (((cgp)->cg_magic != CG_MAGIC) \ > + ? (((struct ocg *)(cgp))->cg_free) \ > + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff))) > +#define cg_chkmagic(cgp) \ > + ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == > CG_MAGIC) > +#define cg_clustersfree(cgp) \ > + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) > +#define cg_clustersum(cgp) \ > + ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_clustersumoff)) > + > +/* > + * 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 */ > +}; > + > +/* > + * Turn file system block numbers into disk block addresses. > + * This maps file system blocks to DEV_BSIZE (a.k.a. 512-byte) size disk > + * blocks. > + */ > +#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb) > +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) > + > +/* > + * 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 cgdata(fs, c) (cgdmin(fs, c) + (fs)->fs_minfree) /* data > zone */ > +#define cgmeta(fs, c) (cgdmin(fs, c)) /* meta > data */ > +#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 */ > +#define cgstart(fs, c) > \ > + (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) > + > +/* > + * 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 frag block number in cylinder group 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 cbtocylno(fs, bno) \ > + (fsbtodb(fs, bno) / (fs)->fs_spc) > +#define cbtorpos(fs, bno) \ > + ((fs)->fs_nrpos <= 1 ? 0 : \ > + (fsbtodb(fs, bno) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew > + \ > + fsbtodb(fs, bno) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) > % \ > + (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_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 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 - ((fs)->fs_dsize * (percentreserved) / 100)) > + > +/* > + * Determining the size of a file block in the file system. > + */ > +#define blksize(fs, ip, lbn) \ > + (((lbn) >= NDADDR || DIP((ip), size) >= ((lbn) + 1) << (fs)->fs_bshift) > \ > + ? (fs)->fs_bsize \ > + : (fragroundup(fs, blkoff(fs, DIP((ip), size))))) > +#define dblksize(fs, dip, lbn) \ > + (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \ > + ? (fs)->fs_bsize \ > + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) > + > +#define sblksize(fs, size, lbn) \ > + (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ > + ? (fs)->fs_bsize \ > + : (fragroundup(fs, blkoff(fs, (size))))) > + > + > +/* > + * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte > + * sector size. > + */ > +#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) > +#define NSPF(fs) ((fs)->fs_nspf) > + > +/* Number of inodes per file system block (fs->fs_bsize) */ > +#define INOPB(fs) ((fs)->fs_inopb) > +/* Number of inodes per file system fragment (fs->fs_fsize) */ > +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) > + > +/* > + * Number of indirects in a file system block. > + */ > +#define NINDIR(fs) ((fs)->fs_nindir) > + > +/* Maximum file size the kernel allows. > + * Even though ffs can handle files up to 16TB, we do limit the max file > + * to 2^31 pages to prevent overflow of a 32-bit unsigned int. The buffer > + * cache has its own checks but a little added paranoia never hurts. > + */ > +#define FS_KERNMAXFILESIZE(pgsiz, fs) ((u_int64_t)0x80000000 * \ > + MIN((pgsiz), (fs)->fs_bsize) - 1) > + > +extern const int inside[], around[]; > +extern const u_char *fragtbl[]; > diff --git a/fs/ffs/stat.h b/fs/ffs/stat.h > new file mode 100644 > index 0000000..bce381e > --- /dev/null > +++ b/fs/ffs/stat.h > @@ -0,0 +1,133 @@ > +/* $OpenBSD: stat.h,v 1.28 2015/04/04 18:06:08 jca Exp $ */ > +/* $NetBSD: stat.h,v 1.20 1996/05/16 22:17:49 cgd 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. > + * > + * @(#)stat.h 8.9 (Berkeley) 8/17/94 > + */ > + > +#ifndef _SYS_STAT_H_ > +#define _SYS_STAT_H_ > + > +struct stat { > + mode_t st_mode; /* inode protection mode */ > + dev_t st_dev; /* inode's device */ > + ino_t st_ino; /* inode's number */ > + nlink_t st_nlink; /* number of hard links */ > + uid_t st_uid; /* user ID of the file's owner */ > + gid_t st_gid; /* group ID of the file's group */ > + dev_t st_rdev; /* device type */ > + time_t st_atime; /* time of last access */ > + long st_atimensec; /* nsec of last access */ > + time_t st_mtime; /* time of last data modification */ > + long st_mtimensec; /* nsec of last data modification */ > + time_t st_ctime; /* time of last file status change */ > + long st_ctimensec; /* nsec of last file status change */ > + off_t st_size; /* file size, in bytes */ > + blkcnt_t st_blocks; /* blocks allocated for file */ > + blksize_t st_blksize; /* optimal blocksize for I/O */ > + u_int32_t st_flags; /* user defined flags for file */ > + u_int32_t st_gen; /* file generation number */ > + time_t __st_birthtime; /* time of file creation */ > + long __st_birthtimensec; /* nsec of file creation */ > +}; > + > +#define S_ISUID 0004000 /* set user id on execution */ > +#define S_ISGID 0002000 /* set group id on execution */ > +#define S_ISTXT 0001000 /* sticky bit */ > + > +#define S_IRWXU 0000700 /* RWX mask for owner */ > +#define S_IRUSR 0000400 /* R for owner */ > +#define S_IWUSR 0000200 /* W for owner */ > +#define S_IXUSR 0000100 /* X for owner */ > + > +#define S_IREAD S_IRUSR > +#define S_IWRITE S_IWUSR > +#define S_IEXEC S_IXUSR > + > +#define S_IRWXG 0000070 /* RWX mask for group */ > +#define S_IRGRP 0000040 /* R for group */ > +#define S_IWGRP 0000020 /* W for group */ > +#define S_IXGRP 0000010 /* X for group */ > + > +#define S_IRWXO 0000007 /* RWX mask for other */ > +#define S_IROTH 0000004 /* R for other */ > +#define S_IWOTH 0000002 /* W for other */ > +#define S_IXOTH 0000001 /* X for other */ > + > +#define S_IFMT 0170000 /* type of file mask */ > +#define S_IFIFO 0010000 /* named pipe (fifo) */ > +#define S_IFCHR 0020000 /* character special */ > +#define S_IFDIR 0040000 /* directory */ > +#define S_IFBLK 0060000 /* block special */ > +#define S_IFREG 0100000 /* regular */ > +#define S_IFLNK 0120000 /* symbolic link */ > +#define S_IFSOCK 0140000 /* socket */ > +#define S_ISVTX 0001000 /* save swapped text even after > use */ > + > +#define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */ > +#define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special > */ > +#define S_ISBLK(m) ((m & 0170000) == 0060000) /* block > special */ > +#define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file > */ > +#define S_ISFIFO(m) ((m & 0170000) == 0010000) /* fifo */ > +#define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic > link */ > +#define S_ISSOCK(m) ((m & 0170000) == 0140000) /* socket */ > + > +#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) /* 00777 */ > + /* 07777 */ > +#define ALLPERMS > (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) > + /* 00666 */ > +#define DEFFILEMODE > (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) > + > +#define S_BLKSIZE 512 /* block size used in the stat > struct */ > + > +/* > + * Definitions of flags stored in file flags word. > + * > + * Super-user and owner changeable flags. > + */ > +#define UF_SETTABLE 0x0000ffff /* mask of owner changeable > flags */ > +#define UF_NODUMP 0x00000001 /* do not dump file */ > +#define UF_IMMUTABLE 0x00000002 /* file may not be changed */ > +#define UF_APPEND 0x00000004 /* writes to file may only > append */ > +#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. > union */ > +/* > + * Super-user changeable flags. > + */ > +#define SF_SETTABLE 0xffff0000 /* mask of superuser changeable > flags */ > +#define SF_ARCHIVED 0x00010000 /* file is archived */ > +#define SF_IMMUTABLE 0x00020000 /* file may not be changed */ > +#define SF_APPEND 0x00040000 /* writes to file may only > append */ > + > +#endif /* !_SYS_STAT_H_ */ > diff --git a/fs/ffs/ufs.c b/fs/ffs/ufs.c > new file mode 100644 > index 0000000..1bcd400 > --- /dev/null > +++ b/fs/ffs/ufs.c > @@ -0,0 +1,885 @@ > +/* $OpenBSD: ufs.c,v 1.25 2015/07/17 18:55:00 kspillner Exp $ */ > +/* $NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $ */ > + > +/*- > + * Copyright (c) 1993 > + * The Regents of the University of California. All rights reserved. > + * > + * This code is derived from software contributed to Berkeley by > + * The Mach Operating System project at Carnegie-Mellon University. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. Neither the name of the University nor the names of its contributors > + * may be used to endorse or promote products derived from this software > + * without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + * > + * > + * Copyright (c) 1990, 1991 Carnegie Mellon University > + * All Rights Reserved. > + * > + * Author: David Golub > + * > + * Permission to use, copy, modify and distribute this software and its > + * documentation is hereby granted, provided that both the copyright > + * notice and this permission notice appear in all copies of the > + * software, derivative works or modified versions, and any portions > + * thereof, and that both notices appear in supporting documentation. > + * > + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" > + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR > + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. > + * > + * Carnegie Mellon requests users of this software to return to > + * > + * Software Distribution Coordinator or [email protected] > + * School of Computer Science > + * Carnegie Mellon University > + * Pittsburgh PA 15213-3890 > + * > + * any improvements or extensions that they make and grant Carnegie the > + * rights to redistribute these changes. > + */ > + > +/* > + * Stand-alone file reading package. > + */ > +#include <common.h> > +#include <blk.h> > +#include <config.h> > +#include <exports.h> > +#include <asm/byteorder.h> > +#include <part.h> > +#include <malloc.h> > +#include <memalign.h> > +#include <linux/compiler.h> > +#include <linux/ctype.h> > + > +typedef int32_t daddr32_t; /* 32-bit disk address */ > +typedef int64_t blkcnt_t; > +typedef int32_t blksize_t; > + > +#include "dinode.h" > +#include "stat.h" > +#include "dir.h" > +#include "fs.h" > + > +#define MAXPATHLEN 1024 > +#define DEV_BSIZE (1 << 9) > +#define MAXBSIZE (64 * 1024) > +#define MAXNAMLEN 255 > +#define MAXSYMLINKS 32 > +#define SOPEN_MAX 16 > + > +#define SEEK_SET 0 /* set file offset to offset */ > +#define SEEK_CUR 1 /* set file offset to current plus > offset */ > +#define SEEK_END 2 /* set file offset to EOF plus offset */ > +/* > + * In-core open file. > + */ > +struct file { > + off_t f_seekp; /* seek pointer */ > + struct fs *f_fs; /* pointer to super-block */ > + struct ufs1_dinode f_di; /* copy of on-disk inode */ > + int f_nindir[NIADDR]; > + /* number of blocks mapped by > + indirect block at level i */ > + char *f_blk[NIADDR]; /* buffer for indirect block at > + level i */ > + size_t f_blksize[NIADDR]; > + /* size of buffer */ > + daddr32_t f_blkno[NIADDR];/* disk address of block in buffer */ > + char *f_buf; /* buffer for data block */ > + size_t f_buf_size; /* size of data block */ > + daddr32_t f_buf_blkno; /* block number of data block */ > +}; > + > +int _ufs_open(const char *); > +void _ufs_close(int); > +int _ufs_read(int, void *, size_t, size_t *); > +off_t _ufs_seek(int, off_t, int); > +void _ufs_stat(int, struct stat *); > +int _ufs_readdir(int, char *); > +int dread(uint32_t, uint32_t, void *, uint32_t *); > + > +static int read_inode(ufsino_t, struct file *); > +static int block_map(struct file *, daddr32_t, daddr32_t *); > +static int buf_read_file(struct file *, char **, size_t *); > +static int search_directory(char *, struct file *, ufsino_t *); > +static void ufs_close_internal(struct file *); > + > +struct file *files[SOPEN_MAX]; > + > +struct blk_desc *cur_dev; > +disk_partition_t *cur_pi; > + > +/* > + * Read a new inode into a file structure. > + */ > +static int > +read_inode(ufsino_t inumber, struct file *fp) > +{ > + struct fs *fs = fp->f_fs; > + char *buf; > + size_t rsize; > + int rc; > + > + /* > + * Read inode and save it. > + */ > + buf = malloc_cache_aligned(fs->fs_bsize); > + rc = dread(fsbtodb(fs, (daddr32_t)ino_to_fsba(fs, inumber)), > + fs->fs_bsize, buf, &rsize); > + if (rc) > + goto out; > + if (rsize != (size_t)fs->fs_bsize) { > + rc = EIO; > + goto out; > + } > + > + { > + struct ufs1_dinode *dp; > + > + dp = (struct ufs1_dinode *)buf; > + fp->f_di = dp[ino_to_fsbo(fs, inumber)]; > + } > + > + /* > + * Clear out the old buffers > + */ > + { > + int level; > + > + for (level = 0; level < NIADDR; level++) > + fp->f_blkno[level] = -1; > + fp->f_buf_blkno = -1; > + fp->f_seekp = 0; > + } > +out: > + free(buf); > + return rc; > +} > + > +/* > + * Given an offset in a file, find the disk block number that > + * contains that block. > + */ > +static int > +block_map(struct file *fp, daddr32_t file_block, daddr32_t *disk_block_p) > +{ > + daddr32_t ind_block_num, *ind_p; > + struct fs *fs = fp->f_fs; > + int level, idx, rc; > + > + /* > + * Index structure of an inode: > + * > + * di_db[0..NDADDR-1] hold block numbers for blocks > + * 0..NDADDR-1 > + * > + * di_ib[0] index block 0 is the single indirect block > + * holds block numbers for blocks > + * NDADDR .. NDADDR + NINDIR(fs)-1 > + * > + * di_ib[1] index block 1 is the double indirect block > + * holds block numbers for INDEX blocks for blocks > + * NDADDR + NINDIR(fs) .. > + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 > + * > + * di_ib[2] index block 2 is the triple indirect block > + * holds block numbers for double-indirect > + * blocks for blocks > + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. > + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 > + * + NINDIR(fs)**3 - 1 > + */ > + > + if (file_block < NDADDR) { > + /* Direct block. */ > + *disk_block_p = fp->f_di.di_db[file_block]; > + return 0; > + } > + > + file_block -= NDADDR; > + > + /* > + * nindir[0] = NINDIR > + * nindir[1] = NINDIR**2 > + * nindir[2] = NINDIR**3 > + * etc > + */ > + for (level = 0; level < NIADDR; level++) { > + if (file_block < fp->f_nindir[level]) > + break; > + file_block -= fp->f_nindir[level]; > + } > + if (level == NIADDR) { > + /* Block number too high */ > + return EFBIG; > + } > + > + ind_block_num = fp->f_di.di_ib[level]; > + > + for (; level >= 0; level--) { > + if (ind_block_num == 0) { > + *disk_block_p = 0; /* missing */ > + return 0; > + } > + > + if (fp->f_blkno[level] != ind_block_num) { > + if (fp->f_blk[level] == NULL) > + fp->f_blk[level] = > + malloc_cache_aligned(fs->fs_bsize); > + rc = dread(fsbtodb(fp->f_fs, ind_block_num), > + fs->fs_bsize, fp->f_blk[level], > + &fp->f_blksize[level]); > + if (rc) > + return rc; > + if (fp->f_blksize[level] != (size_t)fs->fs_bsize) > + return EIO; > + fp->f_blkno[level] = ind_block_num; > + } > + > + ind_p = (daddr32_t *)fp->f_blk[level]; > + > + if (level > 0) { > + idx = file_block / fp->f_nindir[level - 1]; > + file_block %= fp->f_nindir[level - 1]; > + } else > + idx = file_block; > + > + ind_block_num = ind_p[idx]; > + } > + > + *disk_block_p = ind_block_num; > + return 0; > +} > + > +/* > + * Read a portion of a file into an internal buffer. Return > + * the location in the buffer and the amount in the buffer. > + */ > +static int > +buf_read_file(struct file *fp, char **buf_p, size_t *size_p) > +{ > + struct fs *fs = fp->f_fs; > + daddr32_t file_block, disk_block; > + size_t block_size; > + long off; > + int rc; > + > + off = blkoff(fs, fp->f_seekp); > + file_block = lblkno(fs, fp->f_seekp); > + block_size = dblksize(fs, &fp->f_di, file_block); > + > + if (file_block != fp->f_buf_blkno) { > + rc = block_map(fp, file_block, &disk_block); > + if (rc) > + return rc; > + > + if (fp->f_buf == NULL) > + fp->f_buf = malloc_cache_aligned(fs->fs_bsize); > + > + if (disk_block == 0) { > + memset(fp->f_buf, 0, block_size); > + fp->f_buf_size = block_size; > + } else { > + rc = dread(fsbtodb(fs, disk_block), > + block_size, fp->f_buf, &fp->f_buf_size); > + if (rc) > + return rc; > + } > + > + fp->f_buf_blkno = file_block; > + } > + > + /* > + * Return address of byte in buffer corresponding to > + * offset, and size of remainder of buffer after that > + * byte. > + */ > + *buf_p = fp->f_buf + off; > + *size_p = block_size - off; > + > + /* > + * But truncate buffer at end of file. > + */ > + if (*size_p > fp->f_di.di_size - fp->f_seekp) > + *size_p = fp->f_di.di_size - fp->f_seekp; > + > + return 0; > +} > + > +/* > + * Search a directory for a name and return its > + * i_number. > + */ > +static int > +search_directory(char *name, struct file *fp, ufsino_t *inumber_p) > +{ > + int namlen, length, rc; > + struct direct *dp, *edp; > + size_t buf_size; > + char *buf; > + > + length = strlen(name); > + > + fp->f_seekp = 0; > + while (fp->f_seekp < fp->f_di.di_size) { > + rc = buf_read_file(fp, &buf, &buf_size); > + if (rc) > + return rc; > + > + dp = (struct direct *)buf; > + edp = (struct direct *)(buf + buf_size); > + while (dp < edp) { > + if (dp->d_ino == 0) > + goto next; > + if (fp->f_fs->fs_maxsymlinklen <= 0) > + namlen = dp->d_type; > + else > + namlen = dp->d_namlen; > + if (namlen == length && > + !strcmp(name, dp->d_name)) { > + /* found entry */ > + *inumber_p = dp->d_ino; > + return 0; > + } > + next: > + dp = (struct direct *)((char *)dp + dp->d_reclen); > + } > + fp->f_seekp += buf_size; > + } > + return ENOENT; > +} > + > +/* > + * Open a file. > + */ > +int > +_ufs_open(const char *path) > +{ > + char *cp, *ncp; > + ufsino_t inumber; > + int rc, c, fd; > + struct file *fp; > + size_t buf_size; > + struct fs *fs; > +#if 1 /* XXX symbolic links support */ > + char namebuf[MAXPATHLEN+1], *buf = NULL; > + ufsino_t parent_inumber; > + int nlinks = 0; > +#endif > + > + for (fd = 0; fd < SOPEN_MAX; fd++) > + if (files[fd] == NULL) > + goto gotfree; > + return -1; > +gotfree: > + > + /* allocate file system specific data structure */ > + fp = malloc_cache_aligned(sizeof(struct file)); > + memset(fp, 0, sizeof(struct file)); > + files[fd] = fp; > + > + /* allocate space and read super block */ > + fs = malloc_cache_aligned(SBSIZE); > + fp->f_fs = fs; > + rc = dread(SBLOCK, SBSIZE, (char *)fs, &buf_size); > + if (rc) > + goto out; > + > + if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || > + fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { > + rc = EINVAL; > + goto out; > + } > + > + /* > + * Calculate indirect block levels. > + */ > + { > + int mult; > + int level; > + > + mult = 1; > + for (level = 0; level < NIADDR; level++) { > + mult *= NINDIR(fs); > + fp->f_nindir[level] = mult; > + } > + } > + > + inumber = ROOTINO; > + if ((rc = read_inode(inumber, fp)) != 0) > + goto out; > + > + cp = (char *)path; > + while (*cp) { > + > + /* > + * Remove extra separators > + */ > + while (*cp == '/') > + cp++; > + if (*cp == '\0') > + break; > + > + /* > + * Check that current node is a directory. > + */ > + if ((fp->f_di.di_mode & IFMT) != IFDIR) { > + rc = ENOTDIR; > + printf("%s: cp \"%s\" != IFDIR\n", __func__, cp); > + goto out; > + } > + > + /* > + * Get next component of path name. > + */ > + { > + int len = 0; > + > + ncp = cp; > + while ((c = *cp) != '\0' && c != '/') { > + if (++len > MAXNAMLEN) { > + rc = ENOENT; > + goto out; > + } > + cp++; > + } > + *cp = '\0'; > + } > + > + /* > + * Look up component in current directory. > + * Save directory inumber in case we find a > + * symbolic link. > + */ > +#if 1 /* XXX symbolic links support */ > + parent_inumber = inumber; > +#endif > + rc = search_directory(ncp, fp, &inumber); > + *cp = c; > + if (rc) { > + printf("%s: search_directory() %d failed\n", __func__, > + inumber); > + goto out; > + } > + > + /* > + * Open next component. > + */ > + if ((rc = read_inode(inumber, fp)) != 0) { > + printf("%s: reading inode %d failed\n", __func__, > + inumber); > + goto out; > + } > + > +#if 1 /* XXX symbolic links support */ > + /* > + * Check for symbolic link. > + */ > + if ((fp->f_di.di_mode & IFMT) == IFLNK) { > + u_int64_t link_len = fp->f_di.di_size; > + size_t len; > + > + len = strlen(cp); > + > + if (link_len + len > MAXPATHLEN || > + ++nlinks > MAXSYMLINKS) { > + rc = ENOENT; > + goto out; > + } > + > + memcpy(&namebuf[link_len], cp, len + 1); > + > + if (link_len < fs->fs_maxsymlinklen) { > + memcpy(namebuf, fp->f_di.di_shortlink, > link_len); > + } else { > + /* > + * Read file for symbolic link > + */ > + size_t buf_size; > + daddr32_t disk_block; > + struct fs *fs = fp->f_fs; > + > + if (!buf) > + buf = > malloc_cache_aligned(fs->fs_bsize); > + rc = block_map(fp, (daddr32_t)0, &disk_block); > + if (rc) > + goto out; > + > + rc = dread(fsbtodb(fs, disk_block), > + fs->fs_bsize, buf, &buf_size); > + if (rc) > + goto out; > + > + memcpy(namebuf, buf, link_len); > + } > + > + /* > + * If relative pathname, restart at parent directory. > + * If absolute pathname, restart at root. > + */ > + cp = namebuf; > + if (*cp != '/') > + inumber = parent_inumber; > + else > + inumber = ROOTINO; > + > + if ((rc = read_inode(inumber, fp)) != 0) > + goto out; > + } > +#endif > + } > + > + /* > + * Found terminal component. > + */ > +out: > +#if 1 /* XXX symbolic links support */ > + if (buf) > + free(buf); > +#endif > + if (rc) { > + ufs_close_internal(fp); > + files[fd] = NULL; > + fd = -1; > + } > + return fd; > +} > + > +void > +_ufs_close(int fd) > +{ > + if (files[fd] != NULL) > + ufs_close_internal(files[fd]); > + files[fd] = NULL; > +} > + > +static void > +ufs_close_internal(struct file *fp) > +{ > + int level; > + for (level = 0; level < NIADDR; level++) { > + if (fp->f_blk[level]) > + free(fp->f_blk[level]); > + } > + if (fp->f_buf) > + free(fp->f_buf); > + free(fp->f_fs); > + free(fp); > +} > + > +/* > + * Copy a portion of a file into kernel memory. > + * Cross block boundaries when necessary. > + */ > +int > +_ufs_read(int fd, void *start, size_t size, size_t *resid) > +{ > + struct file *fp = files[fd]; > + char *buf, *addr = start; > + size_t csize, buf_size; > + int rc = 0; > + > + while (size != 0) { > + if (fp->f_seekp >= fp->f_di.di_size) > + break; > + > + rc = buf_read_file(fp, &buf, &buf_size); > + if (rc) > + break; > + > + csize = size; > + if (csize > buf_size) > + csize = buf_size; > + > + memcpy(addr, buf, csize); > + > + fp->f_seekp += csize; > + addr += csize; > + size -= csize; > + } > + if (resid) > + *resid = size; > + return rc; > +} > + > +off_t > +_ufs_seek(int fd, off_t offset, int where) > +{ > + struct file *fp = files[fd]; > + switch (where) { > + case SEEK_SET: > + fp->f_seekp = offset; > + break; > + case SEEK_CUR: > + fp->f_seekp += offset; > + break; > + case SEEK_END: > + fp->f_seekp = fp->f_di.di_size - offset; > + break; > + default: > + return -1; > + } > + return fp->f_seekp; > +} > + > +void > +_ufs_stat(int fd, struct stat *sb) > +{ > + struct file *fp = files[fd]; > + /* only important stuff */ > + sb->st_mode = fp->f_di.di_mode; > + sb->st_size = fp->f_di.di_size; > +} > + > +int > +_ufs_readdir(int fd, char *name) > +{ > + struct file *fp = files[fd]; > + struct direct *dp, *edp; > + size_t buf_size; > + int rc, namlen; > + char *buf; > + > + if (name == NULL) > + fp->f_seekp = 0; > + else { > + /* end of dir */ > + if (fp->f_seekp >= fp->f_di.di_size) { > + *name = '\0'; > + return -1; > + } > + > + do { > + if ((rc = buf_read_file(fp, &buf, &buf_size)) != 0) > + return rc; > + > + dp = (struct direct *)buf; > + edp = (struct direct *)(buf + buf_size); > + while (dp < edp && dp->d_ino == 0) > + dp = (struct direct *)((char *)dp + > dp->d_reclen); > + fp->f_seekp += buf_size - > + ((u_int8_t *)edp - (u_int8_t *)dp); > + } while (dp >= edp); > + > + if (fp->f_fs->fs_maxsymlinklen <= 0) > + namlen = dp->d_type; > + else > + namlen = dp->d_namlen; > + strncpy(name, dp->d_name, namlen + 1); > + > + fp->f_seekp += dp->d_reclen; > + } > + > + return 0; > +} > + > +/* _________________________________________________________________________ > */ > +int > +dread(uint32_t off, uint32_t bsize, void *buf, uint32_t *bread) > +{ > + u_long rv; > + uint32_t blks = bsize / cur_pi->blksz; > + > + if (!cur_dev) > + return -1; > + > + rv = blk_dread(cur_dev, cur_pi->start + off, blks, buf); > + if (rv != blks) > + return -1; > + if (bread) > + *bread = rv * cur_pi->blksz; > + return 0; > +} > +int > +ffs_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info) > +{ > + struct fs *fs; > + uint32_t br; > + cur_dev = dev_desc; > + cur_pi = info; > + int i; > + for (i = 0; i < SOPEN_MAX; i++) > + files[i] = NULL; > + > + /* allocate space and read super block */ > + fs = malloc_cache_aligned(SBSIZE); > + > + /* read super block */ > + if (dread(SBLOCK, SBSIZE, fs, &br) < 0) { > + printf("%s: failed to read super block\n", __func__); > + goto errout; > + } > + if (br != SBSIZE) { > + printf("%s: failed to read super block, bytesread %x\n", > + __func__, br); > + goto errout; > + } > + if (fs->fs_magic != FS_MAGIC) { > + printf("%s: failed to read super block, fs_magic %x\n", > + __func__, (u_int)fs->fs_magic); > + goto errout; > + } > + if (fs->fs_bsize > MAXBSIZE) { > + printf("%s: failed to read super block, fs_bsize %x >\n", > + __func__, (u_int)fs->fs_bsize); > + goto errout; > + } > + if (fs->fs_bsize < sizeof(struct fs)) { > + printf("%s: failed to read super block, fs_bsize %x <\n", > + __func__, (u_int)fs->fs_bsize); > + goto errout; > + } > + if (fs) > + free(fs); > + return 0; > +errout: > + if (fs) > + free(fs); > + cur_dev = NULL; > + cur_pi = NULL; > + return -1; > +} > + > +/* _________________________________________________________________________ > */ > +#define lsrwx(mode,s) \ > + putc((mode) & S_IROTH? 'r' : '-'); \ > + putc((mode) & S_IWOTH? 'w' : '-'); \ > + putc((mode) & S_IXOTH? *(s): (s)[1]); > + > +static void > +ls(char *name, struct stat *sb) > +{ > + putc("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]); > + lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-")); > + lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-")); > + lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT? "tT" : "x-")); > + > + printf ("\t%lu%s%s\n", (u_long)sb->st_size, > + (sb->st_size > 9999999) ? "\t" : "\t\t", name); > +} > +#undef lsrwx > + > +static int > +ffs_stat(const char *str, struct stat *sb) > +{ > + int fd; > + if ((fd = _ufs_open(str)) < 0) > + return -1; > + _ufs_stat(fd, sb); > + _ufs_close(fd); > + return 0; > +} > + > +int > +ffs_ls(const char *dir) > +{ > + struct stat sb; > + char *_dir = dir ? (char *)dir : "/."; > + char *p, *tp; > + int dlen; > + int fd; > + > + > + if ((dlen = strnlen(_dir, MAXPATHLEN)) >= MAXPATHLEN) > + return -1; > + if (ffs_stat(_dir, &sb) < 0) > + return -1; > + if (!S_ISDIR(sb.st_mode)) { > + ls(_dir, &sb); > + return -1; > + } > + > + if ((fd = _ufs_open(_dir)) < 0) > + return -1; > + tp = p = malloc(MAXPATHLEN+MAXNAMLEN); > + memset(p, 0, MAXPATHLEN+MAXNAMLEN); > + strncpy(p, _dir, dlen+1); > + p += dlen; > + *p++ = '/'; > + *p = '\0'; > + while (_ufs_readdir(fd, p) >= 0) { > + if (ffs_stat(tp, &sb) < 0) { > + printf("ffs_stat %s failed\n", tp); > + } else > + ls(p, &sb); > + } > + _ufs_close(fd); > + free(tp); > + return 0; > +} > + > +int > +ffs_read(char *fname, void *buf, loff_t offset, loff_t len, loff_t *actread) > +{ > + struct stat sb; > + size_t tsz, br; > + int fd, rv = 0; > + > + if ((fd = _ufs_open(fname)) < 0) > + return -1; > + if (offset > 0) > + _ufs_seek(fd, offset, SEEK_CUR); > + > + _ufs_stat(fd, &sb); > + if (len == 0 || len > sb.st_size) > + tsz = sb.st_size; > + else > + tsz = len; > + br = tsz; > + printf("reading %s\n", fname); > + if (_ufs_read(fd, buf, tsz, &br)) > + rv = -1; > + if (actread) > + *actread = tsz - br; > + > + _ufs_close(fd); > + return rv; > +} > + > +int > +ffs_exists(const char *fname) > +{ > + struct stat sb; > + if (ffs_stat(fname, &sb) < 0) > + return 0; > + return 1; > +} > + > +int > +ffs_size(const char *fname, loff_t *size) > +{ > + struct stat sb; > + if (ffs_stat(fname, &sb) < 0) > + return -1; > + printf("%s: %lubytes\n", __func__, sb.st_size); > + if (size) > + *size = (loff_t)sb.st_size; > + return 0; > +} > + > +void > +ffs_close(void) > +{ > +} > diff --git a/fs/fs.c b/fs/fs.c > index 595ff1f..0d84987 100644 > --- a/fs/fs.c > +++ b/fs/fs.c > @@ -17,6 +17,7 @@ > #include <asm/io.h> > #include <div64.h> > #include <linux/math64.h> > +#include <ffs.h> > > DECLARE_GLOBAL_DATA_PTR; > > @@ -163,6 +164,21 @@ static struct fstype_info fstypes[] = { > .uuid = fs_uuid_unsupported, > }, > #endif > +#ifdef CONFIG_CMD_FFS > + { > + .fstype = FS_TYPE_FFS, > + .name = "ffs", > + .null_dev_desc_ok = false, > + .probe = ffs_set_blk_dev, > + .close = ffs_close, > + .ls = ffs_ls, > + .exists = ffs_exists, > + .size = ffs_size, > + .read = ffs_read, > + .write = fs_write_unsupported, > + .uuid = fs_uuid_unsupported, > + }, > +#endif > { > .fstype = FS_TYPE_ANY, > .name = "unsupported", > diff --git a/include/ffs.h b/include/ffs.h > new file mode 100644 > index 0000000..2f086c3 > --- /dev/null > +++ b/include/ffs.h > @@ -0,0 +1,10 @@ > +/* XXX */ > +#ifndef _FFS_H_ > +#define _FFS_H_ > +int ffs_ls(const char *dir); > +int ffs_exists(const char *); > +void ffs_close(void); > +int ffs_set_blk_dev(struct blk_desc *, disk_partition_t *); > +int ffs_size(const char *, loff_t *); > +int ffs_read(const char *, void *, loff_t, loff_t, loff_t *); > +#endif /* !_FFS_H_ */ > diff --git a/include/fs.h b/include/fs.h > index 2f2aca8..d97077e 100644 > --- a/include/fs.h > +++ b/include/fs.h > @@ -13,6 +13,7 @@ > #define FS_TYPE_EXT 2 > #define FS_TYPE_SANDBOX 3 > #define FS_TYPE_UBIFS 4 > +#define FS_TYPE_FFS 5 > > /* > * Tell the fs layer which block device an partition to use for future > >
