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@free.fr>
6//
7// Please direct support requests to genext2fs-devel@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@codepoet.org>
12//	Copyright (C) 2002  Edward Betts <edward@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@gnu.org
33// 	10 Sep 2000	Bugfix: device nodes endianness		xavier.gueguen@col.bsf.alcatel.fr
34// 			Bugfix: getcwd values for Solaris	xavier.gueguen@col.bsf.alcatel.fr
35// 			Bugfix: ANSI scanf for non-GNU C	xavier.gueguen@col.bsf.alcatel.fr
36// 	28 Jun 2001	Bugfix: getcwd differs for Solaris/GNU	mike@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@ixiacom.com
40// 			endianess swap assert check.
41// 			Copyright (C) 2002 Ixia communications
42// 	12 Oct 2002	Added support for triple indirection	vsundar@ixiacom.com
43// 			Copyright (C) 2002 Ixia communications
44// 	14 Oct 2002	Added support for groups		vsundar@ixiacom.com
45// 			Copyright (C) 2002 Ixia communications
46// 	 5 Jan 2003	Bugfixes: reserved inodes should be set vsundar@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@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>
148unsigned source_path_len = 0;
149
150struct 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
275typedef signed char int8;
276typedef unsigned char uint8;
277typedef signed short int16;
278typedef unsigned short uint16;
279typedef signed int int32;
280typedef 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
303static inline int
304portable_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
324ssize_t
325getdelim(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
393float
394SI_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
425static inline uint16
426swab16(uint16 val)
427{
428	return (val >> 8) | (val << 8);
429}
430
431static inline uint32
432swab32(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
514typedef struct
515{
516	superblock_decl
517	uint32 s_reserved[235];       // Reserved
518} superblock;
519
520typedef struct
521{
522	groupdescriptor_decl
523	uint32 bg_reserved[3];
524} groupdescriptor;
525
526typedef struct
527{
528	inode_decl
529	uint32 i_reserved2[2];
530} inode;
531
532typedef struct
533{
534	directory_decl
535	char d_name[0];
536} directory;
537
538typedef 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
566typedef 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
578typedef 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
607static int32 hdlink_cnt = HDLINK_CNT;
608struct hdlink_s
609{
610	uint32	src_inode;
611	uint32	dst_nod;
612};
613
614struct hdlinks_s
615{
616	int32 count;
617	struct hdlink_s *hdl;
618};
619
620static struct hdlinks_s hdlinks;
621
622static void
623swap_sb(superblock *sb)
624{
625#define this sb
626	superblock_decl
627#undef this
628}
629
630static void
631swap_gd(groupdescriptor *gd)
632{
633#define this gd
634	groupdescriptor_decl
635#undef this
636}
637
638static void
639swap_nod(inode *nod)
640{
641#define this nod
642	inode_decl
643#undef this
644}
645
646static void
647swap_dir(directory *dir)
648{
649#define this dir
650	directory_decl
651#undef this
652}
653
654static void
655swap_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
671static char * app_name;
672static const char *const memory_exhausted = "memory exhausted";
673
674// error (un)handling
675static void
676verror_msg(const char *s, va_list p)
677{
678	fflush(stdout);
679	fprintf(stderr, "%s: ", app_name);
680	vfprintf(stderr, s, p);
681}
682static void
683error_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
692static void
693error_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
703static void
704vperror_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
715static void
716perror_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
725static FILE *
726xfopen(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
734static char *
735xstrdup(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
747static void *
748xrealloc(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
756static char *
757xreadlink(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
777int
778is_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
793static inline uint8 *
794get_workblk(void)
795{
796	unsigned char* b=calloc(1,BLOCKSIZE);
797	return b;
798}
799static inline void
800free_workblk(block b)
801{
802	free(b);
803}
804
805/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
806static inline uint32
807rndup(uint32 qty, uint32 siz)
808{
809	return (qty + (siz - 1)) & ~(siz - 1);
810}
811
812// check if something is allocated in the bitmap
813static inline uint32
814allocated(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
820static inline uint8 *
821get_blk(filesystem *fs, uint32 blk)
822{
823	return (uint8*)fs + blk*BLOCKSIZE;
824}
825
826// return a given inode from a filesystem
827static inline inode *
828get_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
841static uint32
842allocate(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
866static void
867deallocate(block b, uint32 item)
868{
869	b[(item-1) / 8] &= ~(1 << ((item-1) % 8));
870}
871
872// allocate a block
873static uint32
874alloc_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
896static void
897free_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
909static uint32
910alloc_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
941static void
942print_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)
957static inline void
958init_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
972static uint32
973walk_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...)
1204static void
1205extend_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
1247static void
1248add2dir(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
1319static uint32
1320find_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
1339static uint32
1340find_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
1365void
1366chmod_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
1376static uint32
1377mknod_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 "." & "..")
1412static inline uint32
1413mkdir_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
1420static uint32
1421mklink_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*
1436static uint32
1437mkfile_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
1455static uint32
1456get_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
1506static void
1507add2fs_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
1630static void
1631prep_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
1645static void
1646fix_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
1653static void
1654add2fs_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
1796static void
1797swap_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
1853static void
1854swap_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
1899static void
1900swap_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
1928static void
1929swap_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
1958static filesystem *
1959init_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
2129static filesystem *
2130load_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
2151static void
2152free_fs(filesystem *fs)
2153{
2154	free(fs);
2155}
2156
2157// just walk through blocks list
2158static void
2159flist_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
2170static void
2171list_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*
2184static void
2185write_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
2203static void
2204print_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
2213static void
2214print_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
2238static void
2239print_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
2252static void
2253make_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
2312static void
2313print_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
2379static void
2380print_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
2415static void
2416dump_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
2428static void
2429populate_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
2473static void
2474showversion(void)
2475{
2476	printf("genext2fs " VERSION "\n");
2477}
2478
2479static void
2480showhelp(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@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
2510extern char* optarg;
2511extern int optind, opterr, optopt;
2512
2513int
2514main(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