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