Index: Makefile
===================================================================
--- Makefile (nonexistent)
+++ Makefile (revision 5)
@@ -0,0 +1,56 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/packages/a/genext2fs
+
+versions = 1.4.1
+
+tarballs = $(addsuffix .tar.gz, $(addprefix genext2fs-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/genext2fs-1.4.1-blocksize.patch
+patches += $(CURDIR)/patches/genext2fs-1.4.1-configure.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-1.4.1-blocksize-patch ; ./create.patch.sh ) ; \
+ ( cd create-1.4.1-configure-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: create-1.4.1-blocksize-patch/create.patch.sh
===================================================================
--- create-1.4.1-blocksize-patch/create.patch.sh (nonexistent)
+++ create-1.4.1-blocksize-patch/create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=1.4.1
+
+tar --files-from=file.list -xzvf ../genext2fs-$VERSION.tar.gz
+mv genext2fs-$VERSION genext2fs-$VERSION-orig
+
+cp -rf ./genext2fs-$VERSION-new ./genext2fs-$VERSION
+
+diff -b --unified -Nr genext2fs-$VERSION-orig genext2fs-$VERSION > genext2fs-$VERSION-blocksize.patch
+
+mv genext2fs-$VERSION-blocksize.patch ../patches
+
+rm -rf ./genext2fs-$VERSION
+rm -rf ./genext2fs-$VERSION-orig
Property changes on: create-1.4.1-blocksize-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-1.4.1-blocksize-patch/file.list
===================================================================
--- create-1.4.1-blocksize-patch/file.list (nonexistent)
+++ create-1.4.1-blocksize-patch/file.list (revision 5)
@@ -0,0 +1,5 @@
+genext2fs-1.4.1/genext2fs.8
+genext2fs-1.4.1/genext2fs.c
+genext2fs-1.4.1/test-gen.lib
+genext2fs-1.4.1/test-mount.sh
+genext2fs-1.4.1/test.sh
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.8
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.8 (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.8 (revision 5)
@@ -0,0 +1,178 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH GENEXT2FS 8 "October 11, 2015"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp <n> insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+genext2fs \- ext2 filesystem generator for embedded systems
+.SH SYNOPSIS
+.B genext2fs
+.RI "[ options ] [ output\-image ]"
+.SH DESCRIPTION
+\fBgenext2fs\fP generates an ext2 filesystem
+as a normal (non-root) user. It does not require you to mount
+the image file to copy files on it, nor does it require that
+you become the superuser to make device nodes.
+
+The filesystem image is created in the file \fIoutput-image\fP. If not
+specified, it is sent to stdout.
+
+By default, the maximum number of inodes in the filesystem is the minimum
+number required to accommodate the initial contents.
+In this way, a minimal filesystem (typically read-only) can be created with
+minimal free inodes.
+If required, free inodes can be added by passing the relevant options.
+The filesystem image size in blocks can be minimised by trial and error.
+.SH OPTIONS
+.TP
+.BI "\-x, \-\-starting\-image image"
+Use this image as a starting point.
+.TP
+.BI "\-d, \-\-root directory[:path]"
+Add the given directory and contents at a particular path (by default
+the root).
+.TP
+.BI "\-D, \-\-devtable spec\-file[:path]"
+Use \fBspec-file\fP to specify inodes to be added, at the given
+path (by default the root), including files, directories and
+special files like devices.
+If the specified files are already present in the image, their
+ownership and permission modes will be adjusted accordingly.
+Furthermore, you can use a single table entry to create many devices
+with a range of minor numbers (see examples below).
+All specified inodes receive the mtime of \fBspec-file\fP itself.
+.TP
+.BI "\-B, \-\-block\-size bytes"
+Size of the block (valid block sizes: 1024, 20148 or 4096 bytes).
+.TP
+.BI "\-b, \-\-size\-in\-blocks blocks"
+Size of the image in blocks.
+.TP
+.BI "\-N, \-\-number\-of\-inodes inodes"
+Maximum number of inodes.
+.TP
+.BI "\-i, \-\-bytes\-per\-inode ratio"
+Used to calculate the maximum number of inodes from the available blocks.
+.TP
+.BI "\-m, \-\-reserved\-percentage"
+Number of reserved blocks as a percentage of size. Reserving 0 blocks will prevent creation of the "lost+found" directory.
+.TP
+.BI "\-o, \-\-creator\-os OS"
+The default value for Creator OS ('linux', 'hurd', 'freebsd' or a numerical value: 0, 1, 3).
+.TP
+.BI "\-g, \-\-block\-map path"
+Generate a block map file for this path.
+.TP
+.BI "\-e, \-\-fill\-value value"
+Fill unallocated blocks with value.
+.TP
+.BI "\-z, \-\-allow\-holes"
+Make files with holes.
+.TP
+.BI "\-f, \-\-faketime"
+Use a timestamp of 0 for inode and filesystem creation, instead of the present. Useful for testing.
+.TP
+.BI "\-q, \-\-squash"
+Squash permissions and owners (same as -P -U).
+.TP
+.BI "\-U, \-\-squash\-uids"
+Squash ownership of inodes added using the -d option, making them all
+owned by root:root.
+.TP
+.BI "\-P, \-\-squash\-perms"
+Squash permissions of inodes added using the -d option. Analogous to
+"umask 077".
+.TP
+.BI "\-v, \-\-verbose"
+Print resulting filesystem structure.
+.TP
+.BI "\-V, \-\-version"
+Print genext2fs version.
+.TP
+.BI "\-h, \-\-help"
+Display help.
+.SH EXAMPLES
+
+.EX
+.B
+genext2fs -b 1440 -d src /dev/fd0
+.EE
+
+All files in the
+.I src
+directory will be written to
+.B /dev/fd0
+as a new ext2 filesystem image. You can then mount the floppy as
+usual.
+
+.EX
+.B
+genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
+.EE
+
+This example builds a filesystem from all the files in
+.I src,
+then device nodes are created based on the contents of the file
+.I device_table.txt.
+Entries in the device table take the form of:
+
+<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+
+where name is the file name and type can be one of:
+.RS
+.nf
+f A regular file
+d Directory
+c Character special device file
+b Block special device file
+p Fifo (named pipe)
+.fi
+.RE
+uid is the user id for the target file, gid is the group id for the
+target file. The rest of the entries (major, minor, etc) apply only
+to device special files.
+
+An example device file follows:
+
+.RS
+.nf
+# name type mode uid gid major minor start inc count
+
+/dev d 755 0 0 - - - - -
+/dev/mem c 640 0 0 1 1 0 0 -
+/dev/tty c 666 0 0 5 0 0 0 -
+/dev/tty c 666 0 0 4 0 0 1 6
+/dev/loop b 640 0 0 7 0 0 1 2
+/dev/hda b 640 0 0 3 0 0 0 -
+/dev/hda b 640 0 0 3 1 1 1 16
+/dev/log s 666 0 0 - - - - -
+.fi
+.RE
+
+This device table creates the /dev directory, a character device
+node /dev/mem (major 1, minor 1), and also creates /dev/tty,
+/dev/tty[0-5], /dev/loop[0-1], /dev/hda, /dev/hda1 to /dev/hda15 and
+/dev/log socket.
+
+.SH SEE ALSO
+.BR mkfs(8),
+.BR genromfs(8),
+.BR mkisofs(8),
+.BR mkfs.jffs2(1)
+.br
+.SH AUTHOR
+This manual page was written by David Kimdon <dwhedon@debian.org>,
+for the Debian GNU/Linux system (but may be used by others).
+Examples provided by Erik Andersen <andersen@codepoet.org>.
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.c
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.c (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/genext2fs.c (revision 5)
@@ -0,0 +1,2721 @@
+/* vi: set sw=8 ts=8: */
+// genext2fs.c
+//
+// ext2 filesystem generator for embedded systems
+// Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
+//
+// Please direct support requests to genext2fs-devel@lists.sourceforge.net
+//
+// 'du' portions taken from coreutils/du.c in busybox:
+// Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
+// Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+// Copyright (C) 2002 Edward Betts <edward@debian.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; version
+// 2 of the License.
+//
+// Changes:
+// 3 Jun 2000 Initial release
+// 6 Jun 2000 Bugfix: fs size multiple of 8
+// Bugfix: fill blocks with inodes
+// 14 Jun 2000 Bugfix: bad chdir() with -d option
+// Bugfix: removed size=8n constraint
+// Changed -d file to -f file
+// Added -e option
+// 22 Jun 2000 Changed types for 64bits archs
+// 24 Jun 2000 Added endianness swap
+// Bugfix: bad dir name lookup
+// 03 Aug 2000 Bugfix: ind. blocks endian swap
+// 09 Aug 2000 Bugfix: symlinks endian swap
+// 01 Sep 2000 Bugfix: getopt returns int, not char proski@gnu.org
+// 10 Sep 2000 Bugfix: device nodes endianness xavier.gueguen@col.bsf.alcatel.fr
+// Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr
+// Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr
+// 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com
+// 8 Mar 2002 Bugfix: endianness swap of x-indirects
+// 23 Mar 2002 Bugfix: test for IFCHR or IFBLK was flawed
+// 10 Oct 2002 Added comments,makefile targets, vsundar@ixiacom.com
+// endianess swap assert check.
+// Copyright (C) 2002 Ixia communications
+// 12 Oct 2002 Added support for triple indirection vsundar@ixiacom.com
+// Copyright (C) 2002 Ixia communications
+// 14 Oct 2002 Added support for groups vsundar@ixiacom.com
+// Copyright (C) 2002 Ixia communications
+// 5 Jan 2003 Bugfixes: reserved inodes should be set vsundar@usc.edu
+// only in the first group; directory names
+// need to be null padded at the end; and
+// number of blocks per group should be a
+// multiple of 8. Updated md5 values.
+// 6 Jan 2003 Erik Andersen <andersee@debian.org> added
+// mkfs.jffs2 compatible device table support,
+// along with -q, -P, -U
+
+
+#include <config.h>
+#include <stdio.h>
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+#elif MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+#endif
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+# if HAVE_STDDEF_H
+# include <stddef.h>
+# endif
+#endif
+
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+
+#include <stdarg.h>
+#include <assert.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+struct stats {
+ unsigned long nblocks;
+ unsigned long ninodes;
+};
+
+// block size
+
+static int blocksize = 1024;
+
+#define BLOCKSIZE blocksize
+#define BLOCKS_PER_GROUP 8192
+#define INODES_PER_GROUP 8192
+/* Percentage of blocks that are reserved.*/
+#define RESERVED_BLOCKS 5/100
+#define MAX_RESERVED_BLOCKS 25/100
+
+/* The default value for s_creator_os. */
+#if defined(__GNU__)
+# define CREATOR_OS 1 /* Hurd */
+#elif defined(__FreeBSD__)
+# define CREATOR_OS 3 /* FreeBSD */
+#else
+# define CREATOR_OS 0 /* Linux */
+#endif
+
+
+// inode block size (why is it != BLOCKSIZE ?!?)
+/* The field i_blocks in the ext2 inode stores the number of data blocks
+ but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
+ INOBLK is the number of such blocks in an actual disk block */
+
+#define INODE_BLOCKSIZE 512
+#define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE)
+
+// reserved inodes
+
+#define EXT2_BAD_INO 1 // Bad blocks inode
+#define EXT2_ROOT_INO 2 // Root inode
+#define EXT2_ACL_IDX_INO 3 // ACL inode
+#define EXT2_ACL_DATA_INO 4 // ACL inode
+#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode
+#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode
+#define EXT2_FIRST_INO 11 // First non reserved inode
+
+// magic number for ext2
+
+#define EXT2_MAGIC_NUMBER 0xEF53
+
+
+// direct/indirect block addresses
+
+#define EXT2_NDIR_BLOCKS 11 // direct blocks
+#define EXT2_IND_BLOCK 12 // indirect block
+#define EXT2_DIND_BLOCK 13 // double indirect block
+#define EXT2_TIND_BLOCK 14 // triple indirect block
+#define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address)
+
+// end of a block walk
+
+#define WALK_END 0xFFFFFFFE
+
+// file modes
+
+#define FM_IFMT 0170000 // format mask
+#define FM_IFSOCK 0140000 // socket
+#define FM_IFLNK 0120000 // symbolic link
+#define FM_IFREG 0100000 // regular file
+
+#define FM_IFBLK 0060000 // block device
+#define FM_IFDIR 0040000 // directory
+#define FM_IFCHR 0020000 // character device
+#define FM_IFIFO 0010000 // fifo
+
+#define FM_IMASK 0007777 // *all* perms mask for everything below
+
+#define FM_ISUID 0004000 // SUID
+#define FM_ISGID 0002000 // SGID
+#define FM_ISVTX 0001000 // sticky bit
+
+#define FM_IRWXU 0000700 // entire "user" mask
+#define FM_IRUSR 0000400 // read
+#define FM_IWUSR 0000200 // write
+#define FM_IXUSR 0000100 // execute
+
+#define FM_IRWXG 0000070 // entire "group" mask
+#define FM_IRGRP 0000040 // read
+#define FM_IWGRP 0000020 // write
+#define FM_IXGRP 0000010 // execute
+
+#define FM_IRWXO 0000007 // entire "other" mask
+#define FM_IROTH 0000004 // read
+#define FM_IWOTH 0000002 // write
+#define FM_IXOTH 0000001 // execute
+
+// options
+
+#define OP_HOLES 0x01 // make files with holes
+
+/* Defines for accessing group details */
+
+// Number of groups in the filesystem
+#define GRP_NBGROUPS(fs) \
+ (((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
+ (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
+
+// Get group block bitmap (bbm) given the group number
+#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs), get_gd((fs),(grp))->bg_block_bitmap) )
+
+// Get group inode bitmap (ibm) given the group number
+#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs), get_gd((fs),(grp))->bg_inode_bitmap) )
+
+// Given an inode number find the group it belongs to
+#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
+
+//Given an inode number get the inode bitmap that covers it
+#define GRP_GET_INODE_BITMAP(fs,nod) \
+ ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
+
+//Given an inode number find its offset within the inode bitmap that covers it
+#define GRP_IBM_OFFSET(fs,nod) \
+ ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
+
+// Given a block number find the group it belongs to
+#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
+
+//Given a block number get the block bitmap that covers it
+#define GRP_GET_BLOCK_BITMAP(fs,blk) \
+ ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
+
+//Given a block number find its offset within the block bitmap that covers it
+#define GRP_BBM_OFFSET(fs,blk) \
+ ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
+
+
+// used types
+
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+
+
+// the GNU C library has a wonderful scanf("%as", string) which will
+// allocate the string with the right size, good to avoid buffer
+// overruns. the following macros use it if available or use a
+// hacky workaround
+// moreover it will define a snprintf() like a sprintf(), i.e.
+// without the buffer overrun checking, to work around bugs in
+// older solaris. Note that this is still not very portable, in that
+// the return value cannot be trusted.
+
+#if 0 /* SCANF_CAN_MALLOC */
+/* C99 define "a" for floating point, so you can have
+ runtime surprise according the library versions */
+# define SCANF_PREFIX "a"
+# define SCANF_STRING(s) (&s)
+#else
+# define SCANF_PREFIX "511"
+# define SCANF_STRING(s) (s = malloc(512))
+#endif /* SCANF_CAN_MALLOC */
+
+#if PREFER_PORTABLE_SNPRINTF
+static inline int
+portable_snprintf(char *str, size_t n, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsprintf(str, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+# define SNPRINTF portable_snprintf
+#else
+# define SNPRINTF snprintf
+#endif /* PREFER_PORTABLE_SNPRINTF */
+
+#if !HAVE_GETLINE
+// getline() replacement for Darwin and Solaris etc.
+// This code uses backward seeks (unless rchunk is set to 1) which can't work
+// on pipes etc. However, add2fs_from_file() only calls getline() for
+// regular files, so a larger rchunk and backward seeks are okay.
+
+ssize_t
+getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
+{
+ char *p; // reads stored here
+ size_t const rchunk = 512; // number of bytes to read
+ size_t const mchunk = 512; // number of extra bytes to malloc
+ size_t m = rchunk + 1; // initial buffer size
+
+ if (*lineptr) {
+ if (*n < m) {
+ *lineptr = (char*)realloc(*lineptr, m);
+ if (!*lineptr) return -1;
+ *n = m;
+ }
+ } else {
+ *lineptr = (char*)malloc(m);
+ if (!*lineptr) return -1;
+ *n = m;
+ }
+
+ m = 0; // record length including seperator
+
+ do {
+ size_t i; // number of bytes read etc
+ size_t j = 0; // number of bytes searched
+
+ p = *lineptr + m;
+
+ i = fread(p, 1, rchunk, stream);
+ if (i < rchunk && ferror(stream))
+ return -1;
+ while (j < i) {
+ ++j;
+ if (*p++ == (char)delim) {
+ *p = '\0';
+ if (j != i) {
+ if (fseek(stream, j - i, SEEK_CUR))
+ return -1;
+ if (feof(stream))
+ clearerr(stream);
+ }
+ m += j;
+ return m;
+ }
+ }
+
+ m += j;
+ if (feof(stream)) {
+ if (m) return m;
+ if (!i) return -1;
+ }
+
+ // allocate space for next read plus possible null terminator
+ i = ((m + (rchunk + 1 > mchunk ? rchunk + 1 : mchunk) +
+ mchunk - 1) / mchunk) * mchunk;
+ if (i != *n) {
+ *lineptr = (char*)realloc(*lineptr, i);
+ if (!*lineptr) return -1;
+ *n = i;
+ }
+ } while (1);
+}
+#define getline(a,b,c) getdelim(a,b,'\n',c)
+#endif /* HAVE_GETLINE */
+
+// Convert a numerical string to a float, and multiply the result by an
+// IEC or SI multiplier if provided; supported multipliers are Ki, Mi, Gi, k, M
+// and G.
+
+float
+SI_atof(const char *nptr)
+{
+ float f = 0;
+ float m = 1;
+ char *suffixptr;
+
+#if HAVE_STRTOF
+ f = strtof(nptr, &suffixptr);
+#else
+ f = (float)strtod(nptr, &suffixptr);
+#endif /* HAVE_STRTOF */
+
+ if (*suffixptr) {
+ if (!strcmp(suffixptr, "Ki"))
+ m = 1 << 10;
+ else if (!strcmp(suffixptr, "Mi"))
+ m = 1 << 20;
+ else if (!strcmp(suffixptr, "Gi"))
+ m = 1 << 30;
+ else if (!strcmp(suffixptr, "k"))
+ m = 1000;
+ else if (!strcmp(suffixptr, "M"))
+ m = 1000 * 1000;
+ else if (!strcmp(suffixptr, "G"))
+ m = 1000 * 1000 * 1000;
+ }
+ return f * m;
+}
+
+// endianness swap
+
+static inline uint16
+swab16(uint16 val)
+{
+ return (val >> 8) | (val << 8);
+}
+
+static inline uint32
+swab32(uint32 val)
+{
+ return ((val>>24) | ((val>>8)&0xFF00) |
+ ((val<<8)&0xFF0000) | (val<<24));
+}
+
+
+// on-disk structures
+// this trick makes me declare things only once
+// (once for the structures, once for the endianness swap)
+
+#define superblock_decl \
+ udecl32(s_inodes_count) /* Count of inodes in the filesystem */ \
+ udecl32(s_blocks_count) /* Count of blocks in the filesystem */ \
+ udecl32(s_r_blocks_count) /* Count of the number of reserved blocks */ \
+ udecl32(s_free_blocks_count) /* Count of the number of free blocks */ \
+ udecl32(s_free_inodes_count) /* Count of the number of free inodes */ \
+ udecl32(s_first_data_block) /* The first block which contains data */ \
+ udecl32(s_log_block_size) /* Indicator of the block size */ \
+ decl32(s_log_frag_size) /* Indicator of the size of the fragments */ \
+ udecl32(s_blocks_per_group) /* Count of the number of blocks in each block group */ \
+ udecl32(s_frags_per_group) /* Count of the number of fragments in each block group */ \
+ udecl32(s_inodes_per_group) /* Count of the number of inodes in each block group */ \
+ udecl32(s_mtime) /* The time that the filesystem was last mounted */ \
+ udecl32(s_wtime) /* The time that the filesystem was last written to */ \
+ udecl16(s_mnt_count) /* The number of times the file system has been mounted */ \
+ decl16(s_max_mnt_count) /* The number of times the file system can be mounted */ \
+ udecl16(s_magic) /* Magic number indicating ex2fs */ \
+ udecl16(s_state) /* Flags indicating the current state of the filesystem */ \
+ udecl16(s_errors) /* Flags indicating the procedures for error reporting */ \
+ udecl16(s_minor_rev_level) /* The minor revision level of the filesystem */ \
+ udecl32(s_lastcheck) /* The time that the filesystem was last checked */ \
+ udecl32(s_checkinterval) /* The maximum time permissable between checks */ \
+ udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \
+ udecl32(s_rev_level) /* The revision level of the filesystem */ \
+ udecl16(s_def_resuid) /* The default uid for reserved blocks */ \
+ udecl16(s_def_resgid) /* The default gid for reserved blocks */
+
+#define groupdescriptor_decl \
+ udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \
+ udecl32(bg_inode_bitmap) /* Block number of the inode bitmap */ \
+ udecl32(bg_inode_table) /* Block number of the inode table */ \
+ udecl16(bg_free_blocks_count) /* Free blocks in the group */ \
+ udecl16(bg_free_inodes_count) /* Free inodes in the group */ \
+ udecl16(bg_used_dirs_count) /* Number of directories in the group */ \
+ udecl16(bg_pad)
+
+#define inode_decl \
+ udecl16(i_mode) /* Entry type and file mode */ \
+ udecl16(i_uid) /* User id */ \
+ udecl32(i_size) /* File/dir size in bytes */ \
+ udecl32(i_atime) /* Last access time */ \
+ udecl32(i_ctime) /* Creation time */ \
+ udecl32(i_mtime) /* Last modification time */ \
+ udecl32(i_dtime) /* Deletion time */ \
+ udecl16(i_gid) /* Group id */ \
+ udecl16(i_links_count) /* Number of (hard) links to this inode */ \
+ udecl32(i_blocks) /* Number of blocks used (1 block = 512 bytes) */ \
+ udecl32(i_flags) /* ??? */ \
+ udecl32(i_reserved1) \
+ utdecl32(i_block,15) /* Blocks table */ \
+ udecl32(i_version) /* ??? */ \
+ udecl32(i_file_acl) /* File access control list */ \
+ udecl32(i_dir_acl) /* Directory access control list */ \
+ udecl32(i_faddr) /* Fragment address */ \
+ udecl8(i_frag) /* Fragments count*/ \
+ udecl8(i_fsize) /* Fragment size */ \
+ udecl16(i_pad1)
+
+#define directory_decl \
+ udecl32(d_inode) /* Inode entry */ \
+ udecl16(d_rec_len) /* Total size on record */ \
+ udecl16(d_name_len) /* Size of entry name */
+
+#define decl8(x) int8 x;
+#define udecl8(x) uint8 x;
+#define decl16(x) int16 x;
+#define udecl16(x) uint16 x;
+#define decl32(x) int32 x;
+#define udecl32(x) uint32 x;
+#define utdecl32(x,n) uint32 x[n];
+
+typedef struct
+{
+ superblock_decl
+ uint32 s_reserved[235]; // Reserved
+} superblock;
+
+typedef struct
+{
+ groupdescriptor_decl
+ uint32 bg_reserved[3];
+} groupdescriptor;
+
+typedef struct
+{
+ inode_decl
+ uint32 i_reserved2[2];
+} inode;
+
+typedef struct
+{
+ directory_decl
+ char d_name[0];
+} directory;
+
+typedef uint8 *block;
+
+/* blockwalker fields:
+ The blockwalker is used to access all the blocks of a file (including
+ the indirection blocks) through repeated calls to walk_bw.
+
+ bpdir -> index into the inode->i_block[]. Indicates level of indirection.
+ bnum -> total number of blocks so far accessed. including indirection
+ blocks.
+ bpind,bpdind,bptind -> index into indirection blocks.
+
+ bpind, bpdind, bptind do *NOT* index into single, double and triple
+ indirect blocks resp. as you might expect from their names. Instead
+ they are in order the 1st, 2nd & 3rd index to be used
+
+ As an example..
+ To access data block number 70000:
+ bpdir: 15 (we are doing triple indirection)
+ bpind: 0 ( index into the triple indirection block)
+ bpdind: 16 ( index into the double indirection block)
+ bptind: 99 ( index into the single indirection block)
+ 70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
+
+ So,for double indirection bpind will index into the double indirection
+ block and bpdind into the single indirection block. For single indirection
+ only bpind will be used.
+*/
+
+typedef struct
+{
+ uint32 bnum;
+ uint32 bpdir;
+ uint32 bpind;
+ uint32 bpdind;
+ uint32 bptind;
+} blockwalker;
+
+
+/* Filesystem structure that support groups */
+typedef struct
+{
+ uint8 zero[1024]; // Room for bootloader stuff
+ superblock sb; // The superblock, always at 1024
+ // group descriptors come next, see get_gd() below
+} filesystem;
+
+// now the endianness swap
+
+#undef decl8
+#undef udecl8
+#undef decl16
+#undef udecl16
+#undef decl32
+#undef udecl32
+#undef utdecl32
+
+#define decl8(x)
+#define udecl8(x)
+#define decl16(x) this->x = swab16(this->x);
+#define udecl16(x) this->x = swab16(this->x);
+#define decl32(x) this->x = swab32(this->x);
+#define udecl32(x) this->x = swab32(this->x);
+#define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }
+
+#define HDLINK_CNT 16
+static int32 hdlink_cnt = HDLINK_CNT;
+struct hdlink_s
+{
+ uint32 src_inode;
+ uint32 dst_nod;
+};
+
+struct hdlinks_s
+{
+ int32 count;
+ struct hdlink_s *hdl;
+};
+
+static struct hdlinks_s hdlinks;
+
+static void
+swap_sb(superblock *sb)
+{
+#define this sb
+ superblock_decl
+#undef this
+}
+
+static void
+swap_gd(groupdescriptor *gd)
+{
+#define this gd
+ groupdescriptor_decl
+#undef this
+}
+
+static void
+swap_nod(inode *nod)
+{
+#define this nod
+ inode_decl
+#undef this
+}
+
+static void
+swap_dir(directory *dir)
+{
+#define this dir
+ directory_decl
+#undef this
+}
+
+static void
+swap_block(block b)
+{
+ int i;
+ uint32 *blk = (uint32*)b;
+ for(i = 0; i < BLOCKSIZE/4; i++)
+ blk[i] = swab32(blk[i]);
+}
+
+#undef decl8
+#undef udecl8
+#undef decl16
+#undef udecl16
+#undef decl32
+#undef udecl32
+#undef utdecl32
+
+static char * app_name;
+static const char *const memory_exhausted = "memory exhausted";
+
+// error (un)handling
+static void
+verror_msg(const char *s, va_list p)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s: ", app_name);
+ vfprintf(stderr, s, p);
+}
+static void
+error_msg(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+}
+
+static void
+error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void
+vperror_msg(const char *s, va_list p)
+{
+ int err = errno;
+ if (s == 0)
+ s = "";
+ verror_msg(s, p);
+ if (*s)
+ s = ": ";
+ fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void
+perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+ exit(EXIT_FAILURE);
+}
+
+static FILE *
+xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ perror_msg_and_die("%s", path);
+ return fp;
+}
+
+static char *
+xstrdup(const char *s)
+{
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+ t = strdup(s);
+ if (t == NULL)
+ error_msg_and_die(memory_exhausted);
+ return t;
+}
+
+static void *
+xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+static char *
+xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ perror_msg_and_die("%s:%s", app_name, path);
+ }
+ }
+ while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+ return buf;
+}
+
+int
+is_hardlink(ino_t inode)
+{
+ int i;
+
+ for(i = 0; i < hdlinks.count; i++) {
+ if(hdlinks.hdl[i].src_inode == inode)
+ return i;
+ }
+ return -1;
+}
+
+// printf helper macro
+#define plural(a) (a), ((a) > 1) ? "s" : ""
+
+// temporary working block
+static inline uint8 *
+get_workblk(void)
+{
+ unsigned char* b=calloc(1,BLOCKSIZE);
+ return b;
+}
+static inline void
+free_workblk(block b)
+{
+ free(b);
+}
+
+/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
+static inline uint32
+rndup(uint32 qty, uint32 siz)
+{
+ return (qty + (siz - 1)) & ~(siz - 1);
+}
+
+// check if something is allocated in the bitmap
+static inline uint32
+allocated(block b, uint32 item)
+{
+ return b[(item-1) / 8] & (1 << ((item-1) % 8));
+}
+
+// return a given block from a filesystem
+static inline uint8 *
+get_blk(filesystem *fs, uint32 blk)
+{
+ return (uint8*)fs + blk*BLOCKSIZE;
+}
+
+// the group descriptors are aligned on the block size
+static inline groupdescriptor *
+get_gd(filesystem *fs, int no)
+{
+ int gdblk = (sizeof (filesystem) + BLOCKSIZE - 1) / BLOCKSIZE;
+ return ((groupdescriptor *) get_blk(fs, gdblk)) + no;
+}
+
+// return a given inode from a filesystem
+static inline inode *
+get_nod(filesystem *fs, uint32 nod)
+{
+ int grp,offset;
+ inode *itab;
+
+ offset = GRP_IBM_OFFSET(fs,nod);
+ grp = GRP_GROUP_OF_INODE(fs,nod);
+ itab = (inode *)get_blk(fs, get_gd(fs,grp)->bg_inode_table);
+ return itab+offset-1;
+}
+
+// allocate a given block/inode in the bitmap
+// allocate first free if item == 0
+static uint32
+allocate(block b, uint32 item)
+{
+ if(!item)
+ {
+ int i;
+ uint8 bits;
+ for(i = 0; i < BLOCKSIZE; i++)
+ if((bits = b[i]) != (uint8)-1)
+ {
+ int j;
+ for(j = 0; j < 8; j++)
+ if(!(bits & (1 << j)))
+ break;
+ item = i * 8 + j + 1;
+ break;
+ }
+ if(i == BLOCKSIZE)
+ return 0;
+ }
+ b[(item-1) / 8] |= (1 << ((item-1) % 8));
+ return item;
+}
+
+// deallocate a given block/inode
+static void
+deallocate(block b, uint32 item)
+{
+ b[(item-1) / 8] &= ~(1 << ((item-1) % 8));
+}
+
+// allocate a block
+static uint32
+alloc_blk(filesystem *fs, uint32 nod)
+{
+ uint32 bk=0;
+ uint32 grp,nbgroups;
+
+ grp = GRP_GROUP_OF_INODE(fs,nod);
+ nbgroups = GRP_NBGROUPS(fs);
+ if(!(bk = allocate(GRP_GET_GROUP_BBM(fs, grp), 0))) {
+ for(grp=0;grp<nbgroups && !bk;grp++)
+ bk = allocate(GRP_GET_GROUP_BBM(fs, grp), 0);
+ grp--;
+ }
+ if (!bk)
+ error_msg_and_die("couldn't allocate a block (no free space)");
+ if(!(get_gd(fs, grp)->bg_free_blocks_count--))
+ error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
+ if(!(fs->sb.s_free_blocks_count--))
+ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
+ return fs->sb.s_first_data_block + fs->sb.s_blocks_per_group*grp + (bk-1);
+}
+
+// free a block
+static void
+free_blk(filesystem *fs, uint32 bk)
+{
+ uint32 grp;
+
+ grp = bk / fs->sb.s_blocks_per_group;
+ bk %= fs->sb.s_blocks_per_group;
+ deallocate(GRP_GET_GROUP_BBM(fs, grp), bk);
+ get_gd(fs, grp)->bg_free_blocks_count++;
+ fs->sb.s_free_blocks_count++;
+}
+
+// allocate an inode
+static uint32
+alloc_nod(filesystem *fs)
+{
+ uint32 nod,best_group=0;
+ uint32 grp,nbgroups,avefreei;
+
+ nbgroups = GRP_NBGROUPS(fs);
+
+ /* Distribute inodes amongst all the blocks */
+ /* For every block group with more than average number of free inodes */
+ /* find the one with the most free blocks and allocate node there */
+ /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
+ /* We do it for all inodes. */
+ avefreei = fs->sb.s_free_inodes_count / nbgroups;
+ for(grp=0; grp<nbgroups; grp++) {
+ if (get_gd(fs, grp)->bg_free_inodes_count < avefreei ||
+ get_gd(fs, grp)->bg_free_inodes_count == 0)
+ continue;
+ if (!best_group ||
+ get_gd(fs, grp)->bg_free_blocks_count > get_gd(fs, best_group)->bg_free_blocks_count)
+ best_group = grp;
+ }
+ if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, best_group), 0)))
+ error_msg_and_die("couldn't allocate an inode (no free inode)");
+ if(!(get_gd(fs, best_group)->bg_free_inodes_count--))
+ error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
+ if(!(fs->sb.s_free_inodes_count--))
+ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
+ return fs->sb.s_inodes_per_group*best_group+nod;
+}
+
+// print a bitmap allocation
+static void
+print_bm(block b, uint32 max)
+{
+ uint32 i;
+ printf("----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0\n");
+ for(i=1; i <= max; i++)
+ {
+ putchar(allocated(b, i) ? '*' : '.');
+ if(!(i % 100))
+ printf("\n");
+ }
+ if((i-1) % 100)
+ printf("\n");
+}
+
+// initalize a blockwalker (iterator for blocks list)
+static inline void
+init_bw(blockwalker *bw)
+{
+ bw->bnum = 0;
+ bw->bpdir = EXT2_INIT_BLOCK;
+}
+
+// return next block of inode (WALK_END for end)
+// if *create>0, append a newly allocated block at the end
+// if *create<0, free the block - warning, the metadata blocks contents is
+// used after being freed, so once you start
+// freeing blocks don't stop until the end of
+// the file. moreover, i_blocks isn't updated.
+// in fact, don't do that, just use extend_blk
+// if hole!=0, create a hole in the file
+static uint32
+walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
+{
+ uint32 *bkref = 0;
+ uint32 *b;
+ int extend = 0, reduce = 0;
+ if(create && (*create) < 0)
+ reduce = 1;
+ if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
+ {
+ if(create && (*create) > 0)
+ {
+ (*create)--;
+ extend = 1;
+ }
+ else
+ return WALK_END;
+ }
+ // first direct block
+ if(bw->bpdir == EXT2_INIT_BLOCK)
+ {
+ bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
+ if(extend) // allocate first block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ // direct block
+ else if(bw->bpdir < EXT2_NDIR_BLOCKS)
+ {
+ bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
+ if(extend) // allocate block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free block
+ free_blk(fs, *bkref);
+ }
+ // first block in indirect block
+ else if(bw->bpdir == EXT2_NDIR_BLOCKS)
+ {
+ bw->bnum++;
+ bw->bpdir = EXT2_IND_BLOCK;
+ bw->bpind = 0;
+ if(extend) // allocate indirect block
+ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ if(reduce) // free indirect block
+ free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate first block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ // block in indirect block
+ else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+ {
+ bw->bpind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free block
+ free_blk(fs, *bkref);
+ }
+ // first block in first indirect block in first double indirect block
+ else if(bw->bpdir == EXT2_IND_BLOCK)
+ {
+ bw->bnum += 2;
+ bw->bpdir = EXT2_DIND_BLOCK;
+ bw->bpind = 0;
+ bw->bpdind = 0;
+ if(extend) // allocate double indirect block
+ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ if(reduce) // free double indirect block
+ free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate first indirect block
+ b[bw->bpind] = alloc_blk(fs,nod);
+ if(reduce) // free firstindirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ // block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
+ {
+ bw->bpdind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free block
+ free_blk(fs, *bkref);
+ }
+ // first block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+ {
+ bw->bnum++;
+ bw->bpdind = 0;
+ bw->bpind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate indirect block
+ b[bw->bpind] = alloc_blk(fs,nod);
+ if(reduce) // free indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+
+ /* Adding support for triple indirection */
+ /* Just starting triple indirection. Allocate the indirection
+ blocks and the first data block
+ */
+ else if (bw->bpdir == EXT2_DIND_BLOCK)
+ {
+ bw->bnum += 3;
+ bw->bpdir = EXT2_TIND_BLOCK;
+ bw->bpind = 0;
+ bw->bpdind = 0;
+ bw->bptind = 0;
+ if(extend) // allocate triple indirect block
+ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ if(reduce) // free triple indirect block
+ free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate first double indirect block
+ b[bw->bpind] = alloc_blk(fs,nod);
+ if(reduce) // free first double indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ if(extend) // allocate first indirect block
+ b[bw->bpdind] = alloc_blk(fs,nod);
+ if(reduce) // free first indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpdind]);
+ bkref = &b[bw->bptind];
+ if(extend) // allocate first data block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ /* Still processing a single indirect block down the indirection
+ chain.Allocate a data block for it
+ */
+ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
+ (bw->bptind < BLOCKSIZE/4 -1) )
+ {
+ bw->bptind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpdind]);
+ bkref = &b[bw->bptind];
+ if(extend) // allocate data block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free block
+ free_blk(fs, *bkref);
+ }
+ /* Finished processing a single indirect block. But still in the
+ same double indirect block. Allocate new single indirect block
+ for it and a data block
+ */
+ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
+ (bw->bpdind < BLOCKSIZE/4 -1) )
+ {
+ bw->bnum++;
+ bw->bptind = 0;
+ bw->bpdind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ if(extend) // allocate single indirect block
+ b[bw->bpdind] = alloc_blk(fs,nod);
+ if(reduce) // free indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpdind]);
+ bkref = &b[bw->bptind];
+ if(extend) // allocate first data block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ /* Finished processing a double indirect block. Allocate the next
+ double indirect block and the single,data blocks for it
+ */
+ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
+ (bw->bpind < BLOCKSIZE/4 - 1) )
+ {
+ bw->bnum += 2;
+ bw->bpdind = 0;
+ bw->bptind = 0;
+ bw->bpind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate double indirect block
+ b[bw->bpind] = alloc_blk(fs,nod);
+ if(reduce) // free double indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ if(extend) // allocate single indirect block
+ b[bw->bpdind] = alloc_blk(fs,nod);
+ if(reduce) // free indirect block
+ free_blk(fs, b[bw->bpind]);
+ b = (uint32*)get_blk(fs, b[bw->bpdind]);
+ bkref = &b[bw->bptind];
+ if(extend) // allocate first block
+ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ if(reduce) // free first block
+ free_blk(fs, *bkref);
+ }
+ else
+ error_msg_and_die("file too big !");
+ /* End change for walking triple indirection */
+
+ if(*bkref)
+ {
+ bw->bnum++;
+ if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
+ error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
+ }
+ if(extend)
+ get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
+ return *bkref;
+}
+
+// add blocks to an inode (file/dir/etc...)
+static void
+extend_blk(filesystem *fs, uint32 nod, block b, int amount)
+{
+ int create = amount;
+ blockwalker bw, lbw;
+ uint32 bk;
+ init_bw(&bw);
+ if(amount < 0)
+ {
+ uint32 i;
+ for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
+ walk_bw(fs, nod, &bw, 0, 0);
+ while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
+ /*nop*/;
+ get_nod(fs, nod)->i_blocks += amount * INOBLK;
+ }
+ else
+ {
+ lbw = bw;
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ lbw = bw;
+ bw = lbw;
+ while(create)
+ {
+ int i, copyb = 0;
+ if(!(fs->sb.s_reserved[200] & OP_HOLES))
+ copyb = 1;
+ else
+ for(i = 0; i < BLOCKSIZE / 4; i++)
+ if(((int32*)(b + BLOCKSIZE * (amount - create)))[i])
+ {
+ copyb = 1;
+ break;
+ }
+ if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END)
+ break;
+ if(copyb)
+ memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE);
+ }
+ }
+}
+
+// link an entry (inode #) to a directory
+static void
+add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
+{
+ blockwalker bw;
+ uint32 bk;
+ uint8 *b;
+ directory *d;
+ int reclen, nlen;
+ inode *node;
+ inode *pnode;
+
+ pnode = get_nod(fs, dnod);
+ if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
+ error_msg_and_die("can't add '%s' to a non-directory", name);
+ if(!*name)
+ error_msg_and_die("can't create an inode with an empty name");
+ if(strchr(name, '/'))
+ error_msg_and_die("bad name '%s' (contains a slash)", name);
+ nlen = strlen(name);
+ reclen = sizeof(directory) + rndup(nlen, 4);
+ if(reclen > BLOCKSIZE)
+ error_msg_and_die("bad name '%s' (too long)", name);
+ init_bw(&bw);
+ while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
+ {
+ b = get_blk(fs, bk);
+ // for all dir entries in block
+ for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
+ {
+ // if empty dir entry, large enough, use it
+ if((!d->d_inode) && (d->d_rec_len >= reclen))
+ {
+ d->d_inode = nod;
+ node = get_nod(fs, nod);
+ node->i_links_count++;
+ d->d_name_len = nlen;
+ strncpy(d->d_name, name, nlen);
+ return;
+ }
+ // if entry with enough room (last one?), shrink it & use it
+ if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen))
+ {
+ reclen = d->d_rec_len;
+ d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
+ reclen -= d->d_rec_len;
+ d = (directory*) (((int8*)d) + d->d_rec_len);
+ d->d_rec_len = reclen;
+ d->d_inode = nod;
+ node = get_nod(fs, nod);
+ node->i_links_count++;
+ d->d_name_len = nlen;
+ strncpy(d->d_name, name, nlen);
+ return;
+ }
+ }
+ }
+ // we found no free entry in the directory, so we add a block
+ if(!(b = get_workblk()))
+ error_msg_and_die("get_workblk() failed.");
+ d = (directory*)b;
+ d->d_inode = nod;
+ node = get_nod(fs, nod);
+ node->i_links_count++;
+ d->d_rec_len = BLOCKSIZE;
+ d->d_name_len = nlen;
+ strncpy(d->d_name, name, nlen);
+ extend_blk(fs, dnod, b, 1);
+ get_nod(fs, dnod)->i_size += BLOCKSIZE;
+ free_workblk(b);
+}
+
+// find an entry in a directory
+static uint32
+find_dir(filesystem *fs, uint32 nod, const char * name)
+{
+ blockwalker bw;
+ uint32 bk;
+ int nlen = strlen(name);
+ init_bw(&bw);
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ {
+ directory *d;
+ uint8 *b;
+ b = get_blk(fs, bk);
+ for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
+ if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen))
+ return d->d_inode;
+ }
+ return 0;
+}
+
+// find the inode of a full path
+static uint32
+find_path(filesystem *fs, uint32 nod, const char * name)
+{
+ char *p, *n, *n2 = xstrdup(name);
+ n = n2;
+ while(*n == '/')
+ {
+ nod = EXT2_ROOT_INO;
+ n++;
+ }
+ while(*n)
+ {
+ if((p = strchr(n, '/')))
+ (*p) = 0;
+ if(!(nod = find_dir(fs, nod, n)))
+ break;
+ if(p)
+ n = p + 1;
+ else
+ break;
+ }
+ free(n2);
+ return nod;
+}
+
+// create a simple inode
+static uint32
+mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
+{
+ uint32 nod;
+ inode *node;
+ if((nod = find_dir(fs, parent_nod, name)))
+ {
+ node = get_nod(fs, nod);
+ if((node->i_mode & FM_IFMT) != (mode & FM_IFMT))
+ error_msg_and_die("node '%s' already exists and isn't of the same type", name);
+ node->i_mode = mode;
+ }
+ else
+ {
+ nod = alloc_nod(fs);
+ node = get_nod(fs, nod);
+ node->i_mode = mode;
+ add2dir(fs, parent_nod, nod, name);
+ switch(mode & FM_IFMT)
+ {
+ case FM_IFLNK:
+ mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ break;
+ case FM_IFBLK:
+ case FM_IFCHR:
+ ((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
+ ((uint8*)get_nod(fs, nod)->i_block)[1] = major;
+ break;
+ case FM_IFDIR:
+ add2dir(fs, nod, nod, ".");
+ add2dir(fs, nod, parent_nod, "..");
+ get_gd(fs, GRP_GROUP_OF_INODE(fs,nod))->bg_used_dirs_count++;
+ break;
+ }
+ }
+ node->i_uid = uid;
+ node->i_gid = gid;
+ node->i_atime = mtime;
+ node->i_ctime = ctime;
+ node->i_mtime = mtime;
+ return nod;
+}
+
+// make a full-fledged directory (i.e. with "." & "..")
+static inline uint32
+mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
+ uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
+{
+ return mknod_fs(fs, parent_nod, name, mode|FM_IFDIR, uid, gid, 0, 0, ctime, mtime);
+}
+
+// make a symlink
+static uint32
+mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 *b, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
+{
+ uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
+ extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
+ get_nod(fs, nod)->i_size = size;
+ if(size <= 4 * (EXT2_TIND_BLOCK+1))
+ {
+ strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
+ return nod;
+ }
+ extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
+ return nod;
+}
+
+// make a file from a FILE*
+static uint32
+mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
+{
+ uint8 * b;
+ uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
+ extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
+ get_nod(fs, nod)->i_size = size;
+ if (size) {
+ if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
+ error_msg_and_die("not enough mem to read file '%s'", name);
+ if(f)
+ fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
+ extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
+ free(b);
+ }
+ return nod;
+}
+
+// retrieves a mode info from a struct stat
+static uint32
+get_mode(struct stat *st)
+{
+ uint32 mode = 0;
+
+ if(st->st_mode & S_IRUSR)
+ mode |= FM_IRUSR;
+ if(st->st_mode & S_IWUSR)
+ mode |= FM_IWUSR;
+ if(st->st_mode & S_IXUSR)
+ mode |= FM_IXUSR;
+ if(st->st_mode & S_IRGRP)
+ mode |= FM_IRGRP;
+ if(st->st_mode & S_IWGRP)
+ mode |= FM_IWGRP;
+ if(st->st_mode & S_IXGRP)
+ mode |= FM_IXGRP;
+ if(st->st_mode & S_IROTH)
+ mode |= FM_IROTH;
+ if(st->st_mode & S_IWOTH)
+ mode |= FM_IWOTH;
+ if(st->st_mode & S_IXOTH)
+ mode |= FM_IXOTH;
+ if(st->st_mode & S_ISUID)
+ mode |= FM_ISUID;
+ if(st->st_mode & S_ISGID)
+ mode |= FM_ISGID;
+ if(st->st_mode & S_ISVTX)
+ mode |= FM_ISVTX;
+ return mode;
+}
+
+// add or fixup entries to the filesystem from a text file
+/* device table entries take the form of:
+ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+ /dev/mem c 640 0 0 1 1 0 0 -
+
+ type can be one of:
+ f A regular file
+ d Directory
+ c Character special device file
+ b Block special device file
+ p Fifo (named pipe)
+
+ I don't bother with symlinks (permissions are irrelevant), hard
+ links (special cases of regular files), or sockets (why bother).
+
+ Regular files must exist in the target root directory. If a char,
+ block, fifo, or directory does not exist, it will be created.
+*/
+
+static void
+add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh, uint32 fs_timestamp, struct stats *stats)
+{
+ unsigned long mode, uid, gid, major, minor;
+ unsigned long start, increment, count;
+ uint32 nod, ctime, mtime;
+ char *c, type, *path = NULL, *path2 = NULL, *dir, *name, *line = NULL;
+ size_t len;
+ struct stat st;
+ int nbargs, lineno = 0;
+
+ fstat(fileno(fh), &st);
+ ctime = fs_timestamp;
+ mtime = st.st_mtime;
+ while(getline(&line, &len, fh) >= 0)
+ {
+ mode = uid = gid = major = minor = 0;
+ start = 0; increment = 1; count = 0;
+ lineno++;
+ if((c = strchr(line, '#')))
+ *c = 0;
+ if (path) {
+ free(path);
+ path = NULL;
+ }
+ if (path2) {
+ free(path2);
+ path2 = NULL;
+ }
+ nbargs = sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
+ SCANF_STRING(path), &type, &mode, &uid, &gid, &major, &minor,
+ &start, &increment, &count);
+ if(nbargs < 3)
+ {
+ if(nbargs > 0)
+ error_msg("device table line %d skipped: bad format for entry '%s'", lineno, path);
+ continue;
+ }
+ mode &= FM_IMASK;
+ path2 = strdup(path);
+ name = basename(path);
+ dir = dirname(path2);
+ if((!strcmp(name, ".")) || (!strcmp(name, "..")))
+ {
+ error_msg("device table line %d skipped", lineno);
+ continue;
+ }
+ if(fs)
+ {
+ if(!(nod = find_path(fs, this_nod, dir)))
+ {
+ error_msg("device table line %d skipped: can't find directory '%s' to create '%s''", lineno, dir, name);
+ continue;
+ }
+ }
+ else
+ nod = 0;
+ switch (type)
+ {
+ case 'd':
+ mode |= FM_IFDIR;
+ break;
+ case 'f':
+ mode |= FM_IFREG;
+ break;
+ case 'p':
+ mode |= FM_IFIFO;
+ break;
+ case 's':
+ mode |= FM_IFSOCK;
+ break;
+ case 'c':
+ mode |= FM_IFCHR;
+ break;
+ case 'b':
+ mode |= FM_IFBLK;
+ break;
+ default:
+ error_msg("device table line %d skipped: bad type '%c' for entry '%s'", lineno, type, name);
+ continue;
+ }
+ if(stats) {
+ if(count > 0)
+ stats->ninodes += count - start;
+ else
+ stats->ninodes++;
+ } else {
+ if(count > 0)
+ {
+ char *dname;
+ unsigned long i;
+ unsigned len;
+ len = strlen(name) + 10;
+ dname = malloc(len + 1);
+ for(i = start; i < count; i++)
+ {
+ SNPRINTF(dname, len, "%s%lu", name, i);
+ mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
+ }
+ free(dname);
+ }
+ else
+ mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
+ }
+ }
+ if (line)
+ free(line);
+ if (path)
+ free(path);
+ if (path2)
+ free(path2);
+}
+
+// adds a tree of entries to the filesystem from current dir
+static void
+add2fs_from_dir(filesystem *fs, uint32 this_nod, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats)
+{
+ uint32 nod;
+ uint32 uid, gid, mode, ctime, mtime;
+ const char *name;
+ FILE *fh;
+ DIR *dh;
+ struct dirent *dent;
+ struct stat st;
+ char *lnk;
+ uint32 save_nod;
+
+ if(!(dh = opendir(".")))
+ perror_msg_and_die(".");
+ while((dent = readdir(dh)))
+ {
+ if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+ continue;
+ lstat(dent->d_name, &st);
+ uid = st.st_uid;
+ gid = st.st_gid;
+ ctime = fs_timestamp;
+ mtime = st.st_mtime;
+ name = dent->d_name;
+ mode = get_mode(&st);
+ if(squash_uids)
+ uid = gid = 0;
+ if(squash_perms)
+ mode &= ~(FM_IRWXG | FM_IRWXO);
+ if(stats)
+ switch(st.st_mode & S_IFMT)
+ {
+ case S_IFLNK:
+ case S_IFREG:
+ if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
+ stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK:
+ stats->ninodes++;
+ break;
+ case S_IFDIR:
+ stats->ninodes++;
+ if(chdir(dent->d_name) < 0)
+ perror_msg_and_die(dent->d_name);
+ add2fs_from_dir(fs, this_nod, squash_uids, squash_perms, fs_timestamp, stats);
+ chdir("..");
+ break;
+ default:
+ break;
+ }
+ else
+ {
+ save_nod = 0;
+ /* Check for hardlinks */
+ if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
+ int32 hdlink = is_hardlink(st.st_ino);
+ if (hdlink >= 0) {
+ add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
+ continue;
+ } else {
+ save_nod = 1;
+ }
+ }
+ switch(st.st_mode & S_IFMT)
+ {
+#if HAVE_STRUCT_STAT_ST_RDEV
+ case S_IFCHR:
+ nod = mknod_fs(fs, this_nod, name, mode|FM_IFCHR, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
+ break;
+ case S_IFBLK:
+ nod = mknod_fs(fs, this_nod, name, mode|FM_IFBLK, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
+ break;
+#endif
+ case S_IFIFO:
+ nod = mknod_fs(fs, this_nod, name, mode|FM_IFIFO, uid, gid, 0, 0, ctime, mtime);
+ break;
+ case S_IFSOCK:
+ nod = mknod_fs(fs, this_nod, name, mode|FM_IFSOCK, uid, gid, 0, 0, ctime, mtime);
+ break;
+ case S_IFLNK:
+ lnk = xreadlink(dent->d_name);
+ mklink_fs(fs, this_nod, name, st.st_size, (uint8*)lnk, uid, gid, ctime, mtime);
+ free(lnk);
+ break;
+ case S_IFREG:
+ fh = xfopen(dent->d_name, "rb");
+ nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
+ fclose(fh);
+ break;
+ case S_IFDIR:
+ nod = mkdir_fs(fs, this_nod, name, mode, uid, gid, ctime, mtime);
+ if(chdir(dent->d_name) < 0)
+ perror_msg_and_die(name);
+ add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
+ chdir("..");
+ break;
+ default:
+ error_msg("ignoring entry %s", name);
+ }
+ if (save_nod) {
+ if (hdlinks.count == hdlink_cnt) {
+ if ((hdlinks.hdl =
+ realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
+ sizeof (struct hdlink_s))) == NULL) {
+ error_msg_and_die("Not enough memory");
+ }
+ hdlink_cnt += HDLINK_CNT;
+ }
+ hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
+ hdlinks.hdl[hdlinks.count].dst_nod = nod;
+ hdlinks.count++;
+ }
+ }
+ }
+ closedir(dh);
+}
+
+// endianness swap of x-indirect blocks
+static void
+swap_goodblocks(filesystem *fs, inode *nod)
+{
+ uint32 i,j;
+ int done=0;
+ uint32 *b,*b2;
+
+ uint32 nblk = nod->i_blocks / INOBLK;
+ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ nod->i_block[i] = swab32(nod->i_block[i]);
+ if(nblk <= EXT2_IND_BLOCK)
+ return;
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
+ return;
+ /* Currently this will fail b'cos the number of blocks as stored
+ in i_blocks also includes the indirection blocks (see
+ walk_bw). But this function assumes that i_blocks only
+ stores the count of data blocks ( Actually according to
+ "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
+ i_blocks IS supposed to store the count of data blocks). so
+ with a file of size 268K nblk would be 269.The above check
+ will be false even though double indirection hasn't been
+ started.This is benign as 0 means block 0 which has been
+ zeroed out and therefore points back to itself from any offset
+ */
+ // FIXME: I have fixed that, but I have the feeling the rest of
+ // ths function needs to be fixed for the same reasons - Xav
+ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ for(i = 0; i < BLOCKSIZE/4; i++)
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
+ if (((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+ /* Adding support for triple indirection */
+ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
+ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
+ b2 = (uint32*)get_blk(fs,b[i]);
+ for(j=0; j<BLOCKSIZE/4;j++) {
+ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
+ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
+ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
+ j*(BLOCKSIZE/4)) )
+ if (b2[j])
+ swap_block(get_blk(fs,b2[j]));
+ else {
+ done = 1;
+ break;
+ }
+ }
+ swap_block((uint8 *)b2);
+ }
+ swap_block((uint8 *)b);
+ return;
+}
+
+static void
+swap_badblocks(filesystem *fs, inode *nod)
+{
+ uint32 i,j;
+ int done=0;
+ uint32 *b,*b2;
+
+ uint32 nblk = nod->i_blocks / INOBLK;
+ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
+ for(i = 0; i <= EXT2_TIND_BLOCK; i++)
+ nod->i_block[i] = swab32(nod->i_block[i]);
+ if(nblk <= EXT2_IND_BLOCK)
+ return;
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
+ return;
+ /* See comment in swap_goodblocks */
+ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ for(i = 0; i < BLOCKSIZE/4; i++)
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
+ if (((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+ /* Adding support for triple indirection */
+ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
+ swap_block((uint8 *)b);
+ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
+ b2 = (uint32*)get_blk(fs,b[i]);
+ swap_block((uint8 *)b2);
+ for(j=0; j<BLOCKSIZE/4;j++) {
+ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
+ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
+ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
+ j*(BLOCKSIZE/4)) )
+ if (b2[j])
+ swap_block(get_blk(fs,b2[j]));
+ else {
+ done = 1;
+ break;
+ }
+ }
+ }
+ return;
+}
+
+// endianness swap of the whole filesystem
+static void
+swap_goodfs(filesystem *fs)
+{
+ uint32 i;
+ for(i = 1; i < fs->sb.s_inodes_count; i++)
+ {
+ inode *nod = get_nod(fs, i);
+ if(nod->i_mode & FM_IFDIR)
+ {
+ blockwalker bw;
+ uint32 bk;
+ init_bw(&bw);
+ while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
+ {
+ directory *d;
+ uint8 *b;
+ b = get_blk(fs, bk);
+ for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
+ swap_dir(d);
+ }
+ }
+ swap_goodblocks(fs, nod);
+ swap_nod(nod);
+ }
+ for(i=0;i<GRP_NBGROUPS(fs);i++)
+ swap_gd(get_gd(fs, i));
+ swap_sb(&fs->sb);
+}
+
+static void
+swap_badfs(filesystem *fs)
+{
+ uint32 i;
+ swap_sb(&fs->sb);
+ for(i=0;i<GRP_NBGROUPS(fs);i++)
+ swap_gd(get_gd(fs, i));
+ for(i = 1; i < fs->sb.s_inodes_count; i++)
+ {
+ inode *nod = get_nod(fs, i);
+ swap_nod(nod);
+ swap_badblocks(fs, nod);
+ if(nod->i_mode & FM_IFDIR)
+ {
+ blockwalker bw;
+ uint32 bk;
+ init_bw(&bw);
+ while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
+ {
+ directory *d;
+ uint8 *b;
+ b = get_blk(fs, bk);
+ for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
+ swap_dir(d);
+ }
+ }
+ }
+}
+
+// initialize an empty filesystem
+static filesystem *
+init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
+ uint32 fs_timestamp, uint32 creator_os)
+{
+ uint32 i;
+ filesystem *fs;
+ directory *d;
+ uint8 * b;
+ uint32 nod, first_block;
+ uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
+ free_blocks_per_group,nbblocks_per_group,min_nbgroups;
+ uint32 gdsz,itblsz,bbmpos,ibmpos,itblpos;
+ uint32 j;
+ uint8 *bbm,*ibm;
+ inode *itab0;
+
+ if(nbresrvd < 0)
+ error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
+ if(nbinodes < EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0))
+ error_msg_and_die("too few inodes. Note: options have changed, see --help or the man page.");
+ if(nbblocks < 8)
+ error_msg_and_die("too few blocks. Note: options have changed, see --help or the man page.");
+
+ /* nbinodes is the total number of inodes in the system.
+ * a block group can have no more than 8192 inodes.
+ */
+ min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
+
+ /* On filesystems with 1k block size, the bootloader area uses a full
+ * block. For 2048 and up, the superblock can be fitted into block 0.
+ */
+ first_block = (BLOCKSIZE == 1024);
+
+ /* nbblocks is the total number of blocks in the filesystem.
+ * a block group can have no more than 8192 blocks.
+ */
+ nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
+ if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
+ nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
+ nbinodes_per_group = rndup((nbinodes + nbgroups - 1)/nbgroups,
+ (BLOCKSIZE/sizeof(inode)));
+ if (nbinodes_per_group < 16)
+ nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
+
+ gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
+ itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
+ overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
+ free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
+ free_blocks_per_group = nbblocks_per_group - overhead_per_group;
+ if(free_blocks < 0)
+ error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
+
+ if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+ error_msg_and_die("not enough memory for filesystem");
+
+ // create the superblock for an empty filesystem
+ fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
+ fs->sb.s_blocks_count = nbblocks;
+ fs->sb.s_r_blocks_count = nbresrvd;
+ fs->sb.s_free_blocks_count = free_blocks;
+ fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
+ fs->sb.s_first_data_block = first_block;
+ fs->sb.s_log_block_size = BLOCKSIZE >> 11;
+ fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
+ fs->sb.s_blocks_per_group = nbblocks_per_group;
+ fs->sb.s_frags_per_group = nbblocks_per_group;
+ fs->sb.s_inodes_per_group = nbinodes_per_group;
+ fs->sb.s_wtime = fs_timestamp;
+ fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+ fs->sb.s_lastcheck = fs_timestamp;
+ fs->sb.s_creator_os = creator_os;
+
+ // set up groupdescriptors
+ for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
+ i<nbgroups;
+ i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
+ {
+ groupdescriptor *gd = get_gd(fs, i);
+
+ if(free_blocks > free_blocks_per_group) {
+ gd->bg_free_blocks_count = free_blocks_per_group;
+ free_blocks -= free_blocks_per_group;
+ } else {
+ gd->bg_free_blocks_count = free_blocks;
+ free_blocks = 0; // this is the last block group
+ }
+ if(i)
+ gd->bg_free_inodes_count = nbinodes_per_group;
+ else
+ gd->bg_free_inodes_count = nbinodes_per_group -
+ EXT2_FIRST_INO + 2;
+ gd->bg_used_dirs_count = 0;
+ gd->bg_block_bitmap = bbmpos;
+ gd->bg_inode_bitmap = ibmpos;
+ gd->bg_inode_table = itblpos;
+ }
+
+ /* Mark non-filesystem blocks and inodes as allocated */
+ /* Mark system blocks and inodes as allocated */
+ for(i = 0; i<nbgroups;i++) {
+
+ /* Block bitmap */
+ bbm = GRP_GET_GROUP_BBM(fs, i);
+ //non-filesystem blocks
+ for(j = get_gd(fs, i)->bg_free_blocks_count
+ + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
+ allocate(bbm, j);
+ //system blocks
+ for(j = 1; j <= overhead_per_group; j++)
+ allocate(bbm, j);
+
+ /* Inode bitmap */
+ ibm = GRP_GET_GROUP_IBM(fs, i);
+ //non-filesystem inodes
+ for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
+ allocate(ibm, j);
+
+ //system inodes
+ if(i == 0)
+ for(j = 1; j < EXT2_FIRST_INO; j++)
+ allocate(ibm, j);
+ }
+
+ // make root inode and directory
+ /* We have groups now. Add the root filesystem in group 0 */
+ /* Also increment the directory count for group 0 */
+ get_gd(fs, 0)->bg_free_inodes_count--;
+ get_gd(fs, 0)->bg_used_dirs_count = 1;
+ itab0 = (inode *)get_blk(fs, get_gd(fs,0)->bg_inode_table);
+ itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
+ itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
+ itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
+ itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
+ itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
+ itab0[EXT2_ROOT_INO-1].i_links_count = 2;
+
+ if(!(b = get_workblk()))
+ error_msg_and_die("get_workblk() failed.");
+ d = (directory*)b;
+ d->d_inode = EXT2_ROOT_INO;
+ d->d_rec_len = sizeof(directory)+4;
+ d->d_name_len = 1;
+ strcpy(d->d_name, ".");
+ d = (directory*)(b + d->d_rec_len);
+ d->d_inode = EXT2_ROOT_INO;
+ d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
+ d->d_name_len = 2;
+ strcpy(d->d_name, "..");
+ extend_blk(fs, EXT2_ROOT_INO, b, 1);
+
+ // make lost+found directory and reserve blocks
+ if(fs->sb.s_r_blocks_count)
+ {
+ nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
+ memset(b, 0, BLOCKSIZE);
+ ((directory*)b)->d_rec_len = BLOCKSIZE;
+ /* We run into problems with e2fsck if directory lost+found grows
+ * bigger than this. Need to find out why this happens - sundar
+ */
+ if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
+ fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
+ for(i = 1; i < fs->sb.s_r_blocks_count; i++)
+ extend_blk(fs, nod, b, 1);
+ get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
+ }
+ free_workblk(b);
+
+ // administrative info
+ fs->sb.s_state = 1;
+ fs->sb.s_max_mnt_count = 20;
+
+ // options for me
+ if(holes)
+ fs->sb.s_reserved[200] |= OP_HOLES;
+
+ return fs;
+}
+
+// loads a filesystem from disk
+static filesystem *
+load_fs(FILE * fh, int swapit)
+{
+ size_t fssize;
+ filesystem *fs;
+ if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
+ perror_msg_and_die("input filesystem image");
+ rewind(fh);
+ fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
+ if(fssize < 16) // totally arbitrary
+ error_msg_and_die("too small filesystem");
+ if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
+ error_msg_and_die("not enough memory for filesystem");
+ if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
+ perror_msg_and_die("input filesystem image");
+ if(swapit)
+ swap_badfs(fs);
+ if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
+ error_msg_and_die("not a suitable ext2 filesystem");
+ return fs;
+}
+
+static void
+free_fs(filesystem *fs)
+{
+ free(fs);
+}
+
+// just walk through blocks list
+static void
+flist_blocks(filesystem *fs, uint32 nod, FILE *fh)
+{
+ blockwalker bw;
+ uint32 bk;
+ init_bw(&bw);
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ fprintf(fh, " %d", bk);
+ fprintf(fh, "\n");
+}
+
+// walk through blocks list
+static void
+list_blocks(filesystem *fs, uint32 nod)
+{
+ int bn = 0;
+ blockwalker bw;
+ uint32 bk;
+ init_bw(&bw);
+ printf("blocks in inode %d:", nod);
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ printf(" %d", bk), bn++;
+ printf("\n%d blocks (%d bytes)\n", bn, bn * BLOCKSIZE);
+}
+
+// saves blocks to FILE*
+static void
+write_blocks(filesystem *fs, uint32 nod, FILE* f)
+{
+ blockwalker bw;
+ uint32 bk;
+ int32 fsize = get_nod(fs, nod)->i_size;
+ init_bw(&bw);
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ {
+ if(fsize <= 0)
+ error_msg_and_die("wrong size while saving inode %d", nod);
+ if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
+ error_msg_and_die("error while saving inode %d", nod);
+ fsize -= BLOCKSIZE;
+ }
+}
+
+
+// print block/char device minor and major
+static void
+print_dev(filesystem *fs, uint32 nod)
+{
+ int minor, major;
+ minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
+ major = ((uint8*)get_nod(fs, nod)->i_block)[1];
+ printf("major: %d, minor: %d\n", major, minor);
+}
+
+// print an inode as a directory
+static void
+print_dir(filesystem *fs, uint32 nod)
+{
+ blockwalker bw;
+ uint32 bk;
+ init_bw(&bw);
+ printf("directory for inode %d:\n", nod);
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ {
+ directory *d;
+ uint8 *b;
+ b = get_blk(fs, bk);
+ for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
+ if(d->d_inode)
+ {
+ int i;
+ printf("entry '");
+ for(i = 0; i < d->d_name_len; i++)
+ putchar(d->d_name[i]);
+ printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
+ }
+ }
+}
+
+// print a symbolic link
+static void
+print_link(filesystem *fs, uint32 nod)
+{
+ if(!get_nod(fs, nod)->i_blocks)
+ printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
+ else
+ {
+ printf("links to '");
+ write_blocks(fs, nod, stdout);
+ printf("'\n");
+ }
+}
+
+// make a ls-like printout of permissions
+static void
+make_perms(uint32 mode, char perms[11])
+{
+ strcpy(perms, "----------");
+ if(mode & FM_IRUSR)
+ perms[1] = 'r';
+ if(mode & FM_IWUSR)
+ perms[2] = 'w';
+ if(mode & FM_IXUSR)
+ perms[3] = 'x';
+ if(mode & FM_IRGRP)
+ perms[4] = 'r';
+ if(mode & FM_IWGRP)
+ perms[5] = 'w';
+ if(mode & FM_IXGRP)
+ perms[6] = 'x';
+ if(mode & FM_IROTH)
+ perms[7] = 'r';
+ if(mode & FM_IWOTH)
+ perms[8] = 'w';
+ if(mode & FM_IXOTH)
+ perms[9] = 'x';
+ if(mode & FM_ISUID)
+ perms[3] = 's';
+ if(mode & FM_ISGID)
+ perms[6] = 's';
+ if(mode & FM_ISVTX)
+ perms[9] = 't';
+ switch(mode & FM_IFMT)
+ {
+ case 0:
+ *perms = '0';
+ break;
+ case FM_IFSOCK:
+ *perms = 's';
+ break;
+ case FM_IFLNK:
+ *perms = 'l';
+ break;
+ case FM_IFREG:
+ *perms = '-';
+ break;
+ case FM_IFBLK:
+ *perms = 'b';
+ break;
+ case FM_IFDIR:
+ *perms = 'd';
+ break;
+ case FM_IFCHR:
+ *perms = 'c';
+ break;
+ case FM_IFIFO:
+ *perms = 'p';
+ break;
+ default:
+ *perms = '?';
+ }
+}
+
+// print an inode
+static void
+print_inode(filesystem *fs, uint32 nod)
+{
+ char *s;
+ char perms[11];
+ if(!get_nod(fs, nod)->i_mode)
+ return;
+ switch(nod)
+ {
+ case EXT2_BAD_INO:
+ s = "bad blocks";
+ break;
+ case EXT2_ROOT_INO:
+ s = "root";
+ break;
+ case EXT2_ACL_IDX_INO:
+ case EXT2_ACL_DATA_INO:
+ s = "ACL";
+ break;
+ case EXT2_BOOT_LOADER_INO:
+ s = "boot loader";
+ break;
+ case EXT2_UNDEL_DIR_INO:
+ s = "undelete directory";
+ break;
+ default:
+ s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
+ }
+ printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
+ if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
+ {
+ printf("unallocated\n");
+ return;
+ }
+ make_perms(get_nod(fs, nod)->i_mode, perms);
+ printf("%s, size: %d byte%s (%d block%s)\n", perms, plural(get_nod(fs, nod)->i_size), plural(get_nod(fs, nod)->i_blocks / INOBLK));
+ switch(get_nod(fs, nod)->i_mode & FM_IFMT)
+ {
+ case FM_IFSOCK:
+ list_blocks(fs, nod);
+ break;
+ case FM_IFLNK:
+ print_link(fs, nod);
+ break;
+ case FM_IFREG:
+ list_blocks(fs, nod);
+ break;
+ case FM_IFBLK:
+ print_dev(fs, nod);
+ break;
+ case FM_IFDIR:
+ list_blocks(fs, nod);
+ print_dir(fs, nod);
+ break;
+ case FM_IFCHR:
+ print_dev(fs, nod);
+ break;
+ case FM_IFIFO:
+ list_blocks(fs, nod);
+ break;
+ default:
+ list_blocks(fs, nod);
+ }
+ printf("Done with inode %d\n",nod);
+}
+
+// describes various fields in a filesystem
+static void
+print_fs(filesystem *fs)
+{
+ uint32 i;
+ uint8 *ibm;
+
+ printf("%d blocks (%d free, %d reserved), first data block: %d\n",
+ fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
+ fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
+ printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
+ fs->sb.s_free_inodes_count);
+ printf("block size = %d, frag size = %d\n",
+ fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
+ fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
+ printf("number of groups: %d\n",GRP_NBGROUPS(fs));
+ printf("%d blocks per group,%d frags per group,%d inodes per group\n",
+ fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
+ fs->sb.s_inodes_per_group);
+ printf("Size of inode table: %d blocks\n",
+ (int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
+ for (i = 0; i < GRP_NBGROUPS(fs); i++) {
+ printf("Group No: %d\n", i+1);
+ printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
+ get_gd(fs, i)->bg_block_bitmap,
+ get_gd(fs, i)->bg_inode_bitmap,
+ get_gd(fs, i)->bg_inode_table);
+ printf("block bitmap allocation:\n");
+ print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
+ printf("inode bitmap allocation:\n");
+ ibm = GRP_GET_GROUP_IBM(fs, i);
+ print_bm(ibm, fs->sb.s_inodes_per_group);
+ for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
+ if (allocated(ibm, i))
+ print_inode(fs, i);
+ }
+}
+
+static void
+dump_fs(filesystem *fs, FILE * fh, int swapit)
+{
+ uint32 nbblocks = fs->sb.s_blocks_count;
+ fs->sb.s_reserved[200] = 0;
+ if(swapit)
+ swap_goodfs(fs);
+ if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
+ perror_msg_and_die("output filesystem image");
+ if(swapit)
+ swap_badfs(fs);
+}
+
+static void
+populate_fs(filesystem *fs, char **dopt, int didx, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats)
+{
+ int i;
+ for(i = 0; i < didx; i++)
+ {
+ struct stat st;
+ FILE *fh;
+ int pdir;
+ char *pdest;
+ uint32 nod = EXT2_ROOT_INO;
+ if(fs)
+ if((pdest = strchr(dopt[i], ':')))
+ {
+ *(pdest++) = 0;
+ if(!(nod = find_path(fs, EXT2_ROOT_INO, pdest)))
+ error_msg_and_die("path %s not found in filesystem", pdest);
+ }
+ stat(dopt[i], &st);
+ switch(st.st_mode & S_IFMT)
+ {
+ case S_IFREG:
+ fh = xfopen(dopt[i], "rb");
+ add2fs_from_file(fs, nod, fh, fs_timestamp, stats);
+ fclose(fh);
+ break;
+ case S_IFDIR:
+ if((pdir = open(".", O_RDONLY)) < 0)
+ perror_msg_and_die(".");
+ if(chdir(dopt[i]) < 0)
+ perror_msg_and_die(dopt[i]);
+ add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
+ if(fchdir(pdir) < 0)
+ perror_msg_and_die("fchdir");
+ if(close(pdir) < 0)
+ perror_msg_and_die("close");
+ break;
+ default:
+ error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
+ }
+ }
+}
+
+static void
+showversion(void)
+{
+ printf("genext2fs " VERSION "\n");
+}
+
+static void
+showhelp(void)
+{
+ fprintf(stderr, "Usage: %s [options] image\n"
+ "Create an ext2 filesystem image from directories/files\n\n"
+ " -x, --starting-image <image>\n"
+ " -d, --root <directory>\n"
+ " -D, --devtable <file>\n"
+ " -B, --block-size <bytes>\n"
+ " -b, --size-in-blocks <blocks>\n"
+ " -i, --bytes-per-inode <bytes per inode>\n"
+ " -N, --number-of-inodes <number of inodes>\n"
+ " -m, --reserved-percentage <percentage of blocks to reserve>\n"
+ " -o, --creator-os <os> 'linux', 'hurd', 'freebsd' or a numerical value.\n"
+ " -g, --block-map <path> Generate a block map file for this path.\n"
+ " -e, --fill-value <value> Fill unallocated blocks with value.\n"
+ " -z, --allow-holes Allow files with holes.\n"
+ " -f, --faketime Set filesystem timestamps to 0 (for testing).\n"
+ " -q, --squash Same as \"-U -P\".\n"
+ " -U, --squash-uids Squash owners making all files be owned by root.\n"
+ " -P, --squash-perms Squash permissions on all files.\n"
+ " -h, --help\n"
+ " -V, --version\n"
+ " -v, --verbose\n\n"
+ "Report bugs to genext2fs-devel@lists.sourceforge.net\n", app_name);
+}
+
+#define MAX_DOPT 128
+#define MAX_GOPT 128
+
+#define MAX_FILENAME 255
+
+extern char* optarg;
+extern int optind, opterr, optopt;
+
+// parse the value for -o <os>
+int
+lookup_creator_os(const char *name)
+{
+ static const char *const creators[] =
+ {"linux", "hurd", "2", "freebsd", NULL};
+ char *endptr;
+ int i;
+
+ // numerical value ?
+ i = strtol(name, &endptr, 0);
+ if(name[0] && *endptr == '\0')
+ return i;
+
+ // symbolic name ?
+ for(i=0; creators[i]; i++)
+ if(strcasecmp(creators[i], name) == 0)
+ return i;
+
+ // whatever ?
+ return -1;
+}
+
+int
+main(int argc, char **argv)
+{
+ int nbblocks = -1;
+ int nbinodes = -1;
+ int nbresrvd = -1;
+ float bytes_per_inode = -1;
+ float reserved_frac = -1;
+ int fs_timestamp = -1;
+ int creator_os = CREATOR_OS;
+ char * fsout = "-";
+ char * fsin = 0;
+ char * dopt[MAX_DOPT];
+ int didx = 0;
+ char * gopt[MAX_GOPT];
+ int gidx = 0;
+ int verbose = 0;
+ int holes = 0;
+ int emptyval = 0;
+ int squash_uids = 0;
+ int squash_perms = 0;
+ uint16 endian = 1;
+ int bigendian = !*(char*)&endian;
+ filesystem *fs;
+ int i;
+ int c;
+ struct stats stats;
+
+#if HAVE_GETOPT_LONG
+ struct option longopts[] = {
+ { "starting-image", required_argument, NULL, 'x' },
+ { "root", required_argument, NULL, 'd' },
+ { "devtable", required_argument, NULL, 'D' },
+ { "block-size", required_argument, NULL, 'B' },
+ { "size-in-blocks", required_argument, NULL, 'b' },
+ { "bytes-per-inode", required_argument, NULL, 'i' },
+ { "number-of-inodes", required_argument, NULL, 'N' },
+ { "reserved-percentage", required_argument, NULL, 'm' },
+ { "creator-os", required_argument, NULL, 'o' },
+ { "block-map", required_argument, NULL, 'g' },
+ { "fill-value", required_argument, NULL, 'e' },
+ { "allow-holes", no_argument, NULL, 'z' },
+ { "faketime", no_argument, NULL, 'f' },
+ { "squash", no_argument, NULL, 'q' },
+ { "squash-uids", no_argument, NULL, 'U' },
+ { "squash-perms", no_argument, NULL, 'P' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { 0, 0, 0, 0}
+ } ;
+
+ app_name = argv[0];
+
+ while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
+#else
+ app_name = argv[0];
+
+ while((c = getopt(argc, argv, "x:d:D:B:b:i:N:m:o:g:e:zfqUPhVv")) != EOF) {
+#endif /* HAVE_GETOPT_LONG */
+ switch(c)
+ {
+ case 'x':
+ fsin = optarg;
+ break;
+ case 'd':
+ case 'D':
+ dopt[didx++] = optarg;
+ break;
+ case 'B':
+ blocksize = SI_atof(optarg);
+ break;
+ case 'b':
+ nbblocks = SI_atof(optarg);
+ break;
+ case 'i':
+ bytes_per_inode = SI_atof(optarg);
+ break;
+ case 'N':
+ nbinodes = SI_atof(optarg);
+ break;
+ case 'm':
+ reserved_frac = SI_atof(optarg) / 100;
+ break;
+ case 'o':
+ creator_os = lookup_creator_os(optarg);
+ break;
+ case 'g':
+ gopt[gidx++] = optarg;
+ break;
+ case 'e':
+ emptyval = atoi(optarg);
+ break;
+ case 'z':
+ holes = 1;
+ break;
+ case 'f':
+ fs_timestamp = 0;
+ break;
+ case 'q':
+ squash_uids = 1;
+ squash_perms = 1;
+ break;
+ case 'U':
+ squash_uids = 1;
+ break;
+ case 'P':
+ squash_perms = 1;
+ break;
+ case 'h':
+ showhelp();
+ exit(0);
+ case 'V':
+ showversion();
+ exit(0);
+ case 'v':
+ verbose = 1;
+ showversion();
+ break;
+ default:
+ error_msg_and_die("Note: options have changed, see --help or the man page.");
+ }
+ }
+
+ if(optind < (argc - 1))
+ error_msg_and_die("Too many arguments. Try --help or else see the man page.");
+ if(optind > (argc - 1))
+ error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
+ fsout = argv[optind];
+
+ if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
+ error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
+ if(creator_os < 0)
+ error_msg_and_die("Creator OS unknown.");
+
+ hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
+ if (!hdlinks.hdl)
+ error_msg_and_die("Not enough memory");
+ hdlinks.count = 0 ;
+
+ if(fsin)
+ {
+ if(strcmp(fsin, "-"))
+ {
+ FILE * fh = xfopen(fsin, "rb");
+ fs = load_fs(fh, bigendian);
+ fclose(fh);
+ }
+ else
+ fs = load_fs(stdin, bigendian);
+ }
+ else
+ {
+ if(reserved_frac == -1)
+ nbresrvd = nbblocks * RESERVED_BLOCKS;
+ else
+ nbresrvd = nbblocks * reserved_frac;
+
+ stats.ninodes = EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0);
+ stats.nblocks = 0;
+
+ populate_fs(NULL, dopt, didx, squash_uids, squash_perms, fs_timestamp, &stats);
+
+ if(nbinodes == -1)
+ nbinodes = stats.ninodes;
+ else
+ if(stats.ninodes > (unsigned long)nbinodes)
+ {
+ fprintf(stderr, "number of inodes too low, increasing to %ld\n", stats.ninodes);
+ nbinodes = stats.ninodes;
+ }
+
+ if(bytes_per_inode != -1) {
+ int tmp_nbinodes = nbblocks * BLOCKSIZE / bytes_per_inode;
+ if(tmp_nbinodes > nbinodes)
+ nbinodes = tmp_nbinodes;
+ }
+ if(fs_timestamp == -1)
+ fs_timestamp = time(NULL);
+ fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
+ fs_timestamp, creator_os);
+ }
+
+ populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
+
+ if(emptyval) {
+ uint32 b;
+ for(b = 1; b < fs->sb.s_blocks_count; b++)
+ if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
+ memset(get_blk(fs, b), emptyval, BLOCKSIZE);
+ }
+ if(verbose)
+ print_fs(fs);
+ for(i = 0; i < gidx; i++)
+ {
+ uint32 nod;
+ char fname[MAX_FILENAME];
+ char *p;
+ FILE *fh;
+ if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
+ error_msg_and_die("path %s not found in filesystem", gopt[i]);
+ while((p = strchr(gopt[i], '/')))
+ *p = '_';
+ SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
+ fh = xfopen(fname, "wb");
+ fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
+ flist_blocks(fs, nod, fh);
+ fclose(fh);
+ }
+ if(strcmp(fsout, "-"))
+ {
+ FILE * fh = xfopen(fsout, "wb");
+ dump_fs(fs, fh, bigendian);
+ fclose(fh);
+ }
+ else
+ dump_fs(fs, stdout, bigendian);
+ free_fs(fs);
+ return 0;
+}
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-gen.lib
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-gen.lib (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-gen.lib (revision 5)
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# These routines contain the filesystem generation code.
+# This code is sourced by the other scripts so that digest
+# generation is consistent.
+
+# dgen - Exercises the -d directory option of genext2fs
+# Creates an image with a file of given size
+# Usage: dgen file-size number-of-blocks
+dgen () {
+ size=$1; blocks=$2; blocksz=$3;
+ rm -rf test
+ mkdir -p test
+ cd test
+ if [ x$size = x0 ]; then
+ > file.$1
+ else
+ dd if=/dev/zero of=file.$1 bs=$size count=1 2>/dev/null
+ fi
+ chmod 777 file.$1
+ TZ=UTC-11 touch -t 200502070321.43 file.$1 .
+ cd ..
+ ./genext2fs -B $blocksz -N 17 -b $blocks -d test -f -o Linux -q ext2.img
+}
+
+# fgen - Exercises the -f spec-file option of genext2fs
+# Creates an image with the devices mentioned in the given spec file
+# Usage: fgen spec-file number-of-blocks
+fgen () {
+ fname=$1; blocks=$2;
+ mkdir -p test
+ cp $fname test
+ TZ=UTC-11 touch -t 200502070321.43 test/$fname
+ ./genext2fs -N 92 -b $blocks -D test/$fname -f -o Linux ext2.img
+}
+
+# gen_cleanup - Remove the files generated by the above functions
+# Usage: gen_cleanup
+gen_cleanup () {
+ rm -rf ext2.img test
+}
+
+# calc_digest - Return the MD5 digest of the test image
+# Usage: calc_digest
+calc_digest () {
+ digest=`md5sum ext2.img 2>/dev/null | cut -f 1 -d " "`
+ if [ x$digest != x ] ; then
+ echo $digest
+ else
+ digest=`md5 ext2.img 2>/dev/null | cut -f 4 -d " "`
+ echo $digest
+ fi
+}
+
+LC_ALL=C
+export LC_ALL
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-mount.sh
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-mount.sh (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-mount.sh (revision 5)
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+# Use this script if you need to regenerate the digest values
+# in test.sh, or if you don't care about digests and you just
+# want to see some fsck results. Should be run as root.
+
+set -e
+
+. ./test-gen.lib
+
+test_cleanup () {
+ umount mnt 2>/dev/null || true
+ rm -rf mnt fout lsout
+}
+
+fail () {
+ echo FAILED
+ test_cleanup
+ gen_cleanup
+ exit 1
+}
+
+pass () {
+ md5=`calc_digest`
+ echo PASSED
+ echo $@ $md5
+ test_cleanup
+ gen_cleanup
+}
+
+# dtest-mount - Exercise the -d directory option of genext2fs
+# Creates an image with a file of given size, verifies it
+# and returns the command line with which to invoke dtest()
+# Usage: dtest-mount file-size number-of-blocks
+dtest_mount () {
+ size=$1; blocks=$2; blocksz=$3;
+ echo Testing $blocks blocks of $blocksz bytes with file of size $size
+ dgen $size $blocks $blocksz
+ /sbin/e2fsck -fn ext2.img || fail
+ mkdir -p mnt
+ mount -t ext2 -o ro,loop ext2.img mnt || fail
+ if (! [ -f mnt/file.$size ]) || \
+ [ $size != "`ls -al mnt | grep file.$size |
+ awk '{print $5}'`" ] ; then
+ fail
+ fi
+ pass dtest $size $blocks $blocksz
+}
+
+# ftest-mount - Exercise the -f spec-file option of genext2fs
+# Creates an image with the devices mentioned in the given spec
+# file, verifies it, and returns the command line with which to
+# invoke ftest()
+# Usage: ftest-mount spec-file number-of-blocks
+ftest_mount () {
+ fname=$1; blocks=$2
+ echo Testing with devices file $fname
+ fgen $fname $blocks
+ /sbin/e2fsck -fn ext2.img || fail
+ mkdir -p mnt
+ mount -t ext2 -o ro,loop ext2.img mnt || fail
+ [ -d mnt/dev ] || fail
+ # Exclude those devices that have interpolated
+ # minor numbers, as being too hard to match.
+ egrep -v "(hda|hdb|tty|loop|ram|ubda)" $fname | \
+ grep '^[^ #]* [bc]' | \
+ awk '{print $1,$4,$5,$6","$7}'| \
+ sort -d -k3.6 > fout
+ ls -aln mnt/dev | \
+ egrep -v "(hda|hdb|tty|loop|ram|ubda)" | \
+ grep ^[bc] | \
+ awk '{ print "/dev/"$10,$3,$4,$5$6}' | \
+ sort -d -k3.6 > lsout
+ diff fout lsout || fail
+ pass ftest $fname $blocks
+}
+
+dtest_mount 0 4096 1024
+dtest_mount 0 2048 2048
+dtest_mount 0 1024 4096
+dtest_mount 0 8193 1024
+dtest_mount 0 8194 1024
+dtest_mount 0 8193 4096
+dtest_mount 0 8194 2048
+dtest_mount 1 4096 1024
+dtest_mount 1 1024 4096
+dtest_mount 12288 4096 1024
+dtest_mount 274432 4096 1024
+dtest_mount 8388608 9000 1024
+dtest_mount 8388608 4500 2048
+dtest_mount 8388608 2250 4096
+dtest_mount 16777216 20000 1024
+dtest_mount 16777216 10000 2048
+
+ftest_mount device_table.txt 4096
Property changes on: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test-mount.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test.sh
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test.sh (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test.sh (revision 5)
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# This script generates a variety of filesystems and checks that they
+# are identical to ones that are known to be mountable, and pass fsck
+# and various other sanity checks.
+
+# Passing these tests is preferable to passing test-mount.sh because
+# this script doesn't require root, and because passing these tests
+# guarantees byte-for-byte agreement with other builds, ports,
+# architectures, times of day etc.
+
+set -e
+
+. ./test-gen.lib
+
+# md5cmp - Calculate MD5 digest and compare it to an expected value.
+# Usage: md5cmp expected-digest
+md5cmp () {
+ checksum=$1
+ md5=`calc_digest`
+ if [ x$md5 = x$checksum ] ; then
+ echo PASSED
+ else
+ echo FAILED
+ exit 1
+ fi
+}
+
+# dtest - Exercises the -d directory option of genext2fs
+# Creates an image with a file of given size and verifies it
+# Usage: dtest file-size number-of-blocks correct-checksum
+dtest () {
+ size=$1; blocks=$2; blocksz=$3; checksum=$4
+ echo Testing with file of size $size
+ dgen $size $blocks $blocksz
+ md5cmp $checksum
+ gen_cleanup
+}
+
+# ftest - Exercises the -f spec-file option of genext2fs
+# Creates an image with the devices mentioned in the given spec
+# file and verifies it
+# Usage: ftest spec-file number-of-blocks correct-checksum
+ftest () {
+ fname=$1; blocks=$2; checksum=$3
+ echo Testing with devices file $fname
+ fgen $fname $blocks
+ md5cmp $checksum
+ gen_cleanup
+}
+
+# NB: to regenerate these values, always use test-mount.sh, that is,
+# replace the following lines with the output of
+# sudo sh test-mount.sh|grep test
+
+dtest 0 4096 1024 3bc6424b8fcd51a0de34ee59d91d5f16
+dtest 0 2048 2048 230afa16496df019878cc2370c661cdc
+dtest 0 1024 4096 ebff5eeb38b70f3f1cd081e60eb44561
+dtest 0 8193 1024 f174804f6b433b552706cbbfc60c416d
+dtest 0 8194 1024 4855a55d0cbdc44584634df49ebd5711
+dtest 0 8193 4096 c493679698418ec7e6552005e2d2a6d8
+dtest 0 8194 2048 ec13f328fa7543563f35f494bddc059c
+dtest 1 4096 1024 09c569b6bfb45222c729c42d04d5451f
+dtest 1 1024 4096 d318a326fdc907810ae9e6b0a20e9b06
+dtest 12288 4096 1024 61febcbfbf32024ef99103fcdc282c39
+dtest 274432 4096 1024 0c517803552c55c1806e4220b0a0164f
+dtest 8388608 9000 1024 e0e5ea15bced10ab486d8135584b5d8e
+dtest 8388608 4500 2048 39f4d537a72f5053fd6891721c59680d
+dtest 8388608 2250 4096 1d697fa4bc2cfffe02ac91edfadc40bf
+dtest 16777216 20000 1024 fdf636eb905ab4dc1bf76dce5ac5d209
+dtest 16777216 10000 2048 f9824a81ea5e74fdf469c097927c292b
+ftest device_table.txt 4096 a0af06d944b11d2902dfd705484c64cc
Property changes on: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new/test.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new
===================================================================
--- create-1.4.1-blocksize-patch/genext2fs-1.4.1-new (nonexistent)
+++ create-1.4.1-blocksize-patch/genext2fs-1.4.1-new (revision 5)
Property changes on: create-1.4.1-blocksize-patch/genext2fs-1.4.1-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: create-1.4.1-blocksize-patch
===================================================================
--- create-1.4.1-blocksize-patch (nonexistent)
+++ create-1.4.1-blocksize-patch (revision 5)
Property changes on: create-1.4.1-blocksize-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: create-1.4.1-configure-patch/create.patch.sh
===================================================================
--- create-1.4.1-configure-patch/create.patch.sh (nonexistent)
+++ create-1.4.1-configure-patch/create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=1.4.1
+
+tar --files-from=file.list -xzvf ../genext2fs-$VERSION.tar.gz
+mv genext2fs-$VERSION genext2fs-$VERSION-orig
+
+cp -rf ./genext2fs-$VERSION-new ./genext2fs-$VERSION
+
+diff -b --unified -Nr genext2fs-$VERSION-orig genext2fs-$VERSION > genext2fs-$VERSION-configure.patch
+
+mv genext2fs-$VERSION-configure.patch ../patches
+
+rm -rf ./genext2fs-$VERSION
+rm -rf ./genext2fs-$VERSION-orig
Property changes on: create-1.4.1-configure-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-1.4.1-configure-patch/file.list
===================================================================
--- create-1.4.1-configure-patch/file.list (nonexistent)
+++ create-1.4.1-configure-patch/file.list (revision 5)
@@ -0,0 +1,2 @@
+genext2fs-1.4.1/configure.in
+genext2fs-1.4.1/m4/ac_func_scanf_can_malloc.m4
Index: create-1.4.1-configure-patch/genext2fs-1.4.1-new/configure.ac
===================================================================
--- create-1.4.1-configure-patch/genext2fs-1.4.1-new/configure.ac (nonexistent)
+++ create-1.4.1-configure-patch/genext2fs-1.4.1-new/configure.ac (revision 5)
@@ -0,0 +1,41 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([genext2fs],[1.4.1])
+
+builtin(include, [m4/ac_func_snprintf.m4])dnl
+builtin(include, [m4/ac_func_scanf_can_malloc.m4])dnl
+
+AM_INIT_AUTOMAKE([subdir-objects no-dist-gzip dist-xz])
+AC_CONFIG_HEADERS([config.h])
+
+AC_GNU_SOURCE
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+
+# Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_MAJOR
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h memory.h stddef.h stdint.h stdlib.h string.h strings.h unistd.h])
+AC_CHECK_HEADERS([libgen.h getopt.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_C_INLINE
+AC_CHECK_TYPE(size_t, unsigned)
+AC_CHECK_TYPE(ssize_t, signed)
+AC_CHECK_MEMBERS([struct stat.st_rdev])
+
+# Checks for library functions.
+AC_CHECK_FUNCS([getopt_long getline strtof])
+AC_FUNC_SNPRINTF
+AC_FUNC_SCANF_CAN_MALLOC
+
+AC_OUTPUT([Makefile],[
+chmod a+x $ac_top_srcdir/test-mount.sh $ac_top_srcdir/test.sh
+])
Index: create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4/ac_func_scanf_can_malloc.m4
===================================================================
--- create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4/ac_func_scanf_can_malloc.m4 (nonexistent)
+++ create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4/ac_func_scanf_can_malloc.m4 (revision 5)
@@ -0,0 +1,53 @@
+dnl AC_FUNC_SCANF_CAN_MALLOC macro
+dnl
+dnl (c) Finn Thain 2006
+dnl Copying and distribution of this file, with or without modification,
+dnl are permitted in any medium without royalty provided the copyright
+dnl notice and this notice are preserved.
+
+# AC_FUNC_SCANF_CAN_MALLOC()
+# --------------------------------------
+AC_DEFUN([AC_FUNC_SCANF_CAN_MALLOC],
+ [ AC_CHECK_HEADERS([stdlib.h])
+ AC_CACHE_CHECK([whether scanf can malloc], [ac_cv_func_scanf_can_malloc],
+ [ AC_RUN_IFELSE(
+ [ AC_LANG_PROGRAM(
+ [
+#include <stdio.h>
+#if STDC_HEADERS || HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+ ], [
+ union { float f; char *p; } u;
+ char *p;
+ u.f = 0;
+ char *scan_this = "56789";
+ int matched = sscanf(scan_this, "%as", &u);
+ if(matched < 1) return 1; /* shouldn't happens */
+ if(u.f == (float)56789) return 2;
+
+ p = u.p;
+ while(*scan_this && *p == *scan_this) {
+ ++p;
+ ++scan_this;
+ };
+ free(u.p);
+ if(*scan_this == 0) return 0;
+ return 3;
+ ])
+ ],
+ [ac_scanf_can_malloc=yes],
+ [ac_scanf_can_malloc=no],
+ [
+case $host_alias in
+ *-*-linux* ) ac_scanf_can_malloc=yes ;;
+ *-*-solaris* ) ac_scanf_can_malloc=no ;;
+ *-*-darwin* ) ac_scanf_can_malloc=no ;;
+ * ) ac_scanf_can_malloc=no ;;
+esac
+ ])
+ ])
+if test x$ac_scanf_can_malloc = "xyes"; then
+ AC_DEFINE([SCANF_CAN_MALLOC], 1, [Define to 1 if the scanf %a conversion format mallocs a buffer. Undefine if %a format denotes a float.])
+fi
+ ])
Index: create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4
===================================================================
--- create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4 (nonexistent)
+++ create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4 (revision 5)
Property changes on: create-1.4.1-configure-patch/genext2fs-1.4.1-new/m4
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: create-1.4.1-configure-patch/genext2fs-1.4.1-new
===================================================================
--- create-1.4.1-configure-patch/genext2fs-1.4.1-new (nonexistent)
+++ create-1.4.1-configure-patch/genext2fs-1.4.1-new (revision 5)
Property changes on: create-1.4.1-configure-patch/genext2fs-1.4.1-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: create-1.4.1-configure-patch
===================================================================
--- create-1.4.1-configure-patch (nonexistent)
+++ create-1.4.1-configure-patch (revision 5)
Property changes on: create-1.4.1-configure-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README (nonexistent)
+++ patches/README (revision 5)
@@ -0,0 +1,10 @@
+
+/* begin *
+
+ genext2fs-1.4.1-blocksize.patch - adds the two options to set block size and CREATOR_OS.
+ Also the two duncrions swap_goodblocks() [line: 1751]
+ and swap_badblocks() [line: 1810] are fixed;
+
+ genext2fs-1.4.1-configure.patch - changes according to new version of autotools.
+
+ * end */
Index: patches
===================================================================
--- patches (nonexistent)
+++ patches (revision 5)
Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,51 ##
+
+# local config & object files
+build-config.mk
+sbin
+usr
+var
+
+# configure targets
+autom4te.cache
+.config
+config.log
+config.status
+configure
+
+# cpan configure targets
+.installed
+CPAN-Config.pm
+CPAN-install
+
+# Target build dirs
+.build-machine
+
+# Timestamps
+.makefile
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Object Files
+*.[ao]
+
+# backup copies
+*~