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