Home | History | Annotate | Download | only in genext2fs
      1 /* vi: set sw=8 ts=8: */
      2 // genext2fs.c
      3 //
      4 // ext2 filesystem generator for embedded systems
      5 // Copyright (C) 2000 Xavier Bestel <xavier.bestel (at) free.fr>
      6 //
      7 // Please direct support requests to genext2fs-devel (at) lists.sourceforge.net
      8 //
      9 // 'du' portions taken from coreutils/du.c in busybox:
     10 //	Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
     11 //	Copyright (C) 1999,2000,2001 by John Beppu <beppu (at) codepoet.org>
     12 //	Copyright (C) 2002  Edward Betts <edward (at) debian.org>
     13 //
     14 // This program is free software; you can redistribute it and/or
     15 // modify it under the terms of the GNU General Public License
     16 // as published by the Free Software Foundation; version
     17 // 2 of the License.
     18 //
     19 // Changes:
     20 // 	 3 Jun 2000	Initial release
     21 // 	 6 Jun 2000	Bugfix: fs size multiple of 8
     22 // 			Bugfix: fill blocks with inodes
     23 // 	14 Jun 2000	Bugfix: bad chdir() with -d option
     24 // 			Bugfix: removed size=8n constraint
     25 // 			Changed -d file to -f file
     26 // 			Added -e option
     27 // 	22 Jun 2000	Changed types for 64bits archs
     28 // 	24 Jun 2000	Added endianness swap
     29 // 			Bugfix: bad dir name lookup
     30 // 	03 Aug 2000	Bugfix: ind. blocks endian swap
     31 // 	09 Aug 2000	Bugfix: symlinks endian swap
     32 // 	01 Sep 2000	Bugfix: getopt returns int, not char	proski (at) gnu.org
     33 // 	10 Sep 2000	Bugfix: device nodes endianness		xavier.gueguen (at) col.bsf.alcatel.fr
     34 // 			Bugfix: getcwd values for Solaris	xavier.gueguen (at) col.bsf.alcatel.fr
     35 // 			Bugfix: ANSI scanf for non-GNU C	xavier.gueguen (at) col.bsf.alcatel.fr
     36 // 	28 Jun 2001	Bugfix: getcwd differs for Solaris/GNU	mike (at) sowbug.com
     37 // 	 8 Mar 2002	Bugfix: endianness swap of x-indirects
     38 // 	23 Mar 2002	Bugfix: test for IFCHR or IFBLK was flawed
     39 // 	10 Oct 2002	Added comments,makefile targets,	vsundar (at) ixiacom.com
     40 // 			endianess swap assert check.
     41 // 			Copyright (C) 2002 Ixia communications
     42 // 	12 Oct 2002	Added support for triple indirection	vsundar (at) ixiacom.com
     43 // 			Copyright (C) 2002 Ixia communications
     44 // 	14 Oct 2002	Added support for groups		vsundar (at) ixiacom.com
     45 // 			Copyright (C) 2002 Ixia communications
     46 // 	 5 Jan 2003	Bugfixes: reserved inodes should be set vsundar (at) usc.edu
     47 // 			only in the first group; directory names
     48 // 			need to be null padded at the end; and
     49 // 			number of blocks per group should be a
     50 // 			multiple of 8. Updated md5 values.
     51 // 	 6 Jan 2003	Erik Andersen <andersee (at) debian.org> added
     52 // 			mkfs.jffs2 compatible device table support,
     53 // 			along with -q, -P, -U
     54 
     55 
     56 #include <config.h>
     57 #include <stdio.h>
     58 
     59 #if HAVE_SYS_TYPES_H
     60 # include <sys/types.h>
     61 #endif
     62 
     63 #if MAJOR_IN_MKDEV
     64 # include <sys/mkdev.h>
     65 #elif MAJOR_IN_SYSMACROS
     66 # include <sys/sysmacros.h>
     67 #endif
     68 
     69 #if HAVE_SYS_STAT_H
     70 # include <sys/stat.h>
     71 #endif
     72 
     73 #if STDC_HEADERS
     74 # include <stdlib.h>
     75 # include <stddef.h>
     76 #else
     77 # if HAVE_STDLIB_H
     78 #  include <stdlib.h>
     79 # endif
     80 # if HAVE_STDDEF_H
     81 #  include <stddef.h>
     82 # endif
     83 #endif
     84 
     85 #if HAVE_STRING_H
     86 # if !STDC_HEADERS && HAVE_MEMORY_H
     87 #  include <memory.h>
     88 # endif
     89 # include <string.h>
     90 #endif
     91 
     92 #if HAVE_STRINGS_H
     93 # include <strings.h>
     94 #endif
     95 
     96 #if HAVE_INTTYPES_H
     97 # include <inttypes.h>
     98 #else
     99 # if HAVE_STDINT_H
    100 #  include <stdint.h>
    101 # endif
    102 #endif
    103 
    104 #if HAVE_UNISTD_H
    105 # include <unistd.h>
    106 #endif
    107 
    108 #if HAVE_DIRENT_H
    109 # include <dirent.h>
    110 # define NAMLEN(dirent) strlen((dirent)->d_name)
    111 #else
    112 # define dirent direct
    113 # define NAMLEN(dirent) (dirent)->d_namlen
    114 # if HAVE_SYS_NDIR_H
    115 #  include <sys/ndir.h>
    116 # endif
    117 # if HAVE_SYS_DIR_H
    118 #  include <sys/dir.h>
    119 # endif
    120 # if HAVE_NDIR_H
    121 #  include <ndir.h>
    122 # endif
    123 #endif
    124 
    125 #if HAVE_LIBGEN_H
    126 # include <libgen.h>
    127 #endif
    128 
    129 #include <stdarg.h>
    130 #include <assert.h>
    131 #include <time.h>
    132 #include <ctype.h>
    133 #include <errno.h>
    134 
    135 #if HAVE_FCNTL_H
    136 # include <fcntl.h>
    137 #endif
    138 
    139 #if HAVE_GETOPT_H
    140 # include <getopt.h>
    141 #endif
    142 
    143 #if HAVE_LIMITS_H
    144 # include <limits.h>
    145 #endif
    146 
    147 #include <private/android_filesystem_config.h>
    148 unsigned source_path_len = 0;
    149 
    150 struct stats {
    151 	unsigned long nblocks;
    152 	unsigned long ninodes;
    153 };
    154 
    155 // block size
    156 
    157 #define BLOCKSIZE         1024
    158 #define BLOCKS_PER_GROUP  8192
    159 #define INODES_PER_GROUP  8192
    160 /* Percentage of blocks that are reserved.*/
    161 #define RESERVED_BLOCKS       5/100
    162 #define MAX_RESERVED_BLOCKS  25/100
    163 
    164 
    165 // inode block size (why is it != BLOCKSIZE ?!?)
    166 /* The field i_blocks in the ext2 inode stores the number of data blocks
    167    but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
    168    INOBLK is the number of such blocks in an actual disk block            */
    169 
    170 #define INODE_BLOCKSIZE   512
    171 #define INOBLK            (BLOCKSIZE / INODE_BLOCKSIZE)
    172 
    173 // reserved inodes
    174 
    175 #define EXT2_BAD_INO         1     // Bad blocks inode
    176 #define EXT2_ROOT_INO        2     // Root inode
    177 #define EXT2_ACL_IDX_INO     3     // ACL inode
    178 #define EXT2_ACL_DATA_INO    4     // ACL inode
    179 #define EXT2_BOOT_LOADER_INO 5     // Boot loader inode
    180 #define EXT2_UNDEL_DIR_INO   6     // Undelete directory inode
    181 #define EXT2_FIRST_INO       11    // First non reserved inode
    182 
    183 // magic number for ext2
    184 
    185 #define EXT2_MAGIC_NUMBER  0xEF53
    186 
    187 
    188 // direct/indirect block addresses
    189 
    190 #define EXT2_NDIR_BLOCKS   11                    // direct blocks
    191 #define EXT2_IND_BLOCK     12                    // indirect block
    192 #define EXT2_DIND_BLOCK    13                    // double indirect block
    193 #define EXT2_TIND_BLOCK    14                    // triple indirect block
    194 #define EXT2_INIT_BLOCK    0xFFFFFFFF            // just initialized (not really a block address)
    195 
    196 // end of a block walk
    197 
    198 #define WALK_END           0xFFFFFFFE
    199 
    200 // file modes
    201 
    202 #define FM_IFMT    0170000	// format mask
    203 #define FM_IFSOCK  0140000	// socket
    204 #define FM_IFLNK   0120000	// symbolic link
    205 #define FM_IFREG   0100000	// regular file
    206 
    207 #define FM_IFBLK   0060000	// block device
    208 #define FM_IFDIR   0040000	// directory
    209 #define FM_IFCHR   0020000	// character device
    210 #define FM_IFIFO   0010000	// fifo
    211 
    212 #define FM_IMASK   0007777	// *all* perms mask for everything below
    213 
    214 #define FM_ISUID   0004000	// SUID
    215 #define FM_ISGID   0002000	// SGID
    216 #define FM_ISVTX   0001000	// sticky bit
    217 
    218 #define FM_IRWXU   0000700	// entire "user" mask
    219 #define FM_IRUSR   0000400	// read
    220 #define FM_IWUSR   0000200	// write
    221 #define FM_IXUSR   0000100	// execute
    222 
    223 #define FM_IRWXG   0000070	// entire "group" mask
    224 #define FM_IRGRP   0000040	// read
    225 #define FM_IWGRP   0000020	// write
    226 #define FM_IXGRP   0000010	// execute
    227 
    228 #define FM_IRWXO   0000007	// entire "other" mask
    229 #define FM_IROTH   0000004	// read
    230 #define FM_IWOTH   0000002	// write
    231 #define FM_IXOTH   0000001	// execute
    232 
    233 // options
    234 
    235 #define OP_HOLES     0x01       // make files with holes
    236 
    237 /* Defines for accessing group details */
    238 
    239 // Number of groups in the filesystem
    240 #define GRP_NBGROUPS(fs) \
    241 	(((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
    242 	  (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
    243 
    244 // Get group block bitmap (bbm) given the group number
    245 #define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
    246 
    247 // Get group inode bitmap (ibm) given the group number
    248 #define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
    249 
    250 // Given an inode number find the group it belongs to
    251 #define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
    252 
    253 //Given an inode number get the inode bitmap that covers it
    254 #define GRP_GET_INODE_BITMAP(fs,nod) \
    255 	( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
    256 
    257 //Given an inode number find its offset within the inode bitmap that covers it
    258 #define GRP_IBM_OFFSET(fs,nod) \
    259 	( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
    260 
    261 // Given a block number find the group it belongs to
    262 #define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
    263 
    264 //Given a block number get the block bitmap that covers it
    265 #define GRP_GET_BLOCK_BITMAP(fs,blk) \
    266 	( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
    267 
    268 //Given a block number find its offset within the block bitmap that covers it
    269 #define GRP_BBM_OFFSET(fs,blk) \
    270 	( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
    271 
    272 
    273 // used types
    274 
    275 typedef signed char int8;
    276 typedef unsigned char uint8;
    277 typedef signed short int16;
    278 typedef unsigned short uint16;
    279 typedef signed int int32;
    280 typedef unsigned int uint32;
    281 
    282 
    283 // the GNU C library has a wonderful scanf("%as", string) which will
    284 // allocate the string with the right size, good to avoid buffer
    285 // overruns. the following macros use it if available or use a
    286 // hacky workaround
    287 // moreover it will define a snprintf() like a sprintf(), i.e.
    288 // without the buffer overrun checking, to work around bugs in
    289 // older solaris. Note that this is still not very portable, in that
    290 // the return value cannot be trusted.
    291 
    292 #if 0 // SCANF_CAN_MALLOC
    293 // C99 define "a" for floating point, so you can have runtime surprise
    294 // according the library versions
    295 # define SCANF_PREFIX "a"
    296 # define SCANF_STRING(s) (&s)
    297 #else
    298 # define SCANF_PREFIX "511"
    299 # define SCANF_STRING(s) (s = malloc(512))
    300 #endif /* SCANF_CAN_MALLOC */
    301 
    302 #if PREFER_PORTABLE_SNPRINTF
    303 static inline int
    304 portable_snprintf(char *str, size_t n, const char *fmt, ...)
    305 {
    306 	int ret;
    307 	va_list ap;
    308 	va_start(ap, fmt);
    309 	ret = vsprintf(str, fmt, ap);
    310 	va_end(ap);
    311 	return ret;
    312 }
    313 # define SNPRINTF portable_snprintf
    314 #else
    315 # define SNPRINTF snprintf
    316 #endif /* PREFER_PORTABLE_SNPRINTF */
    317 
    318 #if !HAVE_GETLINE
    319 // getline() replacement for Darwin and Solaris etc.
    320 // This code uses backward seeks (unless rchunk is set to 1) which can't work
    321 // on pipes etc. However, add2fs_from_file() only calls getline() for
    322 // regular files, so a larger rchunk and backward seeks are okay.
    323 
    324 ssize_t
    325 getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
    326 {
    327 	char *p;                    // reads stored here
    328 	size_t const rchunk = 512;  // number of bytes to read
    329 	size_t const mchunk = 512;  // number of extra bytes to malloc
    330 	size_t m = rchunk + 1;      // initial buffer size
    331 
    332 	if (*lineptr) {
    333 		if (*n < m) {
    334 			*lineptr = (char*)realloc(*lineptr, m);
    335 			if (!*lineptr) return -1;
    336 			*n = m;
    337 		}
    338 	} else {
    339 		*lineptr = (char*)malloc(m);
    340 		if (!*lineptr) return -1;
    341 		*n = m;
    342 	}
    343 
    344 	m = 0; // record length including seperator
    345 
    346 	do {
    347 		size_t i;     // number of bytes read etc
    348 		size_t j = 0; // number of bytes searched
    349 
    350 		p = *lineptr + m;
    351 
    352 		i = fread(p, 1, rchunk, stream);
    353 		if (i < rchunk && ferror(stream))
    354 			return -1;
    355 		while (j < i) {
    356 			++j;
    357 			if (*p++ == (char)delim) {
    358 				*p = '\0';
    359 				if (j != i) {
    360 					if (fseek(stream, j - i, SEEK_CUR))
    361 						return -1;
    362 					if (feof(stream))
    363 						clearerr(stream);
    364 				}
    365 				m += j;
    366 				return m;
    367 			}
    368 		}
    369 
    370 		m += j;
    371 		if (feof(stream)) {
    372 			if (m) return m;
    373 			if (!i) return -1;
    374 		}
    375 
    376 		// allocate space for next read plus possible null terminator
    377 		i = ((m + (rchunk + 1 > mchunk ? rchunk + 1 : mchunk) +
    378 		      mchunk - 1) / mchunk) * mchunk;
    379 		if (i != *n) {
    380 			*lineptr = (char*)realloc(*lineptr, i);
    381 			if (!*lineptr) return -1;
    382 			*n = i;
    383 		}
    384 	} while (1);
    385 }
    386 #define getline(a,b,c) getdelim(a,b,'\n',c)
    387 #endif /* HAVE_GETLINE */
    388 
    389 // Convert a numerical string to a float, and multiply the result by an
    390 // IEC or SI multiplier if provided; supported multipliers are Ki, Mi, Gi, k, M
    391 // and G.
    392 
    393 float
    394 SI_atof(const char *nptr)
    395 {
    396 	float f = 0;
    397 	float m = 1;
    398 	char *suffixptr;
    399 
    400 #if HAVE_STRTOF
    401 	f = strtof(nptr, &suffixptr);
    402 #else
    403 	f = (float)strtod(nptr, &suffixptr);
    404 #endif /* HAVE_STRTOF */
    405 
    406 	if (*suffixptr) {
    407 		if (!strcmp(suffixptr, "Ki"))
    408 			m = 1 << 10;
    409 		else if (!strcmp(suffixptr, "Mi"))
    410 			m = 1 << 20;
    411 		else if (!strcmp(suffixptr, "Gi"))
    412 			m = 1 << 30;
    413 		else if (!strcmp(suffixptr, "k"))
    414 			m = 1000;
    415 		else if (!strcmp(suffixptr, "M"))
    416 			m = 1000 * 1000;
    417 		else if (!strcmp(suffixptr, "G"))
    418 			m = 1000 * 1000 * 1000;
    419 	}
    420 	return f * m;
    421 }
    422 
    423 // endianness swap
    424 
    425 static inline uint16
    426 swab16(uint16 val)
    427 {
    428 	return (val >> 8) | (val << 8);
    429 }
    430 
    431 static inline uint32
    432 swab32(uint32 val)
    433 {
    434 	return ((val>>24) | ((val>>8)&0xFF00) |
    435 			((val<<8)&0xFF0000) | (val<<24));
    436 }
    437 
    438 
    439 // on-disk structures
    440 // this trick makes me declare things only once
    441 // (once for the structures, once for the endianness swap)
    442 
    443 #define superblock_decl \
    444 	udecl32(s_inodes_count)        /* Count of inodes in the filesystem */ \
    445 	udecl32(s_blocks_count)        /* Count of blocks in the filesystem */ \
    446 	udecl32(s_r_blocks_count)      /* Count of the number of reserved blocks */ \
    447 	udecl32(s_free_blocks_count)   /* Count of the number of free blocks */ \
    448 	udecl32(s_free_inodes_count)   /* Count of the number of free inodes */ \
    449 	udecl32(s_first_data_block)    /* The first block which contains data */ \
    450 	udecl32(s_log_block_size)      /* Indicator of the block size */ \
    451 	decl32(s_log_frag_size)        /* Indicator of the size of the fragments */ \
    452 	udecl32(s_blocks_per_group)    /* Count of the number of blocks in each block group */ \
    453 	udecl32(s_frags_per_group)     /* Count of the number of fragments in each block group */ \
    454 	udecl32(s_inodes_per_group)    /* Count of the number of inodes in each block group */ \
    455 	udecl32(s_mtime)               /* The time that the filesystem was last mounted */ \
    456 	udecl32(s_wtime)               /* The time that the filesystem was last written to */ \
    457 	udecl16(s_mnt_count)           /* The number of times the file system has been mounted */ \
    458 	decl16(s_max_mnt_count)        /* The number of times the file system can be mounted */ \
    459 	udecl16(s_magic)               /* Magic number indicating ex2fs */ \
    460 	udecl16(s_state)               /* Flags indicating the current state of the filesystem */ \
    461 	udecl16(s_errors)              /* Flags indicating the procedures for error reporting */ \
    462 	udecl16(s_minor_rev_level)     /* The minor revision level of the filesystem */ \
    463 	udecl32(s_lastcheck)           /* The time that the filesystem was last checked */ \
    464 	udecl32(s_checkinterval)       /* The maximum time permissable between checks */ \
    465 	udecl32(s_creator_os)          /* Indicator of which OS created the filesystem */ \
    466 	udecl32(s_rev_level)           /* The revision level of the filesystem */ \
    467 	udecl16(s_def_resuid)          /* The default uid for reserved blocks */ \
    468 	udecl16(s_def_resgid)          /* The default gid for reserved blocks */
    469 
    470 #define groupdescriptor_decl \
    471 	udecl32(bg_block_bitmap)       /* Block number of the block bitmap */ \
    472 	udecl32(bg_inode_bitmap)       /* Block number of the inode bitmap */ \
    473 	udecl32(bg_inode_table)        /* Block number of the inode table */ \
    474 	udecl16(bg_free_blocks_count)  /* Free blocks in the group */ \
    475 	udecl16(bg_free_inodes_count)  /* Free inodes in the group */ \
    476 	udecl16(bg_used_dirs_count)    /* Number of directories in the group */ \
    477 	udecl16(bg_pad)
    478 
    479 #define inode_decl \
    480 	udecl16(i_mode)                /* Entry type and file mode */ \
    481 	udecl16(i_uid)                 /* User id */ \
    482 	udecl32(i_size)                /* File/dir size in bytes */ \
    483 	udecl32(i_atime)               /* Last access time */ \
    484 	udecl32(i_ctime)               /* Creation time */ \
    485 	udecl32(i_mtime)               /* Last modification time */ \
    486 	udecl32(i_dtime)               /* Deletion time */ \
    487 	udecl16(i_gid)                 /* Group id */ \
    488 	udecl16(i_links_count)         /* Number of (hard) links to this inode */ \
    489 	udecl32(i_blocks)              /* Number of blocks used (1 block = 512 bytes) */ \
    490 	udecl32(i_flags)               /* ??? */ \
    491 	udecl32(i_reserved1) \
    492 	utdecl32(i_block,15)           /* Blocks table */ \
    493 	udecl32(i_version)             /* ??? */ \
    494 	udecl32(i_file_acl)            /* File access control list */ \
    495 	udecl32(i_dir_acl)             /* Directory access control list */ \
    496 	udecl32(i_faddr)               /* Fragment address */ \
    497 	udecl8(i_frag)                 /* Fragments count*/ \
    498 	udecl8(i_fsize)                /* Fragment size */ \
    499 	udecl16(i_pad1)
    500 
    501 #define directory_decl \
    502 	udecl32(d_inode)               /* Inode entry */ \
    503 	udecl16(d_rec_len)             /* Total size on record */ \
    504 	udecl16(d_name_len)            /* Size of entry name */
    505 
    506 #define decl8(x) int8 x;
    507 #define udecl8(x) uint8 x;
    508 #define decl16(x) int16 x;
    509 #define udecl16(x) uint16 x;
    510 #define decl32(x) int32 x;
    511 #define udecl32(x) uint32 x;
    512 #define utdecl32(x,n) uint32 x[n];
    513 
    514 typedef struct
    515 {
    516 	superblock_decl
    517 	uint32 s_reserved[235];       // Reserved
    518 } superblock;
    519 
    520 typedef struct
    521 {
    522 	groupdescriptor_decl
    523 	uint32 bg_reserved[3];
    524 } groupdescriptor;
    525 
    526 typedef struct
    527 {
    528 	inode_decl
    529 	uint32 i_reserved2[2];
    530 } inode;
    531 
    532 typedef struct
    533 {
    534 	directory_decl
    535 	char d_name[0];
    536 } directory;
    537 
    538 typedef uint8 block[BLOCKSIZE];
    539 
    540 /* blockwalker fields:
    541    The blockwalker is used to access all the blocks of a file (including
    542    the indirection blocks) through repeated calls to walk_bw.
    543 
    544    bpdir -> index into the inode->i_block[]. Indicates level of indirection.
    545    bnum -> total number of blocks so far accessed. including indirection
    546            blocks.
    547    bpind,bpdind,bptind -> index into indirection blocks.
    548 
    549    bpind, bpdind, bptind do *NOT* index into single, double and triple
    550    indirect blocks resp. as you might expect from their names. Instead
    551    they are in order the 1st, 2nd & 3rd index to be used
    552 
    553    As an example..
    554    To access data block number 70000:
    555         bpdir: 15 (we are doing triple indirection)
    556         bpind: 0 ( index into the triple indirection block)
    557         bpdind: 16 ( index into the double indirection block)
    558         bptind: 99 ( index into the single indirection block)
    559 	70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
    560 
    561    So,for double indirection bpind will index into the double indirection
    562    block and bpdind into the single indirection block. For single indirection
    563    only bpind will be used.
    564 */
    565 
    566 typedef struct
    567 {
    568 	uint32 bnum;
    569 	uint32 bpdir;
    570 	uint32 bpind;
    571 	uint32 bpdind;
    572 	uint32 bptind;
    573 } blockwalker;
    574 
    575 
    576 /* Filesystem structure that support groups */
    577 #if BLOCKSIZE == 1024
    578 typedef struct
    579 {
    580 	block zero;            // The famous block 0
    581 	superblock sb;         // The superblock
    582 	groupdescriptor gd[0]; // The group descriptors
    583 } filesystem;
    584 #else
    585 #error UNHANDLED BLOCKSIZE
    586 #endif
    587 
    588 // now the endianness swap
    589 
    590 #undef decl8
    591 #undef udecl8
    592 #undef decl16
    593 #undef udecl16
    594 #undef decl32
    595 #undef udecl32
    596 #undef utdecl32
    597 
    598 #define decl8(x)
    599 #define udecl8(x)
    600 #define decl16(x) this->x = swab16(this->x);
    601 #define udecl16(x) this->x = swab16(this->x);
    602 #define decl32(x) this->x = swab32(this->x);
    603 #define udecl32(x) this->x = swab32(this->x);
    604 #define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }
    605 
    606 #define HDLINK_CNT   16
    607 static int32 hdlink_cnt = HDLINK_CNT;
    608 struct hdlink_s
    609 {
    610 	uint32	src_inode;
    611 	uint32	dst_nod;
    612 };
    613 
    614 struct hdlinks_s
    615 {
    616 	int32 count;
    617 	struct hdlink_s *hdl;
    618 };
    619 
    620 static struct hdlinks_s hdlinks;
    621 
    622 static void
    623 swap_sb(superblock *sb)
    624 {
    625 #define this sb
    626 	superblock_decl
    627 #undef this
    628 }
    629 
    630 static void
    631 swap_gd(groupdescriptor *gd)
    632 {
    633 #define this gd
    634 	groupdescriptor_decl
    635 #undef this
    636 }
    637 
    638 static void
    639 swap_nod(inode *nod)
    640 {
    641 #define this nod
    642 	inode_decl
    643 #undef this
    644 }
    645 
    646 static void
    647 swap_dir(directory *dir)
    648 {
    649 #define this dir
    650 	directory_decl
    651 #undef this
    652 }
    653 
    654 static void
    655 swap_block(block b)
    656 {
    657 	int i;
    658 	uint32 *blk = (uint32*)b;
    659 	for(i = 0; i < BLOCKSIZE/4; i++)
    660 		blk[i] = swab32(blk[i]);
    661 }
    662 
    663 #undef decl8
    664 #undef udecl8
    665 #undef decl16
    666 #undef udecl16
    667 #undef decl32
    668 #undef udecl32
    669 #undef utdecl32
    670 
    671 static char * app_name;
    672 static const char *const memory_exhausted = "memory exhausted";
    673 
    674 // error (un)handling
    675 static void
    676 verror_msg(const char *s, va_list p)
    677 {
    678 	fflush(stdout);
    679 	fprintf(stderr, "%s: ", app_name);
    680 	vfprintf(stderr, s, p);
    681 }
    682 static void
    683 error_msg(const char *s, ...)
    684 {
    685 	va_list p;
    686 	va_start(p, s);
    687 	verror_msg(s, p);
    688 	va_end(p);
    689 	putc('\n', stderr);
    690 }
    691 
    692 static void
    693 error_msg_and_die(const char *s, ...)
    694 {
    695 	va_list p;
    696 	va_start(p, s);
    697 	verror_msg(s, p);
    698 	va_end(p);
    699 	putc('\n', stderr);
    700 	exit(EXIT_FAILURE);
    701 }
    702 
    703 static void
    704 vperror_msg(const char *s, va_list p)
    705 {
    706 	int err = errno;
    707 	if (s == 0)
    708 		s = "";
    709 	verror_msg(s, p);
    710 	if (*s)
    711 		s = ": ";
    712 	fprintf(stderr, "%s%s\n", s, strerror(err));
    713 }
    714 
    715 static void
    716 perror_msg_and_die(const char *s, ...)
    717 {
    718 	va_list p;
    719 	va_start(p, s);
    720 	vperror_msg(s, p);
    721 	va_end(p);
    722 	exit(EXIT_FAILURE);
    723 }
    724 
    725 static FILE *
    726 xfopen(const char *path, const char *mode)
    727 {
    728 	FILE *fp;
    729 	if ((fp = fopen(path, mode)) == NULL)
    730 		perror_msg_and_die("%s", path);
    731 	return fp;
    732 }
    733 
    734 static char *
    735 xstrdup(const char *s)
    736 {
    737 	char *t;
    738 
    739 	if (s == NULL)
    740 		return NULL;
    741 	t = strdup(s);
    742 	if (t == NULL)
    743 		error_msg_and_die(memory_exhausted);
    744 	return t;
    745 }
    746 
    747 static void *
    748 xrealloc(void *ptr, size_t size)
    749 {
    750 	ptr = realloc(ptr, size);
    751 	if (ptr == NULL && size != 0)
    752 		error_msg_and_die(memory_exhausted);
    753 	return ptr;
    754 }
    755 
    756 static char *
    757 xreadlink(const char *path)
    758 {
    759 	static const int GROWBY = 80; /* how large we will grow strings by */
    760 
    761 	char *buf = NULL;
    762 	int bufsize = 0, readsize = 0;
    763 
    764 	do {
    765 		buf = xrealloc(buf, bufsize += GROWBY);
    766 		readsize = readlink(path, buf, bufsize); /* 1st try */
    767 		if (readsize == -1) {
    768 			perror_msg_and_die("%s:%s", app_name, path);
    769 		}
    770 	}
    771 	while (bufsize < readsize + 1);
    772 
    773 	buf[readsize] = '\0';
    774 	return buf;
    775 }
    776 
    777 int
    778 is_hardlink(ino_t inode)
    779 {
    780 	int i;
    781 
    782 	for(i = 0; i < hdlinks.count; i++) {
    783 		if(hdlinks.hdl[i].src_inode == inode)
    784 			return i;
    785 	}
    786 	return -1;
    787 }
    788 
    789 // printf helper macro
    790 #define plural(a) (a), ((a) > 1) ? "s" : ""
    791 
    792 // temporary working block
    793 static inline uint8 *
    794 get_workblk(void)
    795 {
    796 	unsigned char* b=calloc(1,BLOCKSIZE);
    797 	return b;
    798 }
    799 static inline void
    800 free_workblk(block b)
    801 {
    802 	free(b);
    803 }
    804 
    805 /* Rounds qty upto a multiple of siz. siz should be a power of 2 */
    806 static inline uint32
    807 rndup(uint32 qty, uint32 siz)
    808 {
    809 	return (qty + (siz - 1)) & ~(siz - 1);
    810 }
    811 
    812 // check if something is allocated in the bitmap
    813 static inline uint32
    814 allocated(block b, uint32 item)
    815 {
    816 	return b[(item-1) / 8] & (1 << ((item-1) % 8));
    817 }
    818 
    819 // return a given block from a filesystem
    820 static inline uint8 *
    821 get_blk(filesystem *fs, uint32 blk)
    822 {
    823 	return (uint8*)fs + blk*BLOCKSIZE;
    824 }
    825 
    826 // return a given inode from a filesystem
    827 static inline inode *
    828 get_nod(filesystem *fs, uint32 nod)
    829 {
    830 	int grp,offset;
    831 	inode *itab;
    832 
    833 	offset = GRP_IBM_OFFSET(fs,nod);
    834 	grp = GRP_GROUP_OF_INODE(fs,nod);
    835 	itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
    836 	return itab+offset-1;
    837 }
    838 
    839 // allocate a given block/inode in the bitmap
    840 // allocate first free if item == 0
    841 static uint32
    842 allocate(block b, uint32 item)
    843 {
    844 	if(!item)
    845 	{
    846 		int i;
    847 		uint8 bits;
    848 		for(i = 0; i < BLOCKSIZE; i++)
    849 			if((bits = b[i]) != (uint8)-1)
    850 			{
    851 				int j;
    852 				for(j = 0; j < 8; j++)
    853 					if(!(bits & (1 << j)))
    854 						break;
    855 				item = i * 8 + j + 1;
    856 				break;
    857 			}
    858 		if(i == BLOCKSIZE)
    859 			return 0;
    860 	}
    861 	b[(item-1) / 8] |= (1 << ((item-1) % 8));
    862 	return item;
    863 }
    864 
    865 // deallocate a given block/inode
    866 static void
    867 deallocate(block b, uint32 item)
    868 {
    869 	b[(item-1) / 8] &= ~(1 << ((item-1) % 8));
    870 }
    871 
    872 // allocate a block
    873 static uint32
    874 alloc_blk(filesystem *fs, uint32 nod)
    875 {
    876 	uint32 bk=0;
    877 	uint32 grp,nbgroups;
    878 
    879 	grp = GRP_GROUP_OF_INODE(fs,nod);
    880 	nbgroups = GRP_NBGROUPS(fs);
    881 	if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
    882 		for(grp=0;grp<nbgroups && !bk;grp++)
    883 			bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
    884 		grp--;
    885 	}
    886 	if (!bk)
    887 		error_msg_and_die("couldn't allocate a block (no free space)");
    888 	if(!(fs->gd[grp].bg_free_blocks_count--))
    889 		error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
    890 	if(!(fs->sb.s_free_blocks_count--))
    891 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
    892 	return fs->sb.s_blocks_per_group*grp + bk;
    893 }
    894 
    895 // free a block
    896 static void
    897 free_blk(filesystem *fs, uint32 bk)
    898 {
    899 	uint32 grp;
    900 
    901 	grp = bk / fs->sb.s_blocks_per_group;
    902 	bk %= fs->sb.s_blocks_per_group;
    903 	deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
    904 	fs->gd[grp].bg_free_blocks_count++;
    905 	fs->sb.s_free_blocks_count++;
    906 }
    907 
    908 // allocate an inode
    909 static uint32
    910 alloc_nod(filesystem *fs)
    911 {
    912 	uint32 nod,best_group=0;
    913 	uint32 grp,nbgroups,avefreei;
    914 
    915 	nbgroups = GRP_NBGROUPS(fs);
    916 
    917 	/* Distribute inodes amongst all the blocks                           */
    918 	/* For every block group with more than average number of free inodes */
    919 	/* find the one with the most free blocks and allocate node there     */
    920 	/* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel      */
    921 	/* We do it for all inodes.                                           */
    922 	avefreei  =  fs->sb.s_free_inodes_count / nbgroups;
    923 	for(grp=0; grp<nbgroups; grp++) {
    924 		if (fs->gd[grp].bg_free_inodes_count < avefreei ||
    925 		    fs->gd[grp].bg_free_inodes_count == 0)
    926 			continue;
    927 		if (!best_group ||
    928 			fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
    929 			best_group = grp;
    930 	}
    931 	if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
    932 		error_msg_and_die("couldn't allocate an inode (no free inode)");
    933 	if(!(fs->gd[best_group].bg_free_inodes_count--))
    934 		error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
    935 	if(!(fs->sb.s_free_inodes_count--))
    936 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
    937 	return fs->sb.s_inodes_per_group*best_group+nod;
    938 }
    939 
    940 // print a bitmap allocation
    941 static void
    942 print_bm(block b, uint32 max)
    943 {
    944 	uint32 i;
    945 	printf("----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0\n");
    946 	for(i=1; i <= max; i++)
    947 	{
    948 		putchar(allocated(b, i) ? '*' : '.');
    949 		if(!(i % 100))
    950 			printf("\n");
    951 	}
    952 	if((i-1) % 100)
    953 		printf("\n");
    954 }
    955 
    956 // initalize a blockwalker (iterator for blocks list)
    957 static inline void
    958 init_bw(blockwalker *bw)
    959 {
    960 	bw->bnum = 0;
    961 	bw->bpdir = EXT2_INIT_BLOCK;
    962 }
    963 
    964 // return next block of inode (WALK_END for end)
    965 // if *create>0, append a newly allocated block at the end
    966 // if *create<0, free the block - warning, the metadata blocks contents is
    967 //				  used after being freed, so once you start
    968 //				  freeing blocks don't stop until the end of
    969 //				  the file. moreover, i_blocks isn't updated.
    970 //				  in fact, don't do that, just use extend_blk
    971 // if hole!=0, create a hole in the file
    972 static uint32
    973 walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
    974 {
    975 	uint32 *bkref = 0;
    976 	uint32 *b;
    977 	int extend = 0, reduce = 0;
    978 	if(create && (*create) < 0)
    979 		reduce = 1;
    980 	if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
    981 	{
    982 		if(create && (*create) > 0)
    983 		{
    984 			(*create)--;
    985 			extend = 1;
    986 		}
    987 		else
    988 			return WALK_END;
    989 	}
    990 	// first direct block
    991 	if(bw->bpdir == EXT2_INIT_BLOCK)
    992 	{
    993 		bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
    994 		if(extend) // allocate first block
    995 			*bkref = hole ? 0 : alloc_blk(fs,nod);
    996 		if(reduce) // free first block
    997 			free_blk(fs, *bkref);
    998 	}
    999 	// direct block
   1000 	else if(bw->bpdir < EXT2_NDIR_BLOCKS)
   1001 	{
   1002 		bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
   1003 		if(extend) // allocate block
   1004 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1005 		if(reduce) // free block
   1006 			free_blk(fs, *bkref);
   1007 	}
   1008 	// first block in indirect block
   1009 	else if(bw->bpdir == EXT2_NDIR_BLOCKS)
   1010 	{
   1011 		bw->bnum++;
   1012 		bw->bpdir = EXT2_IND_BLOCK;
   1013 		bw->bpind = 0;
   1014 		if(extend) // allocate indirect block
   1015 			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
   1016 		if(reduce) // free indirect block
   1017 			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1018 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1019 		bkref = &b[bw->bpind];
   1020 		if(extend) // allocate first block
   1021 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1022 		if(reduce) // free first block
   1023 			free_blk(fs, *bkref);
   1024 	}
   1025 	// block in indirect block
   1026 	else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
   1027 	{
   1028 		bw->bpind++;
   1029 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1030 		bkref = &b[bw->bpind];
   1031 		if(extend) // allocate block
   1032 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1033 		if(reduce) // free block
   1034 			free_blk(fs, *bkref);
   1035 	}
   1036 	// first block in first indirect block in first double indirect block
   1037 	else if(bw->bpdir == EXT2_IND_BLOCK)
   1038 	{
   1039 		bw->bnum += 2;
   1040 		bw->bpdir = EXT2_DIND_BLOCK;
   1041 		bw->bpind = 0;
   1042 		bw->bpdind = 0;
   1043 		if(extend) // allocate double indirect block
   1044 			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
   1045 		if(reduce) // free double indirect block
   1046 			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1047 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1048 		if(extend) // allocate first indirect block
   1049 			b[bw->bpind] = alloc_blk(fs,nod);
   1050 		if(reduce) // free  firstindirect block
   1051 			free_blk(fs, b[bw->bpind]);
   1052 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1053 		bkref = &b[bw->bpdind];
   1054 		if(extend) // allocate first block
   1055 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1056 		if(reduce) // free first block
   1057 			free_blk(fs, *bkref);
   1058 	}
   1059 	// block in indirect block in double indirect block
   1060 	else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
   1061 	{
   1062 		bw->bpdind++;
   1063 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1064 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1065 		bkref = &b[bw->bpdind];
   1066 		if(extend) // allocate block
   1067 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1068 		if(reduce) // free block
   1069 			free_blk(fs, *bkref);
   1070 	}
   1071 	// first block in indirect block in double indirect block
   1072 	else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
   1073 	{
   1074 		bw->bnum++;
   1075 		bw->bpdind = 0;
   1076 		bw->bpind++;
   1077 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1078 		if(extend) // allocate indirect block
   1079 			b[bw->bpind] = alloc_blk(fs,nod);
   1080 		if(reduce) // free indirect block
   1081 			free_blk(fs, b[bw->bpind]);
   1082 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1083 		bkref = &b[bw->bpdind];
   1084 		if(extend) // allocate first block
   1085 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1086 		if(reduce) // free first block
   1087 			free_blk(fs, *bkref);
   1088 	}
   1089 
   1090 	/* Adding support for triple indirection */
   1091 	/* Just starting triple indirection. Allocate the indirection
   1092 	   blocks and the first data block
   1093 	 */
   1094 	else if (bw->bpdir == EXT2_DIND_BLOCK)
   1095 	{
   1096 	  	bw->bnum += 3;
   1097 		bw->bpdir = EXT2_TIND_BLOCK;
   1098 		bw->bpind = 0;
   1099 		bw->bpdind = 0;
   1100 		bw->bptind = 0;
   1101 		if(extend) // allocate triple indirect block
   1102 			get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
   1103 		if(reduce) // free triple indirect block
   1104 			free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1105 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1106 		if(extend) // allocate first double indirect block
   1107 			b[bw->bpind] = alloc_blk(fs,nod);
   1108 		if(reduce) // free first double indirect block
   1109 			free_blk(fs, b[bw->bpind]);
   1110 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1111 		if(extend) // allocate first indirect block
   1112 			b[bw->bpdind] = alloc_blk(fs,nod);
   1113 		if(reduce) // free first indirect block
   1114 			free_blk(fs, b[bw->bpind]);
   1115 		b = (uint32*)get_blk(fs, b[bw->bpdind]);
   1116 		bkref = &b[bw->bptind];
   1117 		if(extend) // allocate first data block
   1118 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1119 		if(reduce) // free first block
   1120 			free_blk(fs, *bkref);
   1121 	}
   1122 	/* Still processing a single indirect block down the indirection
   1123 	   chain.Allocate a data block for it
   1124 	 */
   1125 	else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
   1126 		  (bw->bptind < BLOCKSIZE/4 -1) )
   1127 	{
   1128 		bw->bptind++;
   1129 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1130 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1131 		b = (uint32*)get_blk(fs, b[bw->bpdind]);
   1132 		bkref = &b[bw->bptind];
   1133 		if(extend) // allocate data block
   1134 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1135 		if(reduce) // free block
   1136 			free_blk(fs, *bkref);
   1137 	}
   1138 	/* Finished processing a single indirect block. But still in the
   1139 	   same double indirect block. Allocate new single indirect block
   1140 	   for it and a data block
   1141 	 */
   1142 	else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
   1143 		  (bw->bpdind < BLOCKSIZE/4 -1) )
   1144 	{
   1145 		bw->bnum++;
   1146 		bw->bptind = 0;
   1147 		bw->bpdind++;
   1148 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1149 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1150 		if(extend) // allocate single indirect block
   1151 			b[bw->bpdind] = alloc_blk(fs,nod);
   1152 		if(reduce) // free indirect block
   1153 			free_blk(fs, b[bw->bpind]);
   1154 		b = (uint32*)get_blk(fs, b[bw->bpdind]);
   1155 		bkref = &b[bw->bptind];
   1156 		if(extend) // allocate first data block
   1157 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1158 		if(reduce) // free first block
   1159 			free_blk(fs, *bkref);
   1160 	}
   1161 	/* Finished processing a double indirect block. Allocate the next
   1162 	   double indirect block and the single,data blocks for it
   1163 	 */
   1164 	else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
   1165 		  (bw->bpind < BLOCKSIZE/4 - 1) )
   1166 	{
   1167 		bw->bnum += 2;
   1168 		bw->bpdind = 0;
   1169 		bw->bptind = 0;
   1170 		bw->bpind++;
   1171 		b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
   1172 		if(extend) // allocate double indirect block
   1173 			b[bw->bpind] = alloc_blk(fs,nod);
   1174 		if(reduce) // free double indirect block
   1175 			free_blk(fs, b[bw->bpind]);
   1176 		b = (uint32*)get_blk(fs, b[bw->bpind]);
   1177 		if(extend) // allocate single indirect block
   1178 			b[bw->bpdind] = alloc_blk(fs,nod);
   1179 		if(reduce) // free indirect block
   1180 			free_blk(fs, b[bw->bpind]);
   1181 		b = (uint32*)get_blk(fs, b[bw->bpdind]);
   1182 		bkref = &b[bw->bptind];
   1183 		if(extend) // allocate first block
   1184 			*bkref = hole ? 0 : alloc_blk(fs,nod);
   1185 		if(reduce) // free first block
   1186 			free_blk(fs, *bkref);
   1187 	}
   1188 	else
   1189 		error_msg_and_die("file too big !");
   1190 	/* End change for walking triple indirection */
   1191 
   1192 	if(*bkref)
   1193 	{
   1194 		bw->bnum++;
   1195 		if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
   1196 			error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
   1197 	}
   1198 	if(extend)
   1199 		get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
   1200 	return *bkref;
   1201 }
   1202 
   1203 // add blocks to an inode (file/dir/etc...)
   1204 static void
   1205 extend_blk(filesystem *fs, uint32 nod, block b, int amount)
   1206 {
   1207 	int create = amount;
   1208 	blockwalker bw, lbw;
   1209 	uint32 bk;
   1210 	init_bw(&bw);
   1211 	if(amount < 0)
   1212 	{
   1213 		uint32 i;
   1214 		for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
   1215 			walk_bw(fs, nod, &bw, 0, 0);
   1216 		while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
   1217 			/*nop*/;
   1218 		get_nod(fs, nod)->i_blocks += amount * INOBLK;
   1219 	}
   1220 	else
   1221 	{
   1222 		lbw = bw;
   1223 		while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   1224 			lbw = bw;
   1225 		bw = lbw;
   1226 		while(create)
   1227 		{
   1228 			int i, copyb = 0;
   1229 			if(!(fs->sb.s_reserved[200] & OP_HOLES))
   1230 				copyb = 1;
   1231 			else
   1232 				for(i = 0; i < BLOCKSIZE / 4; i++)
   1233 					if(((int32*)(b + BLOCKSIZE * (amount - create)))[i])
   1234 					{
   1235 						copyb = 1;
   1236 						break;
   1237 					}
   1238 			if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END)
   1239 				break;
   1240 			if(copyb)
   1241 				memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE);
   1242 		}
   1243 	}
   1244 }
   1245 
   1246 // link an entry (inode #) to a directory
   1247 static void
   1248 add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
   1249 {
   1250 	blockwalker bw;
   1251 	uint32 bk;
   1252 	uint8 *b;
   1253 	directory *d;
   1254 	int reclen, nlen;
   1255 	inode *node;
   1256 	inode *pnode;
   1257 
   1258 	pnode = get_nod(fs, dnod);
   1259 	if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
   1260 		error_msg_and_die("can't add '%s' to a non-directory", name);
   1261 	if(!*name)
   1262 		error_msg_and_die("can't create an inode with an empty name");
   1263 	if(strchr(name, '/'))
   1264 		error_msg_and_die("bad name '%s' (contains a slash)", name);
   1265 	nlen = strlen(name);
   1266 	reclen = sizeof(directory) + rndup(nlen, 4);
   1267 	if(reclen > BLOCKSIZE)
   1268 		error_msg_and_die("bad name '%s' (too long)", name);
   1269 	init_bw(&bw);
   1270 	while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
   1271 	{
   1272 		b = get_blk(fs, bk);
   1273 		// for all dir entries in block
   1274 		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   1275 		{
   1276 			// if empty dir entry, large enough, use it
   1277 			if((!d->d_inode) && (d->d_rec_len >= reclen))
   1278 			{
   1279 				d->d_inode = nod;
   1280 				node = get_nod(fs, nod);
   1281 				node->i_links_count++;
   1282 				d->d_name_len = nlen;
   1283 				strncpy(d->d_name, name, nlen);
   1284 				return;
   1285 			}
   1286 			// if entry with enough room (last one?), shrink it & use it
   1287 			if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen))
   1288 			{
   1289 				reclen = d->d_rec_len;
   1290 				d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
   1291 				reclen -= d->d_rec_len;
   1292 				d = (directory*) (((int8*)d) + d->d_rec_len);
   1293 				d->d_rec_len = reclen;
   1294 				d->d_inode = nod;
   1295 				node = get_nod(fs, nod);
   1296 				node->i_links_count++;
   1297 				d->d_name_len = nlen;
   1298 				strncpy(d->d_name, name, nlen);
   1299 				return;
   1300 			}
   1301 		}
   1302 	}
   1303 	// we found no free entry in the directory, so we add a block
   1304 	if(!(b = get_workblk()))
   1305 		error_msg_and_die("get_workblk() failed.");
   1306 	d = (directory*)b;
   1307 	d->d_inode = nod;
   1308 	node = get_nod(fs, nod);
   1309 	node->i_links_count++;
   1310 	d->d_rec_len = BLOCKSIZE;
   1311 	d->d_name_len = nlen;
   1312 	strncpy(d->d_name, name, nlen);
   1313 	extend_blk(fs, dnod, b, 1);
   1314 	get_nod(fs, dnod)->i_size += BLOCKSIZE;
   1315 	free_workblk(b);
   1316 }
   1317 
   1318 // find an entry in a directory
   1319 static uint32
   1320 find_dir(filesystem *fs, uint32 nod, const char * name)
   1321 {
   1322 	blockwalker bw;
   1323 	uint32 bk;
   1324 	int nlen = strlen(name);
   1325 	init_bw(&bw);
   1326 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   1327 	{
   1328 		directory *d;
   1329 		uint8 *b;
   1330 		b = get_blk(fs, bk);
   1331 		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   1332 			if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen))
   1333 				return d->d_inode;
   1334 	}
   1335 	return 0;
   1336 }
   1337 
   1338 // find the inode of a full path
   1339 static uint32
   1340 find_path(filesystem *fs, uint32 nod, const char * name)
   1341 {
   1342 	char *p, *n, *n2 = xstrdup(name);
   1343 	n = n2;
   1344 	while(*n == '/')
   1345 	{
   1346 		nod = EXT2_ROOT_INO;
   1347 		n++;
   1348 	}
   1349 	while(*n)
   1350 	{
   1351 		if((p = strchr(n, '/')))
   1352 			(*p) = 0;
   1353 		if(!(nod = find_dir(fs, nod, n)))
   1354 			break;
   1355 		if(p)
   1356 			n = p + 1;
   1357 		else
   1358 			break;
   1359 	}
   1360 	free(n2);
   1361 	return nod;
   1362 }
   1363 
   1364 // chmod an inode
   1365 void
   1366 chmod_fs(filesystem *fs, uint32 nod, uint16 mode, uint16 uid, uint16 gid)
   1367 {
   1368 	inode *node;
   1369 	node = get_nod(fs, nod);
   1370 	node->i_mode = (node->i_mode & ~FM_IMASK) | (mode & FM_IMASK);
   1371 	node->i_uid = uid;
   1372 	node->i_gid = gid;
   1373 }
   1374 
   1375 // create a simple inode
   1376 static uint32
   1377 mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
   1378 {
   1379 	uint32 nod;
   1380 	inode *node;
   1381 	{
   1382 		nod = alloc_nod(fs);
   1383 		node = get_nod(fs, nod);
   1384 		node->i_mode = mode;
   1385 		add2dir(fs, parent_nod, nod, name);
   1386 		switch(mode & FM_IFMT)
   1387 		{
   1388 			case FM_IFLNK:
   1389 				mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
   1390 				break;
   1391 			case FM_IFBLK:
   1392 			case FM_IFCHR:
   1393 				((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
   1394 				((uint8*)get_nod(fs, nod)->i_block)[1] = major;
   1395 				break;
   1396 			case FM_IFDIR:
   1397 				add2dir(fs, nod, nod, ".");
   1398 				add2dir(fs, nod, parent_nod, "..");
   1399 				fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
   1400 				break;
   1401 		}
   1402 	}
   1403 	node->i_uid = uid;
   1404 	node->i_gid = gid;
   1405 	node->i_atime = mtime;
   1406 	node->i_ctime = ctime;
   1407 	node->i_mtime = mtime;
   1408 	return nod;
   1409 }
   1410 
   1411 // make a full-fledged directory (i.e. with "." & "..")
   1412 static inline uint32
   1413 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
   1414 	uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
   1415 {
   1416 	return mknod_fs(fs, parent_nod, name, mode|FM_IFDIR, uid, gid, 0, 0, ctime, mtime);
   1417 }
   1418 
   1419 // make a symlink
   1420 static uint32
   1421 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)
   1422 {
   1423 	uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
   1424 	extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
   1425 	get_nod(fs, nod)->i_size = size;
   1426 	if(size <= 4 * (EXT2_TIND_BLOCK+1))
   1427 	{
   1428 		strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
   1429 		return nod;
   1430 	}
   1431 	extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
   1432 	return nod;
   1433 }
   1434 
   1435 // make a file from a FILE*
   1436 static uint32
   1437 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)
   1438 {
   1439 	uint8 * b;
   1440 	uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
   1441 	extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
   1442 	get_nod(fs, nod)->i_size = size;
   1443 	if (size) {
   1444 		if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
   1445 			error_msg_and_die("not enough mem to read file '%s'", name);
   1446 		if(f)
   1447 			fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
   1448 		extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
   1449 		free(b);
   1450 	}
   1451 	return nod;
   1452 }
   1453 
   1454 // retrieves a mode info from a struct stat
   1455 static uint32
   1456 get_mode(struct stat *st)
   1457 {
   1458 	uint32 mode = 0;
   1459 
   1460 	if(st->st_mode & S_IRUSR)
   1461 		mode |= FM_IRUSR;
   1462 	if(st->st_mode & S_IWUSR)
   1463 		mode |= FM_IWUSR;
   1464 	if(st->st_mode & S_IXUSR)
   1465 		mode |= FM_IXUSR;
   1466 	if(st->st_mode & S_IRGRP)
   1467 		mode |= FM_IRGRP;
   1468 	if(st->st_mode & S_IWGRP)
   1469 		mode |= FM_IWGRP;
   1470 	if(st->st_mode & S_IXGRP)
   1471 		mode |= FM_IXGRP;
   1472 	if(st->st_mode & S_IROTH)
   1473 		mode |= FM_IROTH;
   1474 	if(st->st_mode & S_IWOTH)
   1475 		mode |= FM_IWOTH;
   1476 	if(st->st_mode & S_IXOTH)
   1477 		mode |= FM_IXOTH;
   1478 	if(st->st_mode & S_ISUID)
   1479 		mode |= FM_ISUID;
   1480 	if(st->st_mode & S_ISGID)
   1481 		mode |= FM_ISGID;
   1482 	if(st->st_mode & S_ISVTX)
   1483 		mode |= FM_ISVTX;
   1484 	return mode;
   1485 }
   1486 
   1487 // add or fixup entries to the filesystem from a text file
   1488 /*  device table entries take the form of:
   1489     <path>	<type> <mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
   1490     /dev/mem     c    640       0       0         1       1       0     0         -
   1491 
   1492     type can be one of:
   1493 	f	A regular file
   1494 	d	Directory
   1495 	c	Character special device file
   1496 	b	Block special device file
   1497 	p	Fifo (named pipe)
   1498 
   1499     I don't bother with symlinks (permissions are irrelevant), hard
   1500     links (special cases of regular files), or sockets (why bother).
   1501 
   1502     Regular files must exist in the target root directory.  If a char,
   1503     block, fifo, or directory does not exist, it will be created.
   1504 */
   1505 
   1506 static void
   1507 add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh, uint32 fs_timestamp, struct stats *stats)
   1508 {
   1509 	unsigned long mode, uid, gid, major, minor;
   1510 	unsigned long start, increment, count;
   1511 	uint32 nod, ctime, mtime;
   1512 	char *c, type, *path = NULL, *path2 = NULL, *dir, *name, *line = NULL;
   1513 	size_t len;
   1514 	struct stat st;
   1515 	int nbargs, lineno = 0;
   1516 
   1517 	fstat(fileno(fh), &st);
   1518 	ctime = fs_timestamp;
   1519 	mtime = st.st_mtime;
   1520 	while(getline(&line, &len, fh) >= 0)
   1521 	{
   1522 		mode = uid = gid = major = minor = 0;
   1523 		start = 0; increment = 1; count = 0;
   1524 		lineno++;
   1525 		if((c = strchr(line, '#')))
   1526 			*c = 0;
   1527 		if (path) {
   1528 			free(path);
   1529 			path = NULL;
   1530 		}
   1531 		if (path2) {
   1532 			free(path2);
   1533 			path2 = NULL;
   1534 		}
   1535 		nbargs = sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
   1536 					SCANF_STRING(path), &type, &mode, &uid, &gid, &major, &minor,
   1537 					&start, &increment, &count);
   1538 		if(nbargs < 3)
   1539 		{
   1540 			if(nbargs > 0)
   1541 				error_msg("device table line %d skipped: bad format for entry '%s'", lineno, path);
   1542 			continue;
   1543 		}
   1544 		mode &= FM_IMASK;
   1545 		path2 = strdup(path);
   1546 		name = basename(path);
   1547 		dir = dirname(path2);
   1548 		if((!strcmp(name, ".")) || (!strcmp(name, "..")))
   1549 		{
   1550 			error_msg("device table line %d skipped", lineno);
   1551 			continue;
   1552 		}
   1553 		if(fs)
   1554 		{
   1555 			if(!(nod = find_path(fs, this_nod, dir)))
   1556 			{
   1557 				error_msg("device table line %d skipped: can't find directory '%s' to create '%s''", lineno, dir, name);
   1558 				continue;
   1559 			}
   1560 		}
   1561 		else
   1562 			nod = 0;
   1563 		switch (type)
   1564 		{
   1565 			case 'd':
   1566 				mode |= FM_IFDIR;
   1567 				break;
   1568 			case 'f':
   1569 				mode |= FM_IFREG;
   1570 				break;
   1571 			case 'p':
   1572 				mode |= FM_IFIFO;
   1573 				break;
   1574 			case 's':
   1575 				mode |= FM_IFSOCK;
   1576 				break;
   1577 			case 'c':
   1578 				mode |= FM_IFCHR;
   1579 				break;
   1580 			case 'b':
   1581 				mode |= FM_IFBLK;
   1582 				break;
   1583 			default:
   1584 				error_msg("device table line %d skipped: bad type '%c' for entry '%s'", lineno, type, name);
   1585 				continue;
   1586 		}
   1587 		if(stats) {
   1588 			if(count > 0)
   1589 				stats->ninodes += count - start;
   1590 			else
   1591 				stats->ninodes++;
   1592 		} else {
   1593 			if(count > 0)
   1594 			{
   1595 				char *dname;
   1596 				unsigned long i;
   1597 				unsigned len;
   1598 				len = strlen(name) + 10;
   1599 				dname = malloc(len + 1);
   1600 				for(i = start; i < count; i++)
   1601 				{
   1602 					uint32 oldnod;
   1603 					SNPRINTF(dname, len, "%s%lu", name, i);
   1604 					oldnod = find_dir(fs, nod, dname);
   1605 					if(oldnod)
   1606 						chmod_fs(fs, oldnod, mode, uid, gid);
   1607 					else
   1608 						mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
   1609 				}
   1610 				free(dname);
   1611 			}
   1612 			else
   1613 			{
   1614 				uint32 oldnod = find_dir(fs, nod, name);
   1615 				if(oldnod)
   1616 					chmod_fs(fs, oldnod, mode, uid, gid);
   1617 				else
   1618 					mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
   1619 			}
   1620 		}
   1621 	}
   1622 	if (line)
   1623 		free(line);
   1624 	if (path)
   1625 		free(path);
   1626 	if (path2)
   1627 		free(path2);
   1628 }
   1629 
   1630 static void
   1631 prep_stat(const char *root_path)
   1632 {
   1633 	int len = strlen(root_path);
   1634 
   1635 	if((len >= 4) && (!strcmp(root_path + len - 4, "data"))) {
   1636 		source_path_len = len - 4;
   1637 	} else if((len >= 7) && (!strcmp(root_path + len - 6, "system"))) {
   1638 		source_path_len = len - 6;
   1639 	} else {
   1640 		error_msg_and_die("Fixstats (-a) option requested but "
   1641 				  "filesystem is not data or android!");
   1642 	}
   1643 }
   1644 
   1645 static void
   1646 fix_stat(const char *path, struct stat *s)
   1647 {
   1648 	uint64_t capabilities;
   1649 	path += source_path_len;
   1650 	fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);
   1651 }
   1652 
   1653 // adds a tree of entries to the filesystem from current dir
   1654 static void
   1655 add2fs_from_dir(filesystem *fs, const char *path, uint32 this_nod, int squash_uids, int squash_perms, int fixstats, uint32 fs_timestamp, struct stats *stats)
   1656 {
   1657 	uint32 nod;
   1658 	uint32 uid, gid, mode, ctime, mtime;
   1659 	const char *name;
   1660 	FILE *fh;
   1661 	DIR *dh;
   1662 	struct dirent *dent;
   1663 	struct stat st;
   1664 	char *lnk;
   1665 	uint32 save_nod;
   1666 	char full_name[2048];
   1667 
   1668 	if(!(dh = opendir(".")))
   1669 		perror_msg_and_die(".");
   1670 	while((dent = readdir(dh)))
   1671 	{
   1672 		if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
   1673 			continue;
   1674 
   1675 		lstat(dent->d_name, &st);
   1676 
   1677 		if(fixstats) {
   1678 			int tmp = snprintf(full_name, sizeof(full_name),
   1679 			                   "%s/%s", path, dent->d_name);
   1680 			if(tmp >= (int)sizeof(full_name))
   1681 				error_msg_and_die("Path too long!");
   1682 			fix_stat(full_name, &st);
   1683 		} else
   1684 			full_name[0] = '\0';
   1685 		uid = st.st_uid;
   1686 		gid = st.st_gid;
   1687 		ctime = fs_timestamp;
   1688 		mtime = st.st_mtime;
   1689 		name = dent->d_name;
   1690 		mode = get_mode(&st);
   1691 		if(squash_uids)
   1692 			uid = gid = 0;
   1693 		if(squash_perms)
   1694 			mode &= ~(FM_IRWXG | FM_IRWXO);
   1695 		if(stats)
   1696 			switch(st.st_mode & S_IFMT)
   1697 			{
   1698 				case S_IFLNK:
   1699 				case S_IFREG:
   1700 					if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
   1701 						stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
   1702 				case S_IFCHR:
   1703 				case S_IFBLK:
   1704 				case S_IFIFO:
   1705 				case S_IFSOCK:
   1706 					stats->ninodes++;
   1707 					break;
   1708 				case S_IFDIR:
   1709 					stats->ninodes++;
   1710 					if(chdir(dent->d_name) < 0)
   1711 						perror_msg_and_die(dent->d_name);
   1712 					add2fs_from_dir(fs, full_name, this_nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1713 					chdir("..");
   1714 					break;
   1715 				default:
   1716 					break;
   1717 			}
   1718 		else
   1719 		{
   1720 			if((nod = find_dir(fs, this_nod, name)))
   1721 			{
   1722 				error_msg("ignoring duplicate entry %s", name);
   1723 				if(S_ISDIR(st.st_mode)) {
   1724 					if(chdir(dent->d_name) < 0)
   1725 						perror_msg_and_die(name);
   1726 					add2fs_from_dir(fs, full_name, nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1727 					chdir("..");
   1728 				}
   1729 				continue;
   1730 			}
   1731 			save_nod = 0;
   1732 			/* Check for hardlinks */
   1733 			if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
   1734 				int32 hdlink = is_hardlink(st.st_ino);
   1735 				if (hdlink >= 0) {
   1736 					add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
   1737 					continue;
   1738 				} else {
   1739 					save_nod = 1;
   1740 				}
   1741 			}
   1742 			switch(st.st_mode & S_IFMT)
   1743 			{
   1744 #if HAVE_STRUCT_STAT_ST_RDEV
   1745 				case S_IFCHR:
   1746 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFCHR, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
   1747 					break;
   1748 				case S_IFBLK:
   1749 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFBLK, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
   1750 					break;
   1751 #endif
   1752 				case S_IFIFO:
   1753 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFIFO, uid, gid, 0, 0, ctime, mtime);
   1754 					break;
   1755 				case S_IFSOCK:
   1756 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFSOCK, uid, gid, 0, 0, ctime, mtime);
   1757 					break;
   1758 				case S_IFLNK:
   1759 					lnk = xreadlink(dent->d_name);
   1760 					mklink_fs(fs, this_nod, name, st.st_size, (uint8*)lnk, uid, gid, ctime, mtime);
   1761 					free(lnk);
   1762 					break;
   1763 				case S_IFREG:
   1764 					fh = xfopen(dent->d_name, "rb");
   1765 					nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
   1766 					fclose(fh);
   1767 					break;
   1768 				case S_IFDIR:
   1769 					nod = mkdir_fs(fs, this_nod, name, mode, uid, gid, ctime, mtime);
   1770 					if(chdir(dent->d_name) < 0)
   1771 						perror_msg_and_die(name);
   1772 					add2fs_from_dir(fs, full_name, nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1773 					chdir("..");
   1774 					break;
   1775 				default:
   1776 					error_msg("ignoring entry %s", name);
   1777 			}
   1778 			if (save_nod) {
   1779 				if (hdlinks.count == hdlink_cnt) {
   1780 					if ((hdlinks.hdl =
   1781 						 realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
   1782 								  sizeof (struct hdlink_s))) == NULL) {
   1783 						error_msg_and_die("Not enough memory");
   1784 					}
   1785 					hdlink_cnt += HDLINK_CNT;
   1786 				}
   1787 				hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
   1788 				hdlinks.hdl[hdlinks.count].dst_nod = nod;
   1789 				hdlinks.count++;
   1790 			}
   1791 		}
   1792 	}
   1793 	closedir(dh);
   1794 }
   1795 
   1796 // endianness swap of x-indirect blocks
   1797 static void
   1798 swap_goodblocks(filesystem *fs, inode *nod)
   1799 {
   1800 	uint32 i,j;
   1801 	int done=0;
   1802 	uint32 *b,*b2;
   1803 
   1804 	uint32 nblk = nod->i_blocks / INOBLK;
   1805 	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
   1806 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
   1807 			nod->i_block[i] = swab32(nod->i_block[i]);
   1808 	if(nblk <= EXT2_IND_BLOCK)
   1809 		return;
   1810 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
   1811 	if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
   1812 		return;
   1813 	/* Currently this will fail b'cos the number of blocks as stored
   1814 	   in i_blocks also includes the indirection blocks (see
   1815 	   walk_bw). But this function assumes that i_blocks only
   1816 	   stores the count of data blocks ( Actually according to
   1817 	   "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
   1818 	   i_blocks IS supposed to store the count of data blocks). so
   1819 	   with a file of size 268K nblk would be 269.The above check
   1820 	   will be false even though double indirection hasn't been
   1821 	   started.This is benign as 0 means block 0 which has been
   1822 	   zeroed out and therefore points back to itself from any offset
   1823 	 */
   1824 	// FIXME: I have fixed that, but I have the feeling the rest of
   1825 	// ths function needs to be fixed for the same reasons - Xav
   1826 	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
   1827 	for(i = 0; i < BLOCKSIZE/4; i++)
   1828 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
   1829 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
   1830 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
   1831 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
   1832 		return;
   1833 	/* Adding support for triple indirection */
   1834 	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
   1835 	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
   1836 		b2 = (uint32*)get_blk(fs,b[i]);
   1837 		for(j=0; j<BLOCKSIZE/4;j++) {
   1838 			if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
   1839 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1840 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1841 				     j*(BLOCKSIZE/4)) )
   1842 			  swap_block(get_blk(fs,b2[j]));
   1843 			else {
   1844 			  done = 1;
   1845 			  break;
   1846 			}
   1847 		}
   1848 		swap_block((uint8 *)b2);
   1849 	}
   1850 	swap_block((uint8 *)b);
   1851 	return;
   1852 }
   1853 
   1854 static void
   1855 swap_badblocks(filesystem *fs, inode *nod)
   1856 {
   1857 	uint32 i,j;
   1858 	int done=0;
   1859 	uint32 *b,*b2;
   1860 
   1861 	uint32 nblk = nod->i_blocks / INOBLK;
   1862 	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
   1863 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
   1864 			nod->i_block[i] = swab32(nod->i_block[i]);
   1865 	if(nblk <= EXT2_IND_BLOCK)
   1866 		return;
   1867 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
   1868 	if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
   1869 		return;
   1870 	/* See comment in swap_goodblocks */
   1871 	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
   1872 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
   1873 	for(i = 0; i < BLOCKSIZE/4; i++)
   1874 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
   1875 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
   1876 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
   1877 		return;
   1878 	/* Adding support for triple indirection */
   1879 	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
   1880 	swap_block((uint8 *)b);
   1881 	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
   1882 		b2 = (uint32*)get_blk(fs,b[i]);
   1883 		swap_block((uint8 *)b2);
   1884 		for(j=0; j<BLOCKSIZE/4;j++) {
   1885 			if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
   1886 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1887 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1888 				     j*(BLOCKSIZE/4)) )
   1889 			  swap_block(get_blk(fs,b2[j]));
   1890 			else {
   1891 			  done = 1;
   1892 			  break;
   1893 			}
   1894 		}
   1895 	}
   1896 	return;
   1897 }
   1898 
   1899 // endianness swap of the whole filesystem
   1900 static void
   1901 swap_goodfs(filesystem *fs)
   1902 {
   1903 	uint32 i;
   1904 	for(i = 1; i < fs->sb.s_inodes_count; i++)
   1905 	{
   1906 		inode *nod = get_nod(fs, i);
   1907 		if(nod->i_mode & FM_IFDIR)
   1908 		{
   1909 			blockwalker bw;
   1910 			uint32 bk;
   1911 			init_bw(&bw);
   1912 			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
   1913 			{
   1914 				directory *d;
   1915 				uint8 *b;
   1916 				b = get_blk(fs, bk);
   1917 				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
   1918 					swap_dir(d);
   1919 			}
   1920 		}
   1921 		swap_goodblocks(fs, nod);
   1922 		swap_nod(nod);
   1923 	}
   1924 	for(i=0;i<GRP_NBGROUPS(fs);i++)
   1925 		swap_gd(&(fs->gd[i]));
   1926 	swap_sb(&fs->sb);
   1927 }
   1928 
   1929 static void
   1930 swap_badfs(filesystem *fs)
   1931 {
   1932 	uint32 i;
   1933 	swap_sb(&fs->sb);
   1934 	for(i=0;i<GRP_NBGROUPS(fs);i++)
   1935 		swap_gd(&(fs->gd[i]));
   1936 	for(i = 1; i < fs->sb.s_inodes_count; i++)
   1937 	{
   1938 		inode *nod = get_nod(fs, i);
   1939 		swap_nod(nod);
   1940 		swap_badblocks(fs, nod);
   1941 		if(nod->i_mode & FM_IFDIR)
   1942 		{
   1943 			blockwalker bw;
   1944 			uint32 bk;
   1945 			init_bw(&bw);
   1946 			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
   1947 			{
   1948 				directory *d;
   1949 				uint8 *b;
   1950 				b = get_blk(fs, bk);
   1951 				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   1952 					swap_dir(d);
   1953 			}
   1954 		}
   1955 	}
   1956 }
   1957 
   1958 // initialize an empty filesystem
   1959 static filesystem *
   1960 init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
   1961 {
   1962 	uint32 i;
   1963 	filesystem *fs;
   1964 	directory *d;
   1965 	uint8 * b;
   1966 	uint32 nod, first_block;
   1967 	uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
   1968 		free_blocks_per_group,nbblocks_per_group,min_nbgroups;
   1969 	uint32 gdsz,itblsz,bbmpos,ibmpos,itblpos;
   1970 	uint32 j;
   1971 	uint8 *bbm,*ibm;
   1972 	inode *itab0;
   1973 
   1974 	if(nbresrvd < 0)
   1975 		error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
   1976 	if(nbinodes < EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0))
   1977 		error_msg_and_die("too few inodes. Note: options have changed, see --help or the man page.");
   1978 	if(nbblocks < 8)
   1979 		error_msg_and_die("too few blocks. Note: options have changed, see --help or the man page.");
   1980 
   1981 	/* nbinodes is the total number of inodes in the system.
   1982 	 * a block group can have no more than 8192 inodes.
   1983 	 */
   1984 	min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
   1985 
   1986 	/* nbblocks is the total number of blocks in the filesystem.
   1987 	 * a block group can have no more than 8192 blocks.
   1988 	 */
   1989 	first_block = (BLOCKSIZE == 1024);
   1990 	nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
   1991 	if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
   1992 	nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
   1993 	nbinodes_per_group = rndup((nbinodes + nbgroups - 1)/nbgroups,
   1994 						(BLOCKSIZE/sizeof(inode)));
   1995 	if (nbinodes_per_group < 16)
   1996 		nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
   1997 
   1998 	gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
   1999 	itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
   2000 	overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
   2001 	if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
   2002 		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
   2003 	free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
   2004 	free_blocks_per_group = nbblocks_per_group - overhead_per_group;
   2005 
   2006 	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
   2007 		error_msg_and_die("not enough memory for filesystem");
   2008 
   2009 	// create the superblock for an empty filesystem
   2010 	fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
   2011 	fs->sb.s_blocks_count = nbblocks;
   2012 	fs->sb.s_r_blocks_count = nbresrvd;
   2013 	fs->sb.s_free_blocks_count = free_blocks;
   2014 	fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
   2015 	fs->sb.s_first_data_block = first_block;
   2016 	fs->sb.s_log_block_size = BLOCKSIZE >> 11;
   2017 	fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
   2018 	fs->sb.s_blocks_per_group = nbblocks_per_group;
   2019 	fs->sb.s_frags_per_group = nbblocks_per_group;
   2020 	fs->sb.s_inodes_per_group = nbinodes_per_group;
   2021 	fs->sb.s_wtime = fs_timestamp;
   2022 	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
   2023 	fs->sb.s_lastcheck = fs_timestamp;
   2024 
   2025 	// set up groupdescriptors
   2026 	for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
   2027 		i<nbgroups;
   2028 		i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
   2029 	{
   2030 		if(free_blocks > free_blocks_per_group) {
   2031 			fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
   2032 			free_blocks -= free_blocks_per_group;
   2033 		} else {
   2034 			fs->gd[i].bg_free_blocks_count = free_blocks;
   2035 			free_blocks = 0; // this is the last block group
   2036 		}
   2037 		if(i)
   2038 			fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
   2039 		else
   2040 			fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
   2041 							EXT2_FIRST_INO + 2;
   2042 		fs->gd[i].bg_used_dirs_count = 0;
   2043 		fs->gd[i].bg_block_bitmap = bbmpos;
   2044 		fs->gd[i].bg_inode_bitmap = ibmpos;
   2045 		fs->gd[i].bg_inode_table = itblpos;
   2046 	}
   2047 
   2048 	/* Mark non-filesystem blocks and inodes as allocated */
   2049 	/* Mark system blocks and inodes as allocated         */
   2050 	for(i = 0; i<nbgroups;i++) {
   2051 
   2052 		/* Block bitmap */
   2053 		bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
   2054 		//non-filesystem blocks
   2055 		for(j = fs->gd[i].bg_free_blocks_count
   2056 		        + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
   2057 			allocate(bbm, j);
   2058 		//system blocks
   2059 		for(j = 1; j <= overhead_per_group; j++)
   2060 			allocate(bbm, j);
   2061 
   2062 		/* Inode bitmap */
   2063 		ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
   2064 		//non-filesystem inodes
   2065 		for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
   2066 			allocate(ibm, j);
   2067 
   2068 		//system inodes
   2069 		if(i == 0)
   2070 			for(j = 1; j < EXT2_FIRST_INO; j++)
   2071 				allocate(ibm, j);
   2072 	}
   2073 
   2074 	// make root inode and directory
   2075 	/* We have groups now. Add the root filesystem in group 0 */
   2076 	/* Also increment the directory count for group 0 */
   2077 	fs->gd[0].bg_free_inodes_count--;
   2078 	fs->gd[0].bg_used_dirs_count = 1;
   2079 	itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
   2080 	itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
   2081 	itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
   2082 	itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
   2083 	itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
   2084 	itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
   2085 	itab0[EXT2_ROOT_INO-1].i_links_count = 2;
   2086 
   2087 	if(!(b = get_workblk()))
   2088 		error_msg_and_die("get_workblk() failed.");
   2089 	d = (directory*)b;
   2090 	d->d_inode = EXT2_ROOT_INO;
   2091 	d->d_rec_len = sizeof(directory)+4;
   2092 	d->d_name_len = 1;
   2093 	strcpy(d->d_name, ".");
   2094 	d = (directory*)(b + d->d_rec_len);
   2095 	d->d_inode = EXT2_ROOT_INO;
   2096 	d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
   2097 	d->d_name_len = 2;
   2098 	strcpy(d->d_name, "..");
   2099 	extend_blk(fs, EXT2_ROOT_INO, b, 1);
   2100 
   2101 	// make lost+found directory and reserve blocks
   2102 	if(fs->sb.s_r_blocks_count)
   2103 	{
   2104 		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
   2105 		memset(b, 0, BLOCKSIZE);
   2106 		((directory*)b)->d_rec_len = BLOCKSIZE;
   2107 		/* We run into problems with e2fsck if directory lost+found grows
   2108 		 * bigger than this. Need to find out why this happens - sundar
   2109 		 */
   2110 		if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
   2111 			fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
   2112 		for(i = 1; i < fs->sb.s_r_blocks_count; i++)
   2113 			extend_blk(fs, nod, b, 1);
   2114 		get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
   2115 	}
   2116 	free_workblk(b);
   2117 
   2118 	// administrative info
   2119 	fs->sb.s_state = 1;
   2120 	fs->sb.s_max_mnt_count = 20;
   2121 
   2122 	// options for me
   2123 	if(holes)
   2124 		fs->sb.s_reserved[200] |= OP_HOLES;
   2125 
   2126 	return fs;
   2127 }
   2128 
   2129 // loads a filesystem from disk
   2130 static filesystem *
   2131 load_fs(FILE * fh, int swapit)
   2132 {
   2133 	size_t fssize;
   2134 	filesystem *fs;
   2135 	if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
   2136 		perror_msg_and_die("input filesystem image");
   2137 	rewind(fh);
   2138 	fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
   2139 	if(fssize < 16) // totally arbitrary
   2140 		error_msg_and_die("too small filesystem");
   2141 	if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
   2142 		error_msg_and_die("not enough memory for filesystem");
   2143 	if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
   2144 		perror_msg_and_die("input filesystem image");
   2145 	if(swapit)
   2146 		swap_badfs(fs);
   2147 	if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
   2148 		error_msg_and_die("not a suitable ext2 filesystem");
   2149 	return fs;
   2150 }
   2151 
   2152 static void
   2153 free_fs(filesystem *fs)
   2154 {
   2155 	free(fs);
   2156 }
   2157 
   2158 // just walk through blocks list
   2159 static void
   2160 flist_blocks(filesystem *fs, uint32 nod, FILE *fh)
   2161 {
   2162 	blockwalker bw;
   2163 	uint32 bk;
   2164 	init_bw(&bw);
   2165 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2166 		fprintf(fh, " %d", bk);
   2167 	fprintf(fh, "\n");
   2168 }
   2169 
   2170 // walk through blocks list
   2171 static void
   2172 list_blocks(filesystem *fs, uint32 nod)
   2173 {
   2174 	int bn = 0;
   2175 	blockwalker bw;
   2176 	uint32 bk;
   2177 	init_bw(&bw);
   2178 	printf("blocks in inode %d:", nod);
   2179 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2180 		printf(" %d", bk), bn++;
   2181 	printf("\n%d blocks (%d bytes)\n", bn, bn * BLOCKSIZE);
   2182 }
   2183 
   2184 // saves blocks to FILE*
   2185 static void
   2186 write_blocks(filesystem *fs, uint32 nod, FILE* f)
   2187 {
   2188 	blockwalker bw;
   2189 	uint32 bk;
   2190 	int32 fsize = get_nod(fs, nod)->i_size;
   2191 	init_bw(&bw);
   2192 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2193 	{
   2194 		if(fsize <= 0)
   2195 			error_msg_and_die("wrong size while saving inode %d", nod);
   2196 		if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
   2197 			error_msg_and_die("error while saving inode %d", nod);
   2198 		fsize -= BLOCKSIZE;
   2199 	}
   2200 }
   2201 
   2202 
   2203 // print block/char device minor and major
   2204 static void
   2205 print_dev(filesystem *fs, uint32 nod)
   2206 {
   2207 	int minor, major;
   2208 	minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
   2209 	major = ((uint8*)get_nod(fs, nod)->i_block)[1];
   2210 	printf("major: %d, minor: %d\n", major, minor);
   2211 }
   2212 
   2213 // print an inode as a directory
   2214 static void
   2215 print_dir(filesystem *fs, uint32 nod)
   2216 {
   2217 	blockwalker bw;
   2218 	uint32 bk;
   2219 	init_bw(&bw);
   2220 	printf("directory for inode %d:\n", nod);
   2221 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2222 	{
   2223 		directory *d;
   2224 		uint8 *b;
   2225 		b = get_blk(fs, bk);
   2226 		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   2227 			if(d->d_inode)
   2228 			{
   2229 				int i;
   2230 				printf("entry '");
   2231 				for(i = 0; i < d->d_name_len; i++)
   2232 					putchar(d->d_name[i]);
   2233 				printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
   2234 			}
   2235 	}
   2236 }
   2237 
   2238 // print a symbolic link
   2239 static void
   2240 print_link(filesystem *fs, uint32 nod)
   2241 {
   2242 	if(!get_nod(fs, nod)->i_blocks)
   2243 		printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
   2244 	else
   2245 	{
   2246 		printf("links to '");
   2247 		write_blocks(fs, nod, stdout);
   2248 		printf("'\n");
   2249 	}
   2250 }
   2251 
   2252 // make a ls-like printout of permissions
   2253 static void
   2254 make_perms(uint32 mode, char perms[11])
   2255 {
   2256 	strcpy(perms, "----------");
   2257 	if(mode & FM_IRUSR)
   2258 		perms[1] = 'r';
   2259 	if(mode & FM_IWUSR)
   2260 		perms[2] = 'w';
   2261 	if(mode & FM_IXUSR)
   2262 		perms[3] = 'x';
   2263 	if(mode & FM_IRGRP)
   2264 		perms[4] = 'r';
   2265 	if(mode & FM_IWGRP)
   2266 		perms[5] = 'w';
   2267 	if(mode & FM_IXGRP)
   2268 		perms[6] = 'x';
   2269 	if(mode & FM_IROTH)
   2270 		perms[7] = 'r';
   2271 	if(mode & FM_IWOTH)
   2272 		perms[8] = 'w';
   2273 	if(mode & FM_IXOTH)
   2274 		perms[9] = 'x';
   2275 	if(mode & FM_ISUID)
   2276 		perms[3] = 's';
   2277 	if(mode & FM_ISGID)
   2278 		perms[6] = 's';
   2279 	if(mode & FM_ISVTX)
   2280 		perms[9] = 't';
   2281 	switch(mode & FM_IFMT)
   2282 	{
   2283 		case 0:
   2284 			*perms = '0';
   2285 			break;
   2286 		case FM_IFSOCK:
   2287 			*perms = 's';
   2288 			break;
   2289 		case FM_IFLNK:
   2290 			*perms = 'l';
   2291 			break;
   2292 		case FM_IFREG:
   2293 			*perms = '-';
   2294 			break;
   2295 		case FM_IFBLK:
   2296 			*perms = 'b';
   2297 			break;
   2298 		case FM_IFDIR:
   2299 			*perms = 'd';
   2300 			break;
   2301 		case FM_IFCHR:
   2302 			*perms = 'c';
   2303 			break;
   2304 		case FM_IFIFO:
   2305 			*perms = 'p';
   2306 			break;
   2307 		default:
   2308 			*perms = '?';
   2309 	}
   2310 }
   2311 
   2312 // print an inode
   2313 static void
   2314 print_inode(filesystem *fs, uint32 nod)
   2315 {
   2316 	char *s;
   2317 	char perms[11];
   2318 	if(!get_nod(fs, nod)->i_mode)
   2319 		return;
   2320 	switch(nod)
   2321 	{
   2322 		case EXT2_BAD_INO:
   2323 			s = "bad blocks";
   2324 			break;
   2325 		case EXT2_ROOT_INO:
   2326 			s = "root";
   2327 			break;
   2328 		case EXT2_ACL_IDX_INO:
   2329 		case EXT2_ACL_DATA_INO:
   2330 			s = "ACL";
   2331 			break;
   2332 		case EXT2_BOOT_LOADER_INO:
   2333 			s = "boot loader";
   2334 			break;
   2335 		case EXT2_UNDEL_DIR_INO:
   2336 			s = "undelete directory";
   2337 			break;
   2338 		default:
   2339 			s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
   2340 	}
   2341 	printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
   2342 	if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
   2343 	{
   2344 		printf("unallocated\n");
   2345 		return;
   2346 	}
   2347 	make_perms(get_nod(fs, nod)->i_mode, perms);
   2348 	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));
   2349 	switch(get_nod(fs, nod)->i_mode & FM_IFMT)
   2350 	{
   2351 		case FM_IFSOCK:
   2352 			list_blocks(fs, nod);
   2353 			break;
   2354 		case FM_IFLNK:
   2355 			print_link(fs, nod);
   2356 			break;
   2357 		case FM_IFREG:
   2358 			list_blocks(fs, nod);
   2359 			break;
   2360 		case FM_IFBLK:
   2361 			print_dev(fs, nod);
   2362 			break;
   2363 		case FM_IFDIR:
   2364 			list_blocks(fs, nod);
   2365 			print_dir(fs, nod);
   2366 			break;
   2367 		case FM_IFCHR:
   2368 			print_dev(fs, nod);
   2369 			break;
   2370 		case FM_IFIFO:
   2371 			list_blocks(fs, nod);
   2372 			break;
   2373 		default:
   2374 			list_blocks(fs, nod);
   2375 	}
   2376 	printf("Done with inode %d\n",nod);
   2377 }
   2378 
   2379 // describes various fields in a filesystem
   2380 static void
   2381 print_fs(filesystem *fs)
   2382 {
   2383 	uint32 i;
   2384 	uint8 *ibm;
   2385 
   2386 	printf("%d blocks (%d free, %d reserved), first data block: %d\n",
   2387 	       fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
   2388 	       fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
   2389 	printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
   2390 	       fs->sb.s_free_inodes_count);
   2391 	printf("block size = %d, frag size = %d\n",
   2392 	       fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
   2393 	       fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
   2394 	printf("number of groups: %d\n",GRP_NBGROUPS(fs));
   2395 	printf("%d blocks per group,%d frags per group,%d inodes per group\n",
   2396 	     fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
   2397 	     fs->sb.s_inodes_per_group);
   2398 	printf("Size of inode table: %d blocks\n",
   2399 		(int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
   2400 	for (i = 0; i < GRP_NBGROUPS(fs); i++) {
   2401 		printf("Group No: %d\n", i+1);
   2402 		printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
   2403 		     fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
   2404 		     fs->gd[i].bg_inode_table);
   2405 		printf("block bitmap allocation:\n");
   2406 		print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
   2407 		printf("inode bitmap allocation:\n");
   2408 		ibm = GRP_GET_GROUP_IBM(fs, i);
   2409 		print_bm(ibm, fs->sb.s_inodes_per_group);
   2410 		for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
   2411 			if (allocated(ibm, i))
   2412 				print_inode(fs, i);
   2413 	}
   2414 }
   2415 
   2416 static void
   2417 dump_fs(filesystem *fs, FILE * fh, int swapit)
   2418 {
   2419 	uint32 nbblocks = fs->sb.s_blocks_count;
   2420 	fs->sb.s_reserved[200] = 0;
   2421 	if(swapit)
   2422 		swap_goodfs(fs);
   2423 	if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
   2424 		perror_msg_and_die("output filesystem image");
   2425 	if(swapit)
   2426 		swap_badfs(fs);
   2427 }
   2428 
   2429 static void
   2430 populate_fs(filesystem *fs, char **dopt, int didx, int squash_uids, int squash_perms, int fixstats, uint32 fs_timestamp, struct stats *stats)
   2431 {
   2432 	int i;
   2433 	for(i = 0; i < didx; i++)
   2434 	{
   2435 		struct stat st;
   2436 		FILE *fh;
   2437 		int pdir;
   2438 		char *pdest;
   2439 		uint32 nod = EXT2_ROOT_INO;
   2440 		if(fs)
   2441 			if((pdest = strchr(dopt[i], ':')))
   2442 			{
   2443 				*(pdest++) = 0;
   2444 				if(!(nod = find_path(fs, EXT2_ROOT_INO, pdest)))
   2445 					error_msg_and_die("path %s not found in filesystem", pdest);
   2446 			}
   2447 		stat(dopt[i], &st);
   2448 		switch(st.st_mode & S_IFMT)
   2449 		{
   2450 			case S_IFREG:
   2451 				fh = xfopen(dopt[i], "rb");
   2452 				add2fs_from_file(fs, nod, fh, fs_timestamp, stats);
   2453 				fclose(fh);
   2454 				break;
   2455 			case S_IFDIR:
   2456 				if((pdir = open(".", O_RDONLY)) < 0)
   2457 					perror_msg_and_die(".");
   2458 				if(chdir(dopt[i]) < 0)
   2459 					perror_msg_and_die(dopt[i]);
   2460 				if (fixstats)
   2461 					prep_stat(dopt[i]);
   2462 				add2fs_from_dir(fs, dopt[i], nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   2463 				if(fchdir(pdir) < 0)
   2464 					perror_msg_and_die("fchdir");
   2465 				if(close(pdir) < 0)
   2466 					perror_msg_and_die("close");
   2467 				break;
   2468 			default:
   2469 				error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
   2470 		}
   2471 	}
   2472 }
   2473 
   2474 static void
   2475 showversion(void)
   2476 {
   2477 	printf("genext2fs " VERSION "\n");
   2478 }
   2479 
   2480 static void
   2481 showhelp(void)
   2482 {
   2483 	fprintf(stderr, "Usage: %s [options] image\n"
   2484 	"Create an ext2 filesystem image from directories/files\n\n"
   2485 	"  -x, --starting-image <image>\n"
   2486 	"  -d, --root <directory>\n"
   2487 	"  -D, --devtable <file>\n"
   2488 	"  -b, --size-in-blocks <blocks>\n"
   2489 	"  -i, --bytes-per-inode <bytes per inode>\n"
   2490 	"  -N, --number-of-inodes <number of inodes>\n"
   2491 	"  -m, --reserved-percentage <percentage of blocks to reserve>\n"
   2492 	"  -g, --block-map <path>     Generate a block map file for this path.\n"
   2493 	"  -e, --fill-value <value>   Fill unallocated blocks with value.\n"
   2494 	"  -z, --allow-holes          Allow files with holes.\n"
   2495 	"  -f, --faketime             Set filesystem timestamps to 0 (for testing).\n"
   2496 	"  -q, --squash               Same as \"-U -P\".\n"
   2497 	"  -U, --squash-uids          Squash owners making all files be owned by root.\n"
   2498 	"  -P, --squash-perms         Squash permissions on all files.\n"
   2499 	"  -a, --fix-android-stats    Fix-up file stats (user, perms, ...)\n"
   2500 	"  -h, --help\n"
   2501 	"  -V, --version\n"
   2502 	"  -v, --verbose\n\n"
   2503 	"Report bugs to genext2fs-devel (at) lists.sourceforge.net\n", app_name);
   2504 }
   2505 
   2506 #define MAX_DOPT 128
   2507 #define MAX_GOPT 128
   2508 
   2509 #define MAX_FILENAME 255
   2510 
   2511 extern char* optarg;
   2512 extern int optind, opterr, optopt;
   2513 
   2514 int
   2515 main(int argc, char **argv)
   2516 {
   2517 	int nbblocks = -1;
   2518 	int nbinodes = -1;
   2519 	int nbresrvd = -1;
   2520 	float bytes_per_inode = -1;
   2521 	float reserved_frac = -1;
   2522 	int fs_timestamp = -1;
   2523 	char * fsout = "-";
   2524 	char * fsin = 0;
   2525 	char * dopt[MAX_DOPT];
   2526 	int didx = 0;
   2527 	char * gopt[MAX_GOPT];
   2528 	int gidx = 0;
   2529 	int verbose = 0;
   2530 	int holes = 0;
   2531 	int emptyval = 0;
   2532 	int squash_uids = 0;
   2533 	int squash_perms = 0;
   2534 	int fix_android_stats = 0;
   2535 	uint16 endian = 1;
   2536 	int bigendian = !*(char*)&endian;
   2537 	filesystem *fs;
   2538 	int i;
   2539 	int c;
   2540 	struct stats stats;
   2541 
   2542 #if HAVE_GETOPT_LONG
   2543 	struct option longopts[] = {
   2544 	  { "starting-image",	required_argument,	NULL, 'x' },
   2545 	  { "root",		required_argument,	NULL, 'd' },
   2546 	  { "devtable",		required_argument,	NULL, 'D' },
   2547 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
   2548 	  { "bytes-per-inode",	required_argument,	NULL, 'i' },
   2549 	  { "number-of-inodes",	required_argument,	NULL, 'N' },
   2550 	  { "reserved-percentage", required_argument,	NULL, 'm' },
   2551 	  { "block-map",	required_argument,	NULL, 'g' },
   2552 	  { "fill-value",	required_argument,	NULL, 'e' },
   2553 	  { "allow-holes",	no_argument, 		NULL, 'z' },
   2554 	  { "faketime",		no_argument,		NULL, 'f' },
   2555 	  { "squash",		no_argument,		NULL, 'q' },
   2556 	  { "squash-uids",	no_argument,		NULL, 'U' },
   2557 	  { "squash-perms",	no_argument,		NULL, 'P' },
   2558 	  { "fix-android-stats",no_argument,		NULL, 'a' },
   2559 	  { "help",		no_argument,		NULL, 'h' },
   2560 	  { "version",		no_argument,		NULL, 'V' },
   2561 	  { "verbose",		no_argument,		NULL, 'v' },
   2562 	  { 0, 0, 0, 0}
   2563 	} ;
   2564 
   2565 	app_name = argv[0];
   2566 
   2567 	while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPahVv", longopts, NULL)) != EOF) {
   2568 #else
   2569 	app_name = argv[0];
   2570 
   2571 	while((c = getopt(argc, argv,      "x:d:D:b:i:N:m:g:e:zfqUPahVv")) != EOF) {
   2572 #endif /* HAVE_GETOPT_LONG */
   2573 		switch(c)
   2574 		{
   2575 			case 'x':
   2576 				fsin = optarg;
   2577 				break;
   2578 			case 'd':
   2579 			case 'D':
   2580 				dopt[didx++] = optarg;
   2581 				break;
   2582 			case 'b':
   2583 				nbblocks = SI_atof(optarg);
   2584 				break;
   2585 			case 'i':
   2586 				bytes_per_inode = SI_atof(optarg);
   2587 				break;
   2588 			case 'N':
   2589 				nbinodes = SI_atof(optarg);
   2590 				break;
   2591 			case 'm':
   2592 				reserved_frac = SI_atof(optarg) / 100;
   2593 				break;
   2594 			case 'g':
   2595 				gopt[gidx++] = optarg;
   2596 				break;
   2597 			case 'e':
   2598 				emptyval = atoi(optarg);
   2599 				break;
   2600 			case 'z':
   2601 				holes = 1;
   2602 				break;
   2603 			case 'f':
   2604 				fs_timestamp = 0;
   2605 				break;
   2606 			case 'q':
   2607 				squash_uids = 1;
   2608 				squash_perms = 1;
   2609 				break;
   2610 			case 'U':
   2611 				squash_uids = 1;
   2612 				break;
   2613 			case 'P':
   2614 				squash_perms = 1;
   2615 				break;
   2616 			case 'a':
   2617 				fix_android_stats = 1;
   2618 				break;
   2619 			case 'h':
   2620 				showhelp();
   2621 				exit(0);
   2622 			case 'V':
   2623 				showversion();
   2624 				exit(0);
   2625 			case 'v':
   2626 				verbose = 1;
   2627 				showversion();
   2628 				break;
   2629 			default:
   2630 				error_msg_and_die("Note: options have changed, see --help or the man page.");
   2631 		}
   2632 	}
   2633 
   2634 	if(optind < (argc - 1))
   2635 		error_msg_and_die("Too many arguments. Try --help or else see the man page.");
   2636 	if(optind > (argc - 1))
   2637 		error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
   2638 
   2639 	if(fix_android_stats && (squash_uids || squash_perms))
   2640 		error_msg_and_die("Cannot squash uid/perms and fix them up for Android at the same time.");
   2641 
   2642 	fsout = argv[optind];
   2643 
   2644 	hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
   2645 	if (!hdlinks.hdl)
   2646 		error_msg_and_die("Not enough memory");
   2647 	hdlinks.count = 0 ;
   2648 
   2649 	if(fsin)
   2650 	{
   2651 		if(strcmp(fsin, "-"))
   2652 		{
   2653 			FILE * fh = xfopen(fsin, "rb");
   2654 			fs = load_fs(fh, bigendian);
   2655 			fclose(fh);
   2656 		}
   2657 		else
   2658 			fs = load_fs(stdin, bigendian);
   2659 	}
   2660 	else
   2661 	{
   2662 		if(reserved_frac == -1)
   2663 			nbresrvd = nbblocks * RESERVED_BLOCKS;
   2664 		else
   2665 			nbresrvd = nbblocks * reserved_frac;
   2666 
   2667 		stats.ninodes = EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0);
   2668 		stats.nblocks = 0;
   2669 
   2670 		populate_fs(NULL, dopt, didx, squash_uids, squash_perms, 0, fs_timestamp, &stats);
   2671 
   2672 		if(nbinodes == -1)
   2673 			nbinodes = stats.ninodes;
   2674 		else
   2675 			if(stats.ninodes > (unsigned long)nbinodes)
   2676 			{
   2677 				fprintf(stderr, "number of inodes too low, increasing to %ld\n", stats.ninodes);
   2678 				nbinodes = stats.ninodes;
   2679 			}
   2680 
   2681 		if(bytes_per_inode != -1) {
   2682 			int tmp_nbinodes = nbblocks * BLOCKSIZE / bytes_per_inode;
   2683 			if(tmp_nbinodes > nbinodes)
   2684 				nbinodes = tmp_nbinodes;
   2685 		}
   2686 		if(fs_timestamp == -1)
   2687 			fs_timestamp = time(NULL);
   2688 		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
   2689 	}
   2690 
   2691 	populate_fs(fs, dopt, didx, squash_uids, squash_perms, fix_android_stats, fs_timestamp, NULL);
   2692 
   2693 	if(emptyval) {
   2694 		uint32 b;
   2695 		for(b = 1; b < fs->sb.s_blocks_count; b++)
   2696 			if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
   2697 				memset(get_blk(fs, b), emptyval, BLOCKSIZE);
   2698 	}
   2699 	if(verbose)
   2700 		print_fs(fs);
   2701 	for(i = 0; i < gidx; i++)
   2702 	{
   2703 		uint32 nod;
   2704 		char fname[MAX_FILENAME];
   2705 		char *p;
   2706 		FILE *fh;
   2707 		if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
   2708 			error_msg_and_die("path %s not found in filesystem", gopt[i]);
   2709 		while((p = strchr(gopt[i], '/')))
   2710 			*p = '_';
   2711 		SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
   2712 		fh = xfopen(fname, "wb");
   2713 		fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
   2714 		flist_blocks(fs, nod, fh);
   2715 		fclose(fh);
   2716 	}
   2717 	if(strcmp(fsout, "-"))
   2718 	{
   2719 		FILE * fh = xfopen(fsout, "wb");
   2720 		dump_fs(fs, fh, bigendian);
   2721 		fclose(fh);
   2722 	}
   2723 	else
   2724 		dump_fs(fs, stdout, bigendian);
   2725 	free_fs(fs);
   2726 	return 0;
   2727 }
   2728