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