📄 genext2fs.c
字号:
// genext2fs.c//// ext2 filesystem generator for embedded systems// Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License// as published by the Free Software Foundation; version// 2 of the License.//// Changes:// 3 Jun 2000 Initial release// 6 Jun 2000 Bugfix: fs size multiple of 8// Bugfix: fill blocks with inodes// 14 Jun 2000 Bugfix: bad chdir() with -d option// Bugfix: removed size=8n constraint// Changed -d file to -f file// Added -e option// 22 Jun 2000 Changed types for 64bits archs// 24 Jun 2000 Added endianness swap// Bugfix: bad dir name lookup// 03 Aug 2000 Bugfix: ind. blocks endian swap// 09 Aug 2000 Bugfix: symlinks endian swap// 01 Sep 2000 Bugfix: getopt returns int, not char proski@gnu.org// 10 Sep 2000 Bugfix: device nodes endianness xavier.gueguen@col.bsf.alcatel.fr// Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr// Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr// 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com// `genext2fs' is a mean to generate an ext2 filesystem// as a normal (non-root) user. It doesn't require you to mount// the image file to copy files on it. It doesn't even require// you to be the superuser to make device nodes.//// Warning ! `genext2fs' has been designed for embedded// systems. As such, it will generate a filesystem for single-user// usage: all files/directories/etc... will belong to UID/GID 0//// Example usage://// # genext2fs -b 1440 -d srcdir /dev/fd0//// All files in the srcdir directory will be written to /dev/fd0 as// a new ext2 filesystem image. You can then mount the floppy as// usual.//// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img//// This one would build a filesystem from all the files in builddir,// then would read a devices list and make apropriate nodes. The// format for the device list is://// drwx /dev// crw- 10,190 /dev/lcd// brw- 1,0 /dev/ram0// // This device list builds the /dev directory, a character device// node /dev/lcd (major 10, minor 190) and a block device node// /dev/ram0 (major 1, minor 0)#include <stdio.h>#include <stdlib.h>#include <string.h>#include <dirent.h>#include <stdarg.h>#include <unistd.h>#include <sys/stat.h>// block size#define BLOCKSIZE 1024#define BLOCKS_PER_GROUP 8192#define BYTES_PER_INODE (8*BLOCKSIZE)#define RESERVED_INODES 5/100// inode block size (why is it != BLOCKSIZE ?!?)#define INODE_BLOCKSIZE 512#define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE)// reserved inodes#define EXT2_BAD_INO 1 // Bad blocks inode#define EXT2_ROOT_INO 2 // Root inode#define EXT2_ACL_IDX_INO 3 // ACL inode#define EXT2_ACL_DATA_INO 4 // ACL inode#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode#define EXT2_FIRST_INO 11 // First non reserved inode// magic number for ext2#define EXT2_MAGIC_NUMBER 0xEF53// direct/indirect block addresses#define EXT2_NDIR_BLOCKS 11 // direct blocks#define EXT2_IND_BLOCK 12 // indirect block#define EXT2_DIND_BLOCK 13 // double indirect block#define EXT2_TIND_BLOCK 14 // triple indirect block#define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address)// end of a block walk#define WALK_END 0xFFFFFFFE// file modes#define FM_IFMT 0xF000 // format mask#define FM_IFLNK 0xA000 // socket#define FM_IFSOCK 0xC000 // symbolic link#define FM_IFREG 0x8000 // regular file#define FM_IFBLK 0x6000 // block device#define FM_IFDIR 0x4000 // directory#define FM_IFCHR 0x2000 // character device#define FM_IFIFO 0x1000 // fifo#define FM_ISUID 0x0800 // SUID#define FM_ISGID 0x0400 // SGID#define FM_ISVTX 0x0200 // sticky bit#define FM_IRWXU 0x01C0 // user mask#define FM_IRUSR 0x0100 // read#define FM_IWUSR 0x0080 // write#define FM_IXUSR 0x0040 // execute#define FM_IRWXG 0x0038 // group mask#define FM_IRGRP 0x0020 // read#define FM_IWGRP 0x0010 // write#define FM_IXGRP 0x0008 // execute#define FM_IRWXO 0x0007 // other mask#define FM_IROTH 0x0004 // read#define FM_IWOTH 0x0002 // write#define FM_IXOTH 0x0001 // execute// options#define OP_HOLES 0x01 // make files with holes// used typestypedef signed char int8;typedef unsigned char uint8;typedef signed short int16;typedef unsigned short uint16;typedef signed int int32;typedef unsigned int uint32;// the GNU C library has a wonderful scanf("%as", string) which will// allocate the string with the right size, good to avoid buffer// overruns. the following macros use it if available or use a// hacky workaround// moreover it will define a snprintf() like a sprintf(), i.e.// without the buffer overrun checking,// and the correct getcwd() size argument for automatic allocation,// which of course is not the same on Solaris, old glibc and new// glibc ...#ifdef __GNUC__#define SCANF_PREFIX "a"#define SCANF_STRING(s) (&s)#define GETCWD_SIZE 0#else#define SCANF_PREFIX "511"#define SCANF_STRING(s) (s = malloc(512))#define GETCWD_SIZE -1inline int snprintf(char *str, size_t n, const char *fmt, ...){ int ret; va_list ap; va_start(ap, fmt); ret = vsprintf(str, fmt, ap); va_end(ap); return ret;}#endif// endianness swapinline uint16 swab16(uint16 val){ return (val >> 8) | (val << 8);}inline uint32 swab32(uint32 val){ return ((val>>24) | ((val>>8)&0xFF00) | ((val<<8)&0xFF0000) | (val<<24));}// on-disk structures// this trick makes me declare things only once// (once for the structures, once for the endianness swap)#define superblock_decl \ udecl32(s_inodes_count) /* Count of inodes in the filesystem */ \ udecl32(s_blocks_count) /* Count of blocks in the filesystem */ \ udecl32(s_r_blocks_count) /* Count of the number of reserved blocks */ \ udecl32(s_free_blocks_count) /* Count of the number of free blocks */ \ udecl32(s_free_inodes_count) /* Count of the number of free inodes */ \ udecl32(s_first_data_block) /* The first block which contains data */ \ udecl32(s_log_block_size) /* Indicator of the block size */ \ decl32(s_log_frag_size) /* Indicator of the size of the fragments */ \ udecl32(s_blocks_per_group) /* Count of the number of blocks in each block group */ \ udecl32(s_frags_per_group) /* Count of the number of fragments in each block group */ \ udecl32(s_inodes_per_group) /* Count of the number of inodes in each block group */ \ udecl32(s_mtime) /* The time that the filesystem was last mounted */ \ udecl32(s_wtime) /* The time that the filesystem was last written to */ \ udecl16(s_mnt_count) /* The number of times the file system has been mounted */ \ decl16(s_max_mnt_count) /* The number of times the file system can be mounted */ \ udecl16(s_magic) /* Magic number indicating ex2fs */ \ udecl16(s_state) /* Flags indicating the current state of the filesystem */ \ udecl16(s_errors) /* Flags indicating the procedures for error reporting */ \ udecl16(s_minor_rev_level) /* The minor revision level of the filesystem */ \ udecl32(s_lastcheck) /* The time that the filesystem was last checked */ \ udecl32(s_checkinterval) /* The maximum time permissable between checks */ \ udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \ udecl32(s_rev_level) /* The revision level of the filesystem */ \ udecl16(s_def_resuid) /* The default uid for reserved blocks */ \ udecl16(s_def_resgid) /* The default gid for reserved blocks */#define groupdescriptor_decl \ udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \ udecl32(bg_inode_bitmap) /* Block number of the inode bitmap */ \ udecl32(bg_inode_table) /* Block number of the inode table */ \ udecl16(bg_free_blocks_count) /* Free blocks in the group */ \ udecl16(bg_free_inodes_count) /* Free inodes in the group */ \ udecl16(bg_used_dirs_count) /* Number of directories in the group */ \ udecl16(bg_pad)#define inode_decl \ udecl16(i_mode) /* Entry type and file mode */ \ udecl16(i_uid) /* User id */ \ udecl32(i_size) /* File/dir size in bytes */ \ udecl32(i_atime) /* Last access time */ \ udecl32(i_ctime) /* Creation time */ \ udecl32(i_mtime) /* Last modification time */ \ udecl32(i_dtime) /* Deletion time */ \ udecl16(i_gid) /* Group id */ \ udecl16(i_links_count) /* Number of (hard) links to this inode */ \ udecl32(i_blocks) /* Number of blocks used (1 block = 512 bytes) */ \ udecl32(i_flags) /* ??? */ \ udecl32(i_reserved1) \ utdecl32(i_block,15) /* Blocks table */ \ udecl32(i_version) /* ??? */ \ udecl32(i_file_acl) /* File access control list */ \ udecl32(i_dir_acl) /* Directory access control list */ \ udecl32(i_faddr) /* Fragment address */ \ udecl8(i_frag) /* Fragments count*/ \ udecl8(i_fsize) /* Fragment size */ \ udecl16(i_pad1)#define directory_decl \ udecl32(d_inode) /* Inode entry */ \ udecl16(d_rec_len) /* Total size on record */ \ udecl16(d_name_len) /* Size of entry name */#define decl8(x) int8 x;#define udecl8(x) uint8 x;#define decl16(x) int16 x;#define udecl16(x) uint16 x;#define decl32(x) int32 x;#define udecl32(x) uint32 x;#define utdecl32(x,n) uint32 x[n];typedef struct{ superblock_decl uint32 s_reserved[235]; // Reserved} superblock;typedef struct{ groupdescriptor_decl uint32 bg_reserved[3]; uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];} groupdescriptor;typedef struct{ inode_decl uint32 i_reserved2[2];} inode;typedef struct{ directory_decl char d_name[0];} directory;typedef uint8 block[BLOCKSIZE];typedef struct{ uint32 bnum; uint32 bpdir; uint32 bpind; uint32 bpdind; uint32 bptind;} blockwalker;#if BLOCKSIZE == 1024typedef struct{ block zero; // The famous block 0 superblock sb; // The superblock groupdescriptor gd; // The group desciptor block bbm; // The block bitmap block ibm; // The inode bitmap inode itab[0]; // The inode table} filesystem;#else#error UNHANDLED BLOCKSIZE#endif// now the endianness swap#undef decl8#undef udecl8#undef decl16#undef udecl16#undef decl32#undef udecl32#undef utdecl32#define decl8(x)#define udecl8(x)#define decl16(x) this->x = swab16(this->x);#define udecl16(x) this->x = swab16(this->x);#define decl32(x) this->x = swab32(this->x);#define udecl32(x) this->x = swab32(this->x);#define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }void swap_sb(superblock *sb){#define this sb superblock_decl#undef this}void swap_gd(groupdescriptor *gd){#define this gd groupdescriptor_decl#undef this}void swap_nod(inode *nod){#define this nod inode_decl#undef this}void swap_dir(directory *dir){#define this dir directory_decl#undef this}void swap_block(block b){ int i; uint32 *blk = (uint32*)b; for(i = 0; i < BLOCKSIZE/4; i++) blk[i] = swab32(blk[i]);}#undef decl8#undef udecl8#undef decl16#undef udecl16#undef decl32#undef udecl32#undef utdecl32char * argv0;// error (un)handlinginline void errexit(const char *fmt, ...){ va_list ap; fprintf(stderr, "%s: ", argv0); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(1);}inline void pexit(const char * fname){ fprintf(stderr, "%s: ", argv0); perror(fname); exit(1);}// printf helper macro#define plural(a) (a), ((a) > 1) ? "s" : ""// temporary working blockinline uint8 * get_workblk(void){ static block b; return b;}inline void free_workblk(block b){}// rounds a quantity up to a blocksizeuint32 rndup(uint32 qty, uint32 siz){ return (qty + (siz - 1)) & ~(siz - 1);}// check if something is allocated in the bitmapinline uint32 allocated(block b, uint32 item){ return b[(item-1) / 8] & (1 << ((item-1) % 8));}// return a given block from a filesysteminline uint8 * get_blk(filesystem *fs, uint32 blk){ return (uint8*)fs + blk*BLOCKSIZE;}// return a given inode from a filesysteminline inode * get_nod(filesystem *fs, uint32 nod){ return &fs->itab[nod-1];}// allocate a given block/inode in the bitmap// allocate first free if item == 0uint32 allocate(block b, uint32 item){ if(!item) { int i; uint8 bits; for(i = 0; i < BLOCKSIZE; i++) if((bits = b[i]) != (uint8)-1) { int j; for(j = 0; j < 8; j++) if(!(bits & (1 << j))) break; item = i * 8 + j + 1; break; } if(i == BLOCKSIZE) return 0; } b[(item-1) / 8] |= (1 << ((item-1) % 8)); return item;}// deallocate a given block/inodevoid deallocate(block b, uint32 item){ b[(item-1) / 8] &= ~(1 << ((item-1) % 8));}// allocate a blockuint32 alloc_blk(filesystem *fs){ uint32 bk; if(!(bk = allocate(fs->bbm, 0))) errexit("couldn't allocate a block (no free space)"); if(!(fs->gd.bg_free_blocks_count--)) errexit("group descr. free blocks count == 0 (corrupted fs?)"); if(!(fs->sb.s_free_blocks_count--)) errexit("superblock free blocks count == 0 (corrupted fs?)"); return bk;}// allocate an inodeuint32 alloc_nod(filesystem *fs){ uint32 nod; if(!(nod = allocate(fs->ibm, 0))) errexit("couldn't allocate an inode (no free inode)"); if(!(fs->gd.bg_free_inodes_count--)) errexit("group descr. free blocks count == 0 (corrupted fs?)"); if(!(fs->sb.s_free_inodes_count--)) errexit("superblock free blocks count == 0 (corrupted fs?)"); return nod;}// print a bitmap allocationvoid print_bm(block b, uint32 max){ uint32 i; printf("----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0\n"); for(i=1; i <= max; i++) { putchar(allocated(b, i) ? '*' : '.'); if(!(i % 100)) printf("\n"); } if((i-1) % 100) printf("\n");}// initalize a blockwalker (iterator for blocks list)void init_bw(filesystem *fs, uint32 nod, blockwalker *bw){ bw->bnum = 0; bw->bpdir = EXT2_INIT_BLOCK;}// return next block of inode (WALK_END for end)// if create>0, append a newly allocated block at the end// if hole!=0, create a hole in the fileuint32 walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, uint32 *create, uint32 hole){ uint32 *bkref = 0; uint32 *b; int extend = 0; if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK) { if(create && (*create)--) extend = 1; else return WALK_END; } // first direct block if(bw->bpdir == EXT2_INIT_BLOCK) { bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0]; if(extend) // allocate first block *bkref = hole ? 0 : alloc_blk(fs); } // direct block else if(bw->bpdir < EXT2_NDIR_BLOCKS) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -