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