ext2硬盘layout如下:
下面做了ext2的一些验证,主要为了验证对ext2的 Disk Organization的理解, 诸如Block Group Descriptor, Inode Table之类.
给定一个ext2镜像, 遍历其所有文件, 并显示文件内容.
假定该镜像的文件大小都比较小, 不需要indirect pointer.
ext2_parse.c:
#include <assert.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <time.h> #include <sys/types.h> #define dbg_print(fmt,args...) printf("%s(),%d:"fmt, __func__, __LINE__, ##args) #define info_print(fmt,args...) printf("%s(),%d:"fmt, __func__, __LINE__, ##args) typedef unsigned int __le32; typedef unsigned int __u32; typedef unsigned short __le16; typedef unsigned short __u16; typedef unsigned char __u8; /* 主要为了验证对ext2的 Disk Organization的理解, 诸如Block Group Descriptor, Inode Table之类. 1. 不考虑大小端问题 2. 处理file hole的情况 3. 处理block size不为1024的情况 简化, 忽略indirect pointer的情况 */ enum { EXT2_FT_UNKNOWN = 0, EXT2_FT_REG_FILE = 1, EXT2_FT_DIR = 2, EXT2_FT_CHRDEV = 3, EXT2_FT_BLKDEV = 4, EXT2_FT_FIFO = 5, EXT2_FT_SOCK = 6, EXT2_FT_SYMLINK = 7, EXT2_FT_MAX }; struct ext2_super_block { __le32 s_inodes_count; /* Inodes count */ __le32 s_blocks_count; /* Blocks count */ __le32 s_r_blocks_count; /* Reserved blocks count */ __le32 s_free_blocks_count; /* Free blocks count */ __le32 s_free_inodes_count; /* Free inodes count */ __le32 s_first_data_block; /* First Data Block */ /*[Professional Linux Kernel Architecture] Currently, the three values 0, 1, and 2 are used 表示 block sizes of 20 × 1,024 = 1,024, 21 × 1,024 = 2,048, and 22 × 1,024 = 4,096 bytes */ __le32 s_log_block_size; /* Block size */ __le32 s_log_frag_size; /* Fragment size */ __le32 s_blocks_per_group; /* # Blocks per group */ __le32 s_frags_per_group; /* # Fragments per group */ __le32 s_inodes_per_group; /* # Inodes per group */ __le32 s_mtime; /* Mount time */ __le32 s_wtime; /* Write time */ __le16 s_mnt_count; /* Mount count */ __le16 s_max_mnt_count; /* Maximal mount count */ __le16 s_magic; /* Magic signature */ __le16 s_state; /* File system state */ __le16 s_errors; /* Behaviour when detecting errors */ __le16 s_minor_rev_level; /* minor revision level */ __le32 s_lastcheck; /* time of last check */ __le32 s_checkinterval; /* max. time between checks */ __le32 s_creator_os; /* OS */ __le32 s_rev_level; /* Revision level */ __le16 s_def_resuid; /* Default uid for reserved blocks */ __le16 s_def_resgid; /* Default gid for reserved blocks */ /* * These fields are for EXT2_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set * in the incompatible feature set that the kernel doesn't * know about, it should refuse to mount the filesystem. * * e2fsck's requirements are more strict; if it doesn't know * about a feature in either the compatible or incompatible * feature set, it must abort and not try to meddle with * things it doesn't understand... */ __le32 s_first_ino; /* First non-reserved inode */ __le16 s_inode_size; /* size of inode structure */ __le16 s_block_group_nr; /* block group # of this superblock */ __le32 s_feature_compat; /* compatible feature set */ __le32 s_feature_incompat; /* incompatible feature set */ __le32 s_feature_ro_compat; /* readonly-compatible feature set */ __u8 s_uuid[16]; /* 128-bit uuid for volume */ char s_volume_name[16]; /* volume name */ char s_last_mounted[64]; /* directory where last mounted */ __le32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only * happen if the EXT2_COMPAT_PREALLOC flag is on. */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __u16 s_padding1; /* * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. */ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ __u32 s_journal_inum; /* inode number of journal file */ __u32 s_journal_dev; /* device number of journal file */ __u32 s_last_orphan; /* start of list of inodes to delete */ __u32 s_hash_seed[4]; /* HTREE hash seed */ __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_reserved_char_pad; __u16 s_reserved_word_pad; __le32 s_default_mount_opts; __le32 s_first_meta_bg; /* First metablock block group */ __u32 s_reserved[190]; /* Padding to the end of the block */ }; struct ext2_group_desc { __le32 bg_block_bitmap; /* Blocks bitmap block */ __le32 bg_inode_bitmap; /* Inodes bitmap block */ __le32 bg_inode_table; /* Inodes table block */ __le16 bg_free_blocks_count; /* Free blocks count */ __le16 bg_free_inodes_count; /* Free inodes count */ __le16 bg_used_dirs_count; /* Directories count */ __le16 bg_pad; __le32 bg_reserved[3]; }; struct ext2_inode { __le16 i_mode; /* File mode */ __le16 i_uid; /* Low 16 bits of Owner Uid */ __le32 i_size; /* Size in bytes */ __le32 i_atime; /* Access time */ __le32 i_ctime; /* Creation time */ __le32 i_mtime; /* Modification time */ __le32 i_dtime; /* Deletion Time */ __le16 i_gid; /* Low 16 bits of Group Id */ __le16 i_links_count; /* Links count */ __le32 i_blocks; /* Blocks count 用来处理file hole, 单位为512字节 */ __le32 i_flags; /* File flags */ union { struct { __le32 l_i_reserved1; } linux1; #if 0 //awakening-fong.github.io 只管linux的 struct { __le32 h_i_translator; } hurd1; struct { __le32 m_i_reserved1; } masix1; #endif } osd1; /* OS dependent 1 */ #define EXT2_N_BLOCKS (15) __le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ __le32 i_generation; /* File version (for NFS) */ __le32 i_file_acl; /* File ACL */ __le32 i_dir_acl; /* Directory ACL */ __le32 i_faddr; /* Fragment address */ union { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ __u16 i_pad1; __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; } linux2; #if 0 //awakening-fong.github.io 只管linux的 struct { __u8 h_i_frag; /* Fragment number */ __u8 h_i_fsize; /* Fragment size */ __le16 h_i_mode_high; __le16 h_i_uid_high; __le16 h_i_gid_high; __le32 h_i_author; } hurd2; struct { __u8 m_i_frag; /* Fragment number */ __u8 m_i_fsize; /* Fragment size */ __u16 m_pad1; __u32 m_i_reserved2[2]; } masix2; #endif } osd2; /* OS dependent 2 */ }; struct ext2_dir_entry_2 { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __u8 name_len; /* Name length */ __u8 file_type; char name[]; /* File name, up to EXT2_NAME_LEN */ }; struct ext2_dir_entry { __le32 inode; /* Inode number */ __le16 rec_len; /* Directory entry length */ __le16 name_len; /* Name length */ char name[]; /* File name, up to EXT2_NAME_LEN */ }; int inodes_per_group; int block_size=0; int blocks_per_group; void list_file(char *buf,struct ext2_inode *dir_inode); static int FileIn( const char *strFile, unsigned char *inBuff) { FILE *p_in=NULL; if((p_in = fopen(strFile,"rb")) == NULL) { dbg_print("open file:%s error! ",strFile); return -1; } fseek(p_in, 0L, SEEK_END); unsigned int file_size = ftell(p_in); fseek(p_in, 0L,SEEK_SET); dbg_print("ftell size %d ", file_size); ssize_t nread=0; size_t nleft =file_size; unsigned char *bufp = inBuff; while (nleft > 0) { if ((nread = fread(bufp, nleft,1,p_in)) == -1) { if (errno == EINTR) /* interrupted by signal handler return */ nread = 0; /* and call read() again */ else return -1; /* errno set by read() */ } else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } dbg_print("file read size %u ", file_size); fclose(p_in); p_in=NULL; return file_size; } //group descriptors分布在各个block group中的内容是一样的. struct ext2_inode *get_inode_buf(char *buf, int inode) { //inode编号从1开始. int group_th=inode/inodes_per_group; char *p; // dbg_print("group_th:%d ",group_th); int first_desc_table_nr_block=((1024+1024)+(block_size-1))/block_size;//copy from main() struct ext2_group_desc *p_desc =(struct ext2_group_desc *) (buf + first_desc_table_nr_block * block_size); p_desc+=group_th; int dst_block=p_desc->bg_inode_table; // dbg_print("bg_inode_table:%d ",dst_block); //block编号从0开始 p=buf + dst_block*block_size; //inode编号从1开始. p+=(inode-1)%inodes_per_group * sizeof(struct ext2_inode); return (struct ext2_inode*)p; } void read_from_ext2_dir_entry_2(char *buf,struct ext2_dir_entry_2 *entry) { if(EXT2_FT_DIR==entry->file_type) { dbg_print("start list file for %s ",entry->name); struct ext2_inode *dir_inode=get_inode_buf(buf, entry->inode); list_file(buf,dir_inode); dbg_print("end of list_file %s ",entry->name); } else if(EXT2_FT_REG_FILE==entry->file_type) { struct ext2_inode *file_inode=get_inode_buf(buf, entry->inode); int sum_size=0; int j=0; while(1) { int i=0; int block_th=file_inode->i_block[j]; // dbg_print("block_th:%d ",block_th); /* 这个是错误的写法, 因为没有考虑file hole的情况. if(0==block_th) break; */ if(0==block_th) { //XXX 暂不考虑indirect的情况 if( (j+1)*block_size<file_inode->i_size ) { j++; continue; } else break; } //XXX 暂不考虑indirect的情况 //dbg_print("block_th:%d ",block_th); char *p=buf + block_th* block_size; //dbg_print("inode i_size:%d ",root_inode->i_size); do { printf("%c",p[i++]); sum_size++; }while(i<block_size && sum_size < file_inode->i_size ); j++; } } } void list_file(char *buf,struct ext2_inode *dir_inode) { int i=0; while(1) { int block_th=dir_inode->i_block[i]; //dbg_print("block_th:%d ",block_th); //a regular file才有file hole if(0==block_th) break; char *p=buf + block_th* block_size; struct ext2_dir_entry_2*p_dir_entry=(struct ext2_dir_entry_2*)p; int sum_size=0; //dbg_print("inode i_size:%d ",dir_inode->i_size); if(0==p_dir_entry->inode) //https://courses.cs.washington.edu/courses/cse451/09sp/projects/project3light/project3_light.html { dbg_print("p_dir_entry inode:%d ",p_dir_entry->inode); break; } /* if(0==strlen(p_dir_entry->name)) break; */ do { // if(EXT2_FT_DIR==p_dir_entry->file_type) //info_print("dir: "); //dbg_print("%s lel:%d ",p_dir_entry->name,strlen(p_dir_entry->name)); dbg_print("%s ",p_dir_entry->name); if(!(strlen(p_dir_entry->name)==1 && p_dir_entry->name[0]=='.') && !(strlen(p_dir_entry->name)==2 && 0==strcmp(p_dir_entry->name,".."))) read_from_ext2_dir_entry_2(buf,p_dir_entry); sum_size+=p_dir_entry->rec_len; p+=p_dir_entry->rec_len; //dbg_print("sum_size:%d ",sum_size);//tmp_fong p_dir_entry=(struct ext2_dir_entry_2*)p; //}while(sum_size<block_size && sum_size<dir_inode->i_size); /*为何要sum_size<block_size ???*/ }while(sum_size<block_size && sum_size<dir_inode->i_blocks*512); //XXX 先不管file hole //}while(sum_size<dir_inode->i_blocks*512); //XXX 先不管file hole i++; } } int main(int argc, char *argv[]) { int file_size=-1; unsigned char *buf=(unsigned char *)malloc(70*1024*1024); if (!buf) { dbg_print("malloc fail "); return -1; } file_size=FileIn(argv[1],buf); if(file_size<0) { dbg_print("FileIn fail "); return -1; } struct ext2_super_block super_block; memset(&super_block, 0, sizeof(super_block)); /* The Superblock is always located at byte 1024 from the beginning of the volume and is exactly 1024 bytes in length. (来自 http://wiki.osdev.org/Ext2) */ memcpy(&super_block, buf+1024, sizeof(super_block)); dbg_print("sizeof(super_block):%d ",sizeof(super_block)); dbg_print("s_magic:0x%x ",super_block.s_magic); assert(super_block.s_magic==0xef53); dbg_print("s_log_block_size:%d ",super_block.s_log_block_size); if(0==super_block.s_log_block_size) block_size=1024; else if(1==super_block.s_log_block_size) block_size=2048; else if(2==super_block.s_log_block_size) block_size=4096; else exit(-1); dbg_print("block_size:%d ",block_size); inodes_per_group=super_block.s_inodes_per_group; blocks_per_group=super_block.s_blocks_per_group; /*遍历group*/ const int nr_group=(super_block.s_blocks_count+blocks_per_group -1)/blocks_per_group; dbg_print("nr_group:%d ",nr_group); int i=0; struct ext2_super_block *p_sb; char *p; for( i=0; i<nr_group ; i++ ) { if(i==0) p = buf + 1024 + i*blocks_per_group * block_size; else p = buf + 1024*(1024>=block_size) + i*blocks_per_group * block_size; p_sb=(struct ext2_super_block *)p; // __le16 s_block_group_nr; /* block group # of this superblock */ dbg_print("s_block_group_nr:%d ",p_sb->s_block_group_nr); } /*遍历group descriptors*/ int first_desc_table_nr_block=((1024+1024)+(block_size-1))/block_size; struct ext2_group_desc *p_desc =(struct ext2_group_desc *) (buf + first_desc_table_nr_block * block_size); for( i=0; i<nr_group ; i++) { dbg_print("group %d: ",i); dbg_print("bg_block_bitmap:%d ",p_desc->bg_block_bitmap); dbg_print("bg_inode_bitmap:%d ",p_desc->bg_inode_bitmap); dbg_print("bg_inode_table:%d ",p_desc->bg_inode_table); p_desc += 1; } //递归显示 各目录下的文件名及内容 struct ext2_inode *root_inode=get_inode_buf(buf,2); //root dir dbg_print("root_inode->i_size:%d ",root_inode->i_size); list_file(buf,root_inode); //free(buf); we donot care this. return 0; }
验证脚本:
$ cat ext2_layout.sh file_img="img.70M_2048" rm $file_img a.out orig_path=$PWD dd if=/dev/zero of=$file_img bs=1M count=70 /sbin/mke2fs -b 2048 -O ^sparse_super,^has_journal,^dir_index,^resize_inode $file_img <<EOF y EOF mkdir /mnt/ext2 umount /mnt/ext2 /sbin/losetup -d /dev/loop0 /sbin/losetup /dev/loop0 $file_img /sbin/mkfs.ext2 /dev/loop0 mount -t ext2 /dev/loop0 /mnt/ext2/ cd /mnt/ext2 echo file_root_01_01234567aaaaaaaabbbbbbbbccccccccdddddddd >> root_01 echo file_root_02_01234567aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee >> root_02 echo file_root_03_01234567aaaaaaaabbbbbbbbccccccccddddddddffffffff >> root_03 mkdir d.home d.lib d.usr d.boot cd d.boot/ echo file_in_d.boot_file00_named_file00_end_of_file >> file00 echo file_in_d.boot_file01_named_file01_end_of_file >> file01 echo -n "X" | dd of=file02_file_hole bs=1024 seek=6 sync sync umount /mnt/ext2 sync echo $orig_path > /dev/stderr cd $orig_path gcc -m32 ext2_parse.c && ./a.out $file_img #dumpe2fs $file_img
验证结果:
$ sudo sh ext2_layout.sh 70+0 records in 70+0 records out 73400320 bytes (73 MB) copied, 0.8425 seconds, 87.1 MB/s mke2fs 1.39 (29-May-2006) img.70M_2048 is not a block special device. Proceed anyway? (y,n) Filesystem label= OS type: Linux Block size=2048 (log=1) Fragment size=2048 (log=1) 17952 inodes, 35840 blocks 1792 blocks (5.00%) reserved for the super user First data block=0 3 block groups 16384 blocks per group, 16384 fragments per group 5984 inodes per group Superblock backups stored on blocks: 16384, 32768 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 28 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. mkdir: cannot create directory `/mnt/ext2': File exists mke2fs 1.39 (29-May-2006) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 17928 inodes, 71680 blocks 3584 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=67371008 9 block groups 8192 blocks per group, 8192 fragments per group 1992 inodes per group Superblock backups stored on blocks: 8193, 24577, 40961, 57345 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 22 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. 0+1 records in 0+1 records out 1 byte (1 B) copied, 7.9348e-05 seconds, 12.6 kB/s umount: /mnt/ext2: device is busy umount: /mnt/ext2: device is busy /opt/drivr_study/ext2_parse FileIn(),227:ftell size 73400320 FileIn(),247:file read size 73400320 main(),428:sizeof(super_block):1024 main(),429:s_magic:0xef53 main(),431:s_log_block_size:0 main(),441:block_size:1024 main(),449:nr_group:9 main(),461:s_block_group_nr:0 main(),461:s_block_group_nr:1 main(),461:s_block_group_nr:0 main(),461:s_block_group_nr:3 main(),461:s_block_group_nr:0 main(),461:s_block_group_nr:5 main(),461:s_block_group_nr:0 main(),461:s_block_group_nr:7 main(),461:s_block_group_nr:0 main(),470:group 0: main(),471:bg_block_bitmap:259 main(),472:bg_inode_bitmap:260 main(),473:bg_inode_table:261 main(),470:group 1: main(),471:bg_block_bitmap:8451 main(),472:bg_inode_bitmap:8452 main(),473:bg_inode_table:8453 main(),470:group 2: main(),471:bg_block_bitmap:16385 main(),472:bg_inode_bitmap:16386 main(),473:bg_inode_table:16387 main(),470:group 3: main(),471:bg_block_bitmap:24835 main(),472:bg_inode_bitmap:24836 main(),473:bg_inode_table:24837 main(),470:group 4: main(),471:bg_block_bitmap:32769 main(),472:bg_inode_bitmap:32770 main(),473:bg_inode_table:32771 main(),470:group 5: main(),471:bg_block_bitmap:41219 main(),472:bg_inode_bitmap:41220 main(),473:bg_inode_table:41221 main(),470:group 6: main(),471:bg_block_bitmap:49153 main(),472:bg_inode_bitmap:49154 main(),473:bg_inode_table:49155 main(),470:group 7: main(),471:bg_block_bitmap:57603 main(),472:bg_inode_bitmap:57604 main(),473:bg_inode_table:57605 main(),470:group 8: main(),471:bg_block_bitmap:65537 main(),472:bg_inode_bitmap:65538 main(),473:bg_inode_table:65539 main(),479:root_inode->i_size:1024 list_file(),386:. list_file(),386:.. list_file(),386:lost+found read_from_ext2_dir_entry_2(),300:start list file for lost+found list_file(),386:. list_file(),386:.. list_file(),373:p_dir_entry inode:0 read_from_ext2_dir_entry_2(),303:end of list_file lost+found list_file(),386:root_01 file_root_01_01234567aaaaaaaabbbbbbbbccccccccdddddddd list_file(),386:root_02 file_root_02_01234567aaaaaaaabbbbbbbbccccccccddddddddeeeeeeee list_file(),386:root_03 file_root_03_01234567aaaaaaaabbbbbbbbccccccccddddddddffffffff list_file(),386:d.home read_from_ext2_dir_entry_2(),300:start list file for d.home list_file(),386:. list_file(),386:.. read_from_ext2_dir_entry_2(),303:end of list_file d.home list_file(),386:d.lib read_from_ext2_dir_entry_2(),300:start list file for d.lib list_file(),386:. list_file(),386:.. read_from_ext2_dir_entry_2(),303:end of list_file d.lib list_file(),386:d.usr read_from_ext2_dir_entry_2(),300:start list file for d.usr list_file(),386:. list_file(),386:.. read_from_ext2_dir_entry_2(),303:end of list_file d.usr list_file(),386:d.boot read_from_ext2_dir_entry_2(),300:start list file for d.boot list_file(),386:. list_file(),386:.. list_file(),386:file00 file_in_d.boot_file00_named_file00_end_of_file list_file(),386:file01 file_in_d.boot_file01_named_file01_end_of_file list_file(),386:file02_file_hole Xread_from_ext2_dir_entry_2(),303:end of list_file d.boot
dumpe2fs:
$ dumpe2fs img.70M_2048 dumpe2fs 1.39 (29-May-2006) Filesystem volume name: <none> Last mounted on: <not available> Filesystem UUID: dc4c52d6-692e-4d99-a8bb-ed363dd83472 Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: resize_inode dir_index filetype sparse_super Default mount options: (none) Filesystem state: not clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 17928 Block count: 71680 Reserved block count: 3584 Free blocks: 68116 Free inodes: 17917 First block: 1 Block size: 1024 Fragment size: 1024 Reserved GDT blocks: 256 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 1992 Inode blocks per group: 249 Filesystem created: Thu Jan 29 02:59:27 2015 Last mount time: Thu Jan 29 02:59:27 2015 Last write time: Thu Jan 29 02:59:27 2015 Mount count: 1 Maximum mount count: 22 Last checked: Thu Jan 29 02:59:27 2015 Check interval: 15552000 (6 months) Next check after: Tue Jul 28 02:59:27 2015 Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Default directory hash: tea Directory Hash Seed: a46ae30c-3b9f-410d-856b-1c29adc3c0b6 Group 0: (Blocks 1-8192) Primary superblock at 1, Group descriptors at 2-2 Reserved GDT blocks at 3-258 Block bitmap at 259 (+258), Inode bitmap at 260 (+259) Inode table at 261-509 (+260) 7666 free blocks, 1978 free inodes, 2 directories Free blocks: 524-1024, 1028-8192 Free inodes: 15-1992 Group 1: (Blocks 8193-16384) Backup superblock at 8193, Group descriptors at 8194-8194 Reserved GDT blocks at 8195-8450 Block bitmap at 8451 (+258), Inode bitmap at 8452 (+259) Inode table at 8453-8701 (+260) 7683 free blocks, 1992 free inodes, 0 directories Free blocks: 8702-16384 Free inodes: 1993-3984 Group 2: (Blocks 16385-24576) Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1) Inode table at 16387-16635 (+2) 7940 free blocks, 1991 free inodes, 1 directories Free blocks: 16636-24064, 24066-24576 Free inodes: 3986-5976 Group 3: (Blocks 24577-32768) Backup superblock at 24577, Group descriptors at 24578-24578 Reserved GDT blocks at 24579-24834 Block bitmap at 24835 (+258), Inode bitmap at 24836 (+259) Inode table at 24837-25085 (+260) 7683 free blocks, 1992 free inodes, 0 directories Free blocks: 25086-32768 Free inodes: 5977-7968 Group 4: (Blocks 32769-40960) Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1) Inode table at 32771-33019 (+2) 7937 free blocks, 1988 free inodes, 1 directories Free blocks: 33020-33280, 33282-33792, 33795-40448, 40450-40960 Free inodes: 7973-9960 Group 5: (Blocks 40961-49152) Backup superblock at 40961, Group descriptors at 40962-40962 Reserved GDT blocks at 40963-41218 Block bitmap at 41219 (+258), Inode bitmap at 41220 (+259) Inode table at 41221-41469 (+260) 7682 free blocks, 1991 free inodes, 1 directories Free blocks: 41470-48640, 48642-49152 Free inodes: 9962-11952 Group 6: (Blocks 49153-57344) Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1) Inode table at 49155-49403 (+2) 7940 free blocks, 1991 free inodes, 1 directories Free blocks: 49404-56832, 56834-57344 Free inodes: 11954-13944 Group 7: (Blocks 57345-65536) Backup superblock at 57345, Group descriptors at 57346-57346 Reserved GDT blocks at 57347-57602 Block bitmap at 57603 (+258), Inode bitmap at 57604 (+259) Inode table at 57605-57853 (+260) 7683 free blocks, 1992 free inodes, 0 directories Free blocks: 57854-65536 Free inodes: 13945-15936 Group 8: (Blocks 65537-71679) Block bitmap at 65537 (+0), Inode bitmap at 65538 (+1) Inode table at 65539-65787 (+2) 5892 free blocks, 1992 free inodes, 0 directories Free blocks: 65788-71679 Free inodes: 15937-17928