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 	path += source_path_len;
   1649 	fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
   1650 }
   1651 
   1652 // adds a tree of entries to the filesystem from current dir
   1653 static void
   1654 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)
   1655 {
   1656 	uint32 nod;
   1657 	uint32 uid, gid, mode, ctime, mtime;
   1658 	const char *name;
   1659 	FILE *fh;
   1660 	DIR *dh;
   1661 	struct dirent *dent;
   1662 	struct stat st;
   1663 	char *lnk;
   1664 	uint32 save_nod;
   1665 	char full_name[2048];
   1666 
   1667 	if(!(dh = opendir(".")))
   1668 		perror_msg_and_die(".");
   1669 	while((dent = readdir(dh)))
   1670 	{
   1671 		if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
   1672 			continue;
   1673 
   1674 		lstat(dent->d_name, &st);
   1675 
   1676 		if(fixstats) {
   1677 			int tmp = snprintf(full_name, sizeof(full_name),
   1678 			                   "%s/%s", path, dent->d_name);
   1679 			if(tmp >= (int)sizeof(full_name))
   1680 				error_msg_and_die("Path too long!");
   1681 			fix_stat(full_name, &st);
   1682 		} else
   1683 			full_name[0] = '\0';
   1684 		uid = st.st_uid;
   1685 		gid = st.st_gid;
   1686 		ctime = fs_timestamp;
   1687 		mtime = st.st_mtime;
   1688 		name = dent->d_name;
   1689 		mode = get_mode(&st);
   1690 		if(squash_uids)
   1691 			uid = gid = 0;
   1692 		if(squash_perms)
   1693 			mode &= ~(FM_IRWXG | FM_IRWXO);
   1694 		if(stats)
   1695 			switch(st.st_mode & S_IFMT)
   1696 			{
   1697 				case S_IFLNK:
   1698 				case S_IFREG:
   1699 					if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
   1700 						stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
   1701 				case S_IFCHR:
   1702 				case S_IFBLK:
   1703 				case S_IFIFO:
   1704 				case S_IFSOCK:
   1705 					stats->ninodes++;
   1706 					break;
   1707 				case S_IFDIR:
   1708 					stats->ninodes++;
   1709 					if(chdir(dent->d_name) < 0)
   1710 						perror_msg_and_die(dent->d_name);
   1711 					add2fs_from_dir(fs, full_name, this_nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1712 					chdir("..");
   1713 					break;
   1714 				default:
   1715 					break;
   1716 			}
   1717 		else
   1718 		{
   1719 			if((nod = find_dir(fs, this_nod, name)))
   1720 			{
   1721 				error_msg("ignoring duplicate entry %s", name);
   1722 				if(S_ISDIR(st.st_mode)) {
   1723 					if(chdir(dent->d_name) < 0)
   1724 						perror_msg_and_die(name);
   1725 					add2fs_from_dir(fs, full_name, nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1726 					chdir("..");
   1727 				}
   1728 				continue;
   1729 			}
   1730 			save_nod = 0;
   1731 			/* Check for hardlinks */
   1732 			if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
   1733 				int32 hdlink = is_hardlink(st.st_ino);
   1734 				if (hdlink >= 0) {
   1735 					add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
   1736 					continue;
   1737 				} else {
   1738 					save_nod = 1;
   1739 				}
   1740 			}
   1741 			switch(st.st_mode & S_IFMT)
   1742 			{
   1743 #if HAVE_STRUCT_STAT_ST_RDEV
   1744 				case S_IFCHR:
   1745 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFCHR, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
   1746 					break;
   1747 				case S_IFBLK:
   1748 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFBLK, uid, gid, major(st.st_rdev), minor(st.st_rdev), ctime, mtime);
   1749 					break;
   1750 #endif
   1751 				case S_IFIFO:
   1752 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFIFO, uid, gid, 0, 0, ctime, mtime);
   1753 					break;
   1754 				case S_IFSOCK:
   1755 					nod = mknod_fs(fs, this_nod, name, mode|FM_IFSOCK, uid, gid, 0, 0, ctime, mtime);
   1756 					break;
   1757 				case S_IFLNK:
   1758 					lnk = xreadlink(dent->d_name);
   1759 					mklink_fs(fs, this_nod, name, st.st_size, (uint8*)lnk, uid, gid, ctime, mtime);
   1760 					free(lnk);
   1761 					break;
   1762 				case S_IFREG:
   1763 					fh = xfopen(dent->d_name, "rb");
   1764 					nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
   1765 					fclose(fh);
   1766 					break;
   1767 				case S_IFDIR:
   1768 					nod = mkdir_fs(fs, this_nod, name, mode, uid, gid, ctime, mtime);
   1769 					if(chdir(dent->d_name) < 0)
   1770 						perror_msg_and_die(name);
   1771 					add2fs_from_dir(fs, full_name, nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   1772 					chdir("..");
   1773 					break;
   1774 				default:
   1775 					error_msg("ignoring entry %s", name);
   1776 			}
   1777 			if (save_nod) {
   1778 				if (hdlinks.count == hdlink_cnt) {
   1779 					if ((hdlinks.hdl =
   1780 						 realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
   1781 								  sizeof (struct hdlink_s))) == NULL) {
   1782 						error_msg_and_die("Not enough memory");
   1783 					}
   1784 					hdlink_cnt += HDLINK_CNT;
   1785 				}
   1786 				hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
   1787 				hdlinks.hdl[hdlinks.count].dst_nod = nod;
   1788 				hdlinks.count++;
   1789 			}
   1790 		}
   1791 	}
   1792 	closedir(dh);
   1793 }
   1794 
   1795 // endianness swap of x-indirect blocks
   1796 static void
   1797 swap_goodblocks(filesystem *fs, inode *nod)
   1798 {
   1799 	uint32 i,j;
   1800 	int done=0;
   1801 	uint32 *b,*b2;
   1802 
   1803 	uint32 nblk = nod->i_blocks / INOBLK;
   1804 	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
   1805 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
   1806 			nod->i_block[i] = swab32(nod->i_block[i]);
   1807 	if(nblk <= EXT2_IND_BLOCK)
   1808 		return;
   1809 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
   1810 	if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
   1811 		return;
   1812 	/* Currently this will fail b'cos the number of blocks as stored
   1813 	   in i_blocks also includes the indirection blocks (see
   1814 	   walk_bw). But this function assumes that i_blocks only
   1815 	   stores the count of data blocks ( Actually according to
   1816 	   "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
   1817 	   i_blocks IS supposed to store the count of data blocks). so
   1818 	   with a file of size 268K nblk would be 269.The above check
   1819 	   will be false even though double indirection hasn't been
   1820 	   started.This is benign as 0 means block 0 which has been
   1821 	   zeroed out and therefore points back to itself from any offset
   1822 	 */
   1823 	// FIXME: I have fixed that, but I have the feeling the rest of
   1824 	// ths function needs to be fixed for the same reasons - Xav
   1825 	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
   1826 	for(i = 0; i < BLOCKSIZE/4; i++)
   1827 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
   1828 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
   1829 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
   1830 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
   1831 		return;
   1832 	/* Adding support for triple indirection */
   1833 	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
   1834 	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
   1835 		b2 = (uint32*)get_blk(fs,b[i]);
   1836 		for(j=0; j<BLOCKSIZE/4;j++) {
   1837 			if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
   1838 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1839 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1840 				     j*(BLOCKSIZE/4)) )
   1841 			  swap_block(get_blk(fs,b2[j]));
   1842 			else {
   1843 			  done = 1;
   1844 			  break;
   1845 			}
   1846 		}
   1847 		swap_block((uint8 *)b2);
   1848 	}
   1849 	swap_block((uint8 *)b);
   1850 	return;
   1851 }
   1852 
   1853 static void
   1854 swap_badblocks(filesystem *fs, inode *nod)
   1855 {
   1856 	uint32 i,j;
   1857 	int done=0;
   1858 	uint32 *b,*b2;
   1859 
   1860 	uint32 nblk = nod->i_blocks / INOBLK;
   1861 	if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
   1862 		for(i = 0; i <= EXT2_TIND_BLOCK; i++)
   1863 			nod->i_block[i] = swab32(nod->i_block[i]);
   1864 	if(nblk <= EXT2_IND_BLOCK)
   1865 		return;
   1866 	swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
   1867 	if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
   1868 		return;
   1869 	/* See comment in swap_goodblocks */
   1870 	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
   1871 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
   1872 	for(i = 0; i < BLOCKSIZE/4; i++)
   1873 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
   1874 			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
   1875 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
   1876 		return;
   1877 	/* Adding support for triple indirection */
   1878 	b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
   1879 	swap_block((uint8 *)b);
   1880 	for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
   1881 		b2 = (uint32*)get_blk(fs,b[i]);
   1882 		swap_block((uint8 *)b2);
   1883 		for(j=0; j<BLOCKSIZE/4;j++) {
   1884 			if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
   1885 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1886 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
   1887 				     j*(BLOCKSIZE/4)) )
   1888 			  swap_block(get_blk(fs,b2[j]));
   1889 			else {
   1890 			  done = 1;
   1891 			  break;
   1892 			}
   1893 		}
   1894 	}
   1895 	return;
   1896 }
   1897 
   1898 // endianness swap of the whole filesystem
   1899 static void
   1900 swap_goodfs(filesystem *fs)
   1901 {
   1902 	uint32 i;
   1903 	for(i = 1; i < fs->sb.s_inodes_count; i++)
   1904 	{
   1905 		inode *nod = get_nod(fs, i);
   1906 		if(nod->i_mode & FM_IFDIR)
   1907 		{
   1908 			blockwalker bw;
   1909 			uint32 bk;
   1910 			init_bw(&bw);
   1911 			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
   1912 			{
   1913 				directory *d;
   1914 				uint8 *b;
   1915 				b = get_blk(fs, bk);
   1916 				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
   1917 					swap_dir(d);
   1918 			}
   1919 		}
   1920 		swap_goodblocks(fs, nod);
   1921 		swap_nod(nod);
   1922 	}
   1923 	for(i=0;i<GRP_NBGROUPS(fs);i++)
   1924 		swap_gd(&(fs->gd[i]));
   1925 	swap_sb(&fs->sb);
   1926 }
   1927 
   1928 static void
   1929 swap_badfs(filesystem *fs)
   1930 {
   1931 	uint32 i;
   1932 	swap_sb(&fs->sb);
   1933 	for(i=0;i<GRP_NBGROUPS(fs);i++)
   1934 		swap_gd(&(fs->gd[i]));
   1935 	for(i = 1; i < fs->sb.s_inodes_count; i++)
   1936 	{
   1937 		inode *nod = get_nod(fs, i);
   1938 		swap_nod(nod);
   1939 		swap_badblocks(fs, nod);
   1940 		if(nod->i_mode & FM_IFDIR)
   1941 		{
   1942 			blockwalker bw;
   1943 			uint32 bk;
   1944 			init_bw(&bw);
   1945 			while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
   1946 			{
   1947 				directory *d;
   1948 				uint8 *b;
   1949 				b = get_blk(fs, bk);
   1950 				for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   1951 					swap_dir(d);
   1952 			}
   1953 		}
   1954 	}
   1955 }
   1956 
   1957 // initialize an empty filesystem
   1958 static filesystem *
   1959 init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
   1960 {
   1961 	uint32 i;
   1962 	filesystem *fs;
   1963 	directory *d;
   1964 	uint8 * b;
   1965 	uint32 nod, first_block;
   1966 	uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
   1967 		free_blocks_per_group,nbblocks_per_group,min_nbgroups;
   1968 	uint32 gdsz,itblsz,bbmpos,ibmpos,itblpos;
   1969 	uint32 j;
   1970 	uint8 *bbm,*ibm;
   1971 	inode *itab0;
   1972 
   1973 	if(nbresrvd < 0)
   1974 		error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
   1975 	if(nbinodes < EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0))
   1976 		error_msg_and_die("too few inodes. Note: options have changed, see --help or the man page.");
   1977 	if(nbblocks < 8)
   1978 		error_msg_and_die("too few blocks. Note: options have changed, see --help or the man page.");
   1979 
   1980 	/* nbinodes is the total number of inodes in the system.
   1981 	 * a block group can have no more than 8192 inodes.
   1982 	 */
   1983 	min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
   1984 
   1985 	/* nbblocks is the total number of blocks in the filesystem.
   1986 	 * a block group can have no more than 8192 blocks.
   1987 	 */
   1988 	first_block = (BLOCKSIZE == 1024);
   1989 	nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
   1990 	if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
   1991 	nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
   1992 	nbinodes_per_group = rndup((nbinodes + nbgroups - 1)/nbgroups,
   1993 						(BLOCKSIZE/sizeof(inode)));
   1994 	if (nbinodes_per_group < 16)
   1995 		nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
   1996 
   1997 	gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
   1998 	itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
   1999 	overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
   2000 	if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
   2001 		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
   2002 	free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
   2003 	free_blocks_per_group = nbblocks_per_group - overhead_per_group;
   2004 
   2005 	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
   2006 		error_msg_and_die("not enough memory for filesystem");
   2007 
   2008 	// create the superblock for an empty filesystem
   2009 	fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
   2010 	fs->sb.s_blocks_count = nbblocks;
   2011 	fs->sb.s_r_blocks_count = nbresrvd;
   2012 	fs->sb.s_free_blocks_count = free_blocks;
   2013 	fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
   2014 	fs->sb.s_first_data_block = first_block;
   2015 	fs->sb.s_log_block_size = BLOCKSIZE >> 11;
   2016 	fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
   2017 	fs->sb.s_blocks_per_group = nbblocks_per_group;
   2018 	fs->sb.s_frags_per_group = nbblocks_per_group;
   2019 	fs->sb.s_inodes_per_group = nbinodes_per_group;
   2020 	fs->sb.s_wtime = fs_timestamp;
   2021 	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
   2022 	fs->sb.s_lastcheck = fs_timestamp;
   2023 
   2024 	// set up groupdescriptors
   2025 	for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
   2026 		i<nbgroups;
   2027 		i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
   2028 	{
   2029 		if(free_blocks > free_blocks_per_group) {
   2030 			fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
   2031 			free_blocks -= free_blocks_per_group;
   2032 		} else {
   2033 			fs->gd[i].bg_free_blocks_count = free_blocks;
   2034 			free_blocks = 0; // this is the last block group
   2035 		}
   2036 		if(i)
   2037 			fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
   2038 		else
   2039 			fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
   2040 							EXT2_FIRST_INO + 2;
   2041 		fs->gd[i].bg_used_dirs_count = 0;
   2042 		fs->gd[i].bg_block_bitmap = bbmpos;
   2043 		fs->gd[i].bg_inode_bitmap = ibmpos;
   2044 		fs->gd[i].bg_inode_table = itblpos;
   2045 	}
   2046 
   2047 	/* Mark non-filesystem blocks and inodes as allocated */
   2048 	/* Mark system blocks and inodes as allocated         */
   2049 	for(i = 0; i<nbgroups;i++) {
   2050 
   2051 		/* Block bitmap */
   2052 		bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
   2053 		//non-filesystem blocks
   2054 		for(j = fs->gd[i].bg_free_blocks_count
   2055 		        + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
   2056 			allocate(bbm, j);
   2057 		//system blocks
   2058 		for(j = 1; j <= overhead_per_group; j++)
   2059 			allocate(bbm, j);
   2060 
   2061 		/* Inode bitmap */
   2062 		ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
   2063 		//non-filesystem inodes
   2064 		for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
   2065 			allocate(ibm, j);
   2066 
   2067 		//system inodes
   2068 		if(i == 0)
   2069 			for(j = 1; j < EXT2_FIRST_INO; j++)
   2070 				allocate(ibm, j);
   2071 	}
   2072 
   2073 	// make root inode and directory
   2074 	/* We have groups now. Add the root filesystem in group 0 */
   2075 	/* Also increment the directory count for group 0 */
   2076 	fs->gd[0].bg_free_inodes_count--;
   2077 	fs->gd[0].bg_used_dirs_count = 1;
   2078 	itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
   2079 	itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
   2080 	itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
   2081 	itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
   2082 	itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
   2083 	itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
   2084 	itab0[EXT2_ROOT_INO-1].i_links_count = 2;
   2085 
   2086 	if(!(b = get_workblk()))
   2087 		error_msg_and_die("get_workblk() failed.");
   2088 	d = (directory*)b;
   2089 	d->d_inode = EXT2_ROOT_INO;
   2090 	d->d_rec_len = sizeof(directory)+4;
   2091 	d->d_name_len = 1;
   2092 	strcpy(d->d_name, ".");
   2093 	d = (directory*)(b + d->d_rec_len);
   2094 	d->d_inode = EXT2_ROOT_INO;
   2095 	d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
   2096 	d->d_name_len = 2;
   2097 	strcpy(d->d_name, "..");
   2098 	extend_blk(fs, EXT2_ROOT_INO, b, 1);
   2099 
   2100 	// make lost+found directory and reserve blocks
   2101 	if(fs->sb.s_r_blocks_count)
   2102 	{
   2103 		nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
   2104 		memset(b, 0, BLOCKSIZE);
   2105 		((directory*)b)->d_rec_len = BLOCKSIZE;
   2106 		/* We run into problems with e2fsck if directory lost+found grows
   2107 		 * bigger than this. Need to find out why this happens - sundar
   2108 		 */
   2109 		if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
   2110 			fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
   2111 		for(i = 1; i < fs->sb.s_r_blocks_count; i++)
   2112 			extend_blk(fs, nod, b, 1);
   2113 		get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
   2114 	}
   2115 	free_workblk(b);
   2116 
   2117 	// administrative info
   2118 	fs->sb.s_state = 1;
   2119 	fs->sb.s_max_mnt_count = 20;
   2120 
   2121 	// options for me
   2122 	if(holes)
   2123 		fs->sb.s_reserved[200] |= OP_HOLES;
   2124 
   2125 	return fs;
   2126 }
   2127 
   2128 // loads a filesystem from disk
   2129 static filesystem *
   2130 load_fs(FILE * fh, int swapit)
   2131 {
   2132 	size_t fssize;
   2133 	filesystem *fs;
   2134 	if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
   2135 		perror_msg_and_die("input filesystem image");
   2136 	rewind(fh);
   2137 	fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
   2138 	if(fssize < 16) // totally arbitrary
   2139 		error_msg_and_die("too small filesystem");
   2140 	if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
   2141 		error_msg_and_die("not enough memory for filesystem");
   2142 	if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
   2143 		perror_msg_and_die("input filesystem image");
   2144 	if(swapit)
   2145 		swap_badfs(fs);
   2146 	if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
   2147 		error_msg_and_die("not a suitable ext2 filesystem");
   2148 	return fs;
   2149 }
   2150 
   2151 static void
   2152 free_fs(filesystem *fs)
   2153 {
   2154 	free(fs);
   2155 }
   2156 
   2157 // just walk through blocks list
   2158 static void
   2159 flist_blocks(filesystem *fs, uint32 nod, FILE *fh)
   2160 {
   2161 	blockwalker bw;
   2162 	uint32 bk;
   2163 	init_bw(&bw);
   2164 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2165 		fprintf(fh, " %d", bk);
   2166 	fprintf(fh, "\n");
   2167 }
   2168 
   2169 // walk through blocks list
   2170 static void
   2171 list_blocks(filesystem *fs, uint32 nod)
   2172 {
   2173 	int bn = 0;
   2174 	blockwalker bw;
   2175 	uint32 bk;
   2176 	init_bw(&bw);
   2177 	printf("blocks in inode %d:", nod);
   2178 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2179 		printf(" %d", bk), bn++;
   2180 	printf("\n%d blocks (%d bytes)\n", bn, bn * BLOCKSIZE);
   2181 }
   2182 
   2183 // saves blocks to FILE*
   2184 static void
   2185 write_blocks(filesystem *fs, uint32 nod, FILE* f)
   2186 {
   2187 	blockwalker bw;
   2188 	uint32 bk;
   2189 	int32 fsize = get_nod(fs, nod)->i_size;
   2190 	init_bw(&bw);
   2191 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2192 	{
   2193 		if(fsize <= 0)
   2194 			error_msg_and_die("wrong size while saving inode %d", nod);
   2195 		if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
   2196 			error_msg_and_die("error while saving inode %d", nod);
   2197 		fsize -= BLOCKSIZE;
   2198 	}
   2199 }
   2200 
   2201 
   2202 // print block/char device minor and major
   2203 static void
   2204 print_dev(filesystem *fs, uint32 nod)
   2205 {
   2206 	int minor, major;
   2207 	minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
   2208 	major = ((uint8*)get_nod(fs, nod)->i_block)[1];
   2209 	printf("major: %d, minor: %d\n", major, minor);
   2210 }
   2211 
   2212 // print an inode as a directory
   2213 static void
   2214 print_dir(filesystem *fs, uint32 nod)
   2215 {
   2216 	blockwalker bw;
   2217 	uint32 bk;
   2218 	init_bw(&bw);
   2219 	printf("directory for inode %d:\n", nod);
   2220 	while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
   2221 	{
   2222 		directory *d;
   2223 		uint8 *b;
   2224 		b = get_blk(fs, bk);
   2225 		for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
   2226 			if(d->d_inode)
   2227 			{
   2228 				int i;
   2229 				printf("entry '");
   2230 				for(i = 0; i < d->d_name_len; i++)
   2231 					putchar(d->d_name[i]);
   2232 				printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
   2233 			}
   2234 	}
   2235 }
   2236 
   2237 // print a symbolic link
   2238 static void
   2239 print_link(filesystem *fs, uint32 nod)
   2240 {
   2241 	if(!get_nod(fs, nod)->i_blocks)
   2242 		printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
   2243 	else
   2244 	{
   2245 		printf("links to '");
   2246 		write_blocks(fs, nod, stdout);
   2247 		printf("'\n");
   2248 	}
   2249 }
   2250 
   2251 // make a ls-like printout of permissions
   2252 static void
   2253 make_perms(uint32 mode, char perms[11])
   2254 {
   2255 	strcpy(perms, "----------");
   2256 	if(mode & FM_IRUSR)
   2257 		perms[1] = 'r';
   2258 	if(mode & FM_IWUSR)
   2259 		perms[2] = 'w';
   2260 	if(mode & FM_IXUSR)
   2261 		perms[3] = 'x';
   2262 	if(mode & FM_IRGRP)
   2263 		perms[4] = 'r';
   2264 	if(mode & FM_IWGRP)
   2265 		perms[5] = 'w';
   2266 	if(mode & FM_IXGRP)
   2267 		perms[6] = 'x';
   2268 	if(mode & FM_IROTH)
   2269 		perms[7] = 'r';
   2270 	if(mode & FM_IWOTH)
   2271 		perms[8] = 'w';
   2272 	if(mode & FM_IXOTH)
   2273 		perms[9] = 'x';
   2274 	if(mode & FM_ISUID)
   2275 		perms[3] = 's';
   2276 	if(mode & FM_ISGID)
   2277 		perms[6] = 's';
   2278 	if(mode & FM_ISVTX)
   2279 		perms[9] = 't';
   2280 	switch(mode & FM_IFMT)
   2281 	{
   2282 		case 0:
   2283 			*perms = '0';
   2284 			break;
   2285 		case FM_IFSOCK:
   2286 			*perms = 's';
   2287 			break;
   2288 		case FM_IFLNK:
   2289 			*perms = 'l';
   2290 			break;
   2291 		case FM_IFREG:
   2292 			*perms = '-';
   2293 			break;
   2294 		case FM_IFBLK:
   2295 			*perms = 'b';
   2296 			break;
   2297 		case FM_IFDIR:
   2298 			*perms = 'd';
   2299 			break;
   2300 		case FM_IFCHR:
   2301 			*perms = 'c';
   2302 			break;
   2303 		case FM_IFIFO:
   2304 			*perms = 'p';
   2305 			break;
   2306 		default:
   2307 			*perms = '?';
   2308 	}
   2309 }
   2310 
   2311 // print an inode
   2312 static void
   2313 print_inode(filesystem *fs, uint32 nod)
   2314 {
   2315 	char *s;
   2316 	char perms[11];
   2317 	if(!get_nod(fs, nod)->i_mode)
   2318 		return;
   2319 	switch(nod)
   2320 	{
   2321 		case EXT2_BAD_INO:
   2322 			s = "bad blocks";
   2323 			break;
   2324 		case EXT2_ROOT_INO:
   2325 			s = "root";
   2326 			break;
   2327 		case EXT2_ACL_IDX_INO:
   2328 		case EXT2_ACL_DATA_INO:
   2329 			s = "ACL";
   2330 			break;
   2331 		case EXT2_BOOT_LOADER_INO:
   2332 			s = "boot loader";
   2333 			break;
   2334 		case EXT2_UNDEL_DIR_INO:
   2335 			s = "undelete directory";
   2336 			break;
   2337 		default:
   2338 			s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
   2339 	}
   2340 	printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
   2341 	if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
   2342 	{
   2343 		printf("unallocated\n");
   2344 		return;
   2345 	}
   2346 	make_perms(get_nod(fs, nod)->i_mode, perms);
   2347 	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));
   2348 	switch(get_nod(fs, nod)->i_mode & FM_IFMT)
   2349 	{
   2350 		case FM_IFSOCK:
   2351 			list_blocks(fs, nod);
   2352 			break;
   2353 		case FM_IFLNK:
   2354 			print_link(fs, nod);
   2355 			break;
   2356 		case FM_IFREG:
   2357 			list_blocks(fs, nod);
   2358 			break;
   2359 		case FM_IFBLK:
   2360 			print_dev(fs, nod);
   2361 			break;
   2362 		case FM_IFDIR:
   2363 			list_blocks(fs, nod);
   2364 			print_dir(fs, nod);
   2365 			break;
   2366 		case FM_IFCHR:
   2367 			print_dev(fs, nod);
   2368 			break;
   2369 		case FM_IFIFO:
   2370 			list_blocks(fs, nod);
   2371 			break;
   2372 		default:
   2373 			list_blocks(fs, nod);
   2374 	}
   2375 	printf("Done with inode %d\n",nod);
   2376 }
   2377 
   2378 // describes various fields in a filesystem
   2379 static void
   2380 print_fs(filesystem *fs)
   2381 {
   2382 	uint32 i;
   2383 	uint8 *ibm;
   2384 
   2385 	printf("%d blocks (%d free, %d reserved), first data block: %d\n",
   2386 	       fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
   2387 	       fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
   2388 	printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
   2389 	       fs->sb.s_free_inodes_count);
   2390 	printf("block size = %d, frag size = %d\n",
   2391 	       fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
   2392 	       fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
   2393 	printf("number of groups: %d\n",GRP_NBGROUPS(fs));
   2394 	printf("%d blocks per group,%d frags per group,%d inodes per group\n",
   2395 	     fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
   2396 	     fs->sb.s_inodes_per_group);
   2397 	printf("Size of inode table: %d blocks\n",
   2398 		(int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
   2399 	for (i = 0; i < GRP_NBGROUPS(fs); i++) {
   2400 		printf("Group No: %d\n", i+1);
   2401 		printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
   2402 		     fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
   2403 		     fs->gd[i].bg_inode_table);
   2404 		printf("block bitmap allocation:\n");
   2405 		print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
   2406 		printf("inode bitmap allocation:\n");
   2407 		ibm = GRP_GET_GROUP_IBM(fs, i);
   2408 		print_bm(ibm, fs->sb.s_inodes_per_group);
   2409 		for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
   2410 			if (allocated(ibm, i))
   2411 				print_inode(fs, i);
   2412 	}
   2413 }
   2414 
   2415 static void
   2416 dump_fs(filesystem *fs, FILE * fh, int swapit)
   2417 {
   2418 	uint32 nbblocks = fs->sb.s_blocks_count;
   2419 	fs->sb.s_reserved[200] = 0;
   2420 	if(swapit)
   2421 		swap_goodfs(fs);
   2422 	if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
   2423 		perror_msg_and_die("output filesystem image");
   2424 	if(swapit)
   2425 		swap_badfs(fs);
   2426 }
   2427 
   2428 static void
   2429 populate_fs(filesystem *fs, char **dopt, int didx, int squash_uids, int squash_perms, int fixstats, uint32 fs_timestamp, struct stats *stats)
   2430 {
   2431 	int i;
   2432 	for(i = 0; i < didx; i++)
   2433 	{
   2434 		struct stat st;
   2435 		FILE *fh;
   2436 		int pdir;
   2437 		char *pdest;
   2438 		uint32 nod = EXT2_ROOT_INO;
   2439 		if(fs)
   2440 			if((pdest = strchr(dopt[i], ':')))
   2441 			{
   2442 				*(pdest++) = 0;
   2443 				if(!(nod = find_path(fs, EXT2_ROOT_INO, pdest)))
   2444 					error_msg_and_die("path %s not found in filesystem", pdest);
   2445 			}
   2446 		stat(dopt[i], &st);
   2447 		switch(st.st_mode & S_IFMT)
   2448 		{
   2449 			case S_IFREG:
   2450 				fh = xfopen(dopt[i], "rb");
   2451 				add2fs_from_file(fs, nod, fh, fs_timestamp, stats);
   2452 				fclose(fh);
   2453 				break;
   2454 			case S_IFDIR:
   2455 				if((pdir = open(".", O_RDONLY)) < 0)
   2456 					perror_msg_and_die(".");
   2457 				if(chdir(dopt[i]) < 0)
   2458 					perror_msg_and_die(dopt[i]);
   2459 				if (fixstats)
   2460 					prep_stat(dopt[i]);
   2461 				add2fs_from_dir(fs, dopt[i], nod, squash_uids, squash_perms, fixstats, fs_timestamp, stats);
   2462 				if(fchdir(pdir) < 0)
   2463 					perror_msg_and_die("fchdir");
   2464 				if(close(pdir) < 0)
   2465 					perror_msg_and_die("close");
   2466 				break;
   2467 			default:
   2468 				error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
   2469 		}
   2470 	}
   2471 }
   2472 
   2473 static void
   2474 showversion(void)
   2475 {
   2476 	printf("genext2fs " VERSION "\n");
   2477 }
   2478 
   2479 static void
   2480 showhelp(void)
   2481 {
   2482 	fprintf(stderr, "Usage: %s [options] image\n"
   2483 	"Create an ext2 filesystem image from directories/files\n\n"
   2484 	"  -x, --starting-image <image>\n"
   2485 	"  -d, --root <directory>\n"
   2486 	"  -D, --devtable <file>\n"
   2487 	"  -b, --size-in-blocks <blocks>\n"
   2488 	"  -i, --bytes-per-inode <bytes per inode>\n"
   2489 	"  -N, --number-of-inodes <number of inodes>\n"
   2490 	"  -m, --reserved-percentage <percentage of blocks to reserve>\n"
   2491 	"  -g, --block-map <path>     Generate a block map file for this path.\n"
   2492 	"  -e, --fill-value <value>   Fill unallocated blocks with value.\n"
   2493 	"  -z, --allow-holes          Allow files with holes.\n"
   2494 	"  -f, --faketime             Set filesystem timestamps to 0 (for testing).\n"
   2495 	"  -q, --squash               Same as \"-U -P\".\n"
   2496 	"  -U, --squash-uids          Squash owners making all files be owned by root.\n"
   2497 	"  -P, --squash-perms         Squash permissions on all files.\n"
   2498 	"  -a, --fix-android-stats    Fix-up file stats (user, perms, ...)\n"
   2499 	"  -h, --help\n"
   2500 	"  -V, --version\n"
   2501 	"  -v, --verbose\n\n"
   2502 	"Report bugs to genext2fs-devel (at) lists.sourceforge.net\n", app_name);
   2503 }
   2504 
   2505 #define MAX_DOPT 128
   2506 #define MAX_GOPT 128
   2507 
   2508 #define MAX_FILENAME 255
   2509 
   2510 extern char* optarg;
   2511 extern int optind, opterr, optopt;
   2512 
   2513 int
   2514 main(int argc, char **argv)
   2515 {
   2516 	int nbblocks = -1;
   2517 	int nbinodes = -1;
   2518 	int nbresrvd = -1;
   2519 	float bytes_per_inode = -1;
   2520 	float reserved_frac = -1;
   2521 	int fs_timestamp = -1;
   2522 	char * fsout = "-";
   2523 	char * fsin = 0;
   2524 	char * dopt[MAX_DOPT];
   2525 	int didx = 0;
   2526 	char * gopt[MAX_GOPT];
   2527 	int gidx = 0;
   2528 	int verbose = 0;
   2529 	int holes = 0;
   2530 	int emptyval = 0;
   2531 	int squash_uids = 0;
   2532 	int squash_perms = 0;
   2533 	int fix_android_stats = 0;
   2534 	uint16 endian = 1;
   2535 	int bigendian = !*(char*)&endian;
   2536 	filesystem *fs;
   2537 	int i;
   2538 	int c;
   2539 	struct stats stats;
   2540 
   2541 #if HAVE_GETOPT_LONG
   2542 	struct option longopts[] = {
   2543 	  { "starting-image",	required_argument,	NULL, 'x' },
   2544 	  { "root",		required_argument,	NULL, 'd' },
   2545 	  { "devtable",		required_argument,	NULL, 'D' },
   2546 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
   2547 	  { "bytes-per-inode",	required_argument,	NULL, 'i' },
   2548 	  { "number-of-inodes",	required_argument,	NULL, 'N' },
   2549 	  { "reserved-percentage", required_argument,	NULL, 'm' },
   2550 	  { "block-map",	required_argument,	NULL, 'g' },
   2551 	  { "fill-value",	required_argument,	NULL, 'e' },
   2552 	  { "allow-holes",	no_argument, 		NULL, 'z' },
   2553 	  { "faketime",		no_argument,		NULL, 'f' },
   2554 	  { "squash",		no_argument,		NULL, 'q' },
   2555 	  { "squash-uids",	no_argument,		NULL, 'U' },
   2556 	  { "squash-perms",	no_argument,		NULL, 'P' },
   2557 	  { "fix-android-stats",no_argument,		NULL, 'a' },
   2558 	  { "help",		no_argument,		NULL, 'h' },
   2559 	  { "version",		no_argument,		NULL, 'V' },
   2560 	  { "verbose",		no_argument,		NULL, 'v' },
   2561 	  { 0, 0, 0, 0}
   2562 	} ;
   2563 
   2564 	app_name = argv[0];
   2565 
   2566 	while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPahVv", longopts, NULL)) != EOF) {
   2567 #else
   2568 	app_name = argv[0];
   2569 
   2570 	while((c = getopt(argc, argv,      "x:d:D:b:i:N:m:g:e:zfqUPahVv")) != EOF) {
   2571 #endif /* HAVE_GETOPT_LONG */
   2572 		switch(c)
   2573 		{
   2574 			case 'x':
   2575 				fsin = optarg;
   2576 				break;
   2577 			case 'd':
   2578 			case 'D':
   2579 				dopt[didx++] = optarg;
   2580 				break;
   2581 			case 'b':
   2582 				nbblocks = SI_atof(optarg);
   2583 				break;
   2584 			case 'i':
   2585 				bytes_per_inode = SI_atof(optarg);
   2586 				break;
   2587 			case 'N':
   2588 				nbinodes = SI_atof(optarg);
   2589 				break;
   2590 			case 'm':
   2591 				reserved_frac = SI_atof(optarg) / 100;
   2592 				break;
   2593 			case 'g':
   2594 				gopt[gidx++] = optarg;
   2595 				break;
   2596 			case 'e':
   2597 				emptyval = atoi(optarg);
   2598 				break;
   2599 			case 'z':
   2600 				holes = 1;
   2601 				break;
   2602 			case 'f':
   2603 				fs_timestamp = 0;
   2604 				break;
   2605 			case 'q':
   2606 				squash_uids = 1;
   2607 				squash_perms = 1;
   2608 				break;
   2609 			case 'U':
   2610 				squash_uids = 1;
   2611 				break;
   2612 			case 'P':
   2613 				squash_perms = 1;
   2614 				break;
   2615 			case 'a':
   2616 				fix_android_stats = 1;
   2617 				break;
   2618 			case 'h':
   2619 				showhelp();
   2620 				exit(0);
   2621 			case 'V':
   2622 				showversion();
   2623 				exit(0);
   2624 			case 'v':
   2625 				verbose = 1;
   2626 				showversion();
   2627 				break;
   2628 			default:
   2629 				error_msg_and_die("Note: options have changed, see --help or the man page.");
   2630 		}
   2631 	}
   2632 
   2633 	if(optind < (argc - 1))
   2634 		error_msg_and_die("Too many arguments. Try --help or else see the man page.");
   2635 	if(optind > (argc - 1))
   2636 		error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
   2637 
   2638 	if(fix_android_stats && (squash_uids || squash_perms))
   2639 		error_msg_and_die("Cannot squash uid/perms and fix them up for Android at the same time.");
   2640 
   2641 	fsout = argv[optind];
   2642 
   2643 	hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
   2644 	if (!hdlinks.hdl)
   2645 		error_msg_and_die("Not enough memory");
   2646 	hdlinks.count = 0 ;
   2647 
   2648 	if(fsin)
   2649 	{
   2650 		if(strcmp(fsin, "-"))
   2651 		{
   2652 			FILE * fh = xfopen(fsin, "rb");
   2653 			fs = load_fs(fh, bigendian);
   2654 			fclose(fh);
   2655 		}
   2656 		else
   2657 			fs = load_fs(stdin, bigendian);
   2658 	}
   2659 	else
   2660 	{
   2661 		if(reserved_frac == -1)
   2662 			nbresrvd = nbblocks * RESERVED_BLOCKS;
   2663 		else
   2664 			nbresrvd = nbblocks * reserved_frac;
   2665 
   2666 		stats.ninodes = EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0);
   2667 		stats.nblocks = 0;
   2668 
   2669 		populate_fs(NULL, dopt, didx, squash_uids, squash_perms, 0, fs_timestamp, &stats);
   2670 
   2671 		if(nbinodes == -1)
   2672 			nbinodes = stats.ninodes;
   2673 		else
   2674 			if(stats.ninodes > (unsigned long)nbinodes)
   2675 			{
   2676 				fprintf(stderr, "number of inodes too low, increasing to %ld\n", stats.ninodes);
   2677 				nbinodes = stats.ninodes;
   2678 			}
   2679 
   2680 		if(bytes_per_inode != -1) {
   2681 			int tmp_nbinodes = nbblocks * BLOCKSIZE / bytes_per_inode;
   2682 			if(tmp_nbinodes > nbinodes)
   2683 				nbinodes = tmp_nbinodes;
   2684 		}
   2685 		if(fs_timestamp == -1)
   2686 			fs_timestamp = time(NULL);
   2687 		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
   2688 	}
   2689 
   2690 	populate_fs(fs, dopt, didx, squash_uids, squash_perms, fix_android_stats, fs_timestamp, NULL);
   2691 
   2692 	if(emptyval) {
   2693 		uint32 b;
   2694 		for(b = 1; b < fs->sb.s_blocks_count; b++)
   2695 			if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
   2696 				memset(get_blk(fs, b), emptyval, BLOCKSIZE);
   2697 	}
   2698 	if(verbose)
   2699 		print_fs(fs);
   2700 	for(i = 0; i < gidx; i++)
   2701 	{
   2702 		uint32 nod;
   2703 		char fname[MAX_FILENAME];
   2704 		char *p;
   2705 		FILE *fh;
   2706 		if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
   2707 			error_msg_and_die("path %s not found in filesystem", gopt[i]);
   2708 		while((p = strchr(gopt[i], '/')))
   2709 			*p = '_';
   2710 		SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
   2711 		fh = xfopen(fname, "wb");
   2712 		fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
   2713 		flist_blocks(fs, nod, fh);
   2714 		fclose(fh);
   2715 	}
   2716 	if(strcmp(fsout, "-"))
   2717 	{
   2718 		FILE * fh = xfopen(fsout, "wb");
   2719 		dump_fs(fs, fh, bigendian);
   2720 		fclose(fh);
   2721 	}
   2722 	else
   2723 		dump_fs(fs, stdout, bigendian);
   2724 	free_fs(fs);
   2725 	return 0;
   2726 }
   2727