On Mon, Jul 18, 2016 at 12:25:27PM +0200, Mark Kettenis wrote: > > 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.
Loading directly from ffs would still require a u-boot header with a soc specific load address as well. And it would need to understand disklabels. > > Ultimately this code should be contributed back upstream. We don't > really want to maintain large patches like this in the ports tree. Indeed, ideally we'd not have any patches in u-boot or dtbs at all. Look at all the pain FreeBSD seems to go through with CONFIG_API. > > 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 > > > > >
