John's spec of the second extended filesystem
This information has been compiled from resources published on the internet, the Linux kernel source and information gained from experimentation.
The primary focus of the document is to provide enough information to allow someone to read the file system.
When Linus was first creating Linux, he used the Minix filesystem. This served initial development well but soon there was a need for something bigger and better.
In April 1992, the Extended File System was created. Although solving the problems of Minix, it had problems of it's own so a successor was created. This new filesystem was known as the Second Extended File System or Ext2 FS (or EXT2).
The file system is created from a sequential collection of blocks. These blocks can be either 1k, 2k or 4k in size. These blocks are divided up into groups for various reasons which will be discussed below.
The starting point for the filesystem is the superblock. This is a structure 1024 bytes in length and is always located at an offset of 1024 bytes from the start of the filesystem. This means that it might be in block 0 or block 1, depending on the block size of the filesystem. This is the reason for the s_first_data_block entry in the superblock.
The following is a list of the structure used by Linux. Note that other OS's may use a different structure. For details see ???.h
The information in the superblock is used to access the rest of the data on the disk.
The number of block groups = the number of blocks / the number of blocks per group; // rounded up
(There are several calculations which require divisions rounded up. I wrote a function called div2 which does the division and then checks to see if it should round up the result)
All block and inode addresses start at 1. The first block on the disk is block 1. 0 is used to indicate no block. (Sparse files can have these inside them)
Each block group can be found at the block address ((group_number - 1)* blocks_per_group) and is of course blocks_per_group long. Group numbers are 1 based as well
Each group is just a series of blocks, however the first blocks in the group have a special purpose. The remainder are used for storing data.
The Group Descriptors contains information on the block groups. This data is covers all the groups and is stored in all the groups for redundancy. This is an array of the following structure
The size of the descriptors can be calculated as (sizeof(ext2_group) * number_of_groups) / block size; // rounded up if necessary
The information in this structure us used to locate the block and inode bitmaps and inode table.
Remember that the first entry corresponds to block group 1.
The block bitmap is a bitmap indicating which blocks in the group have been allocated. If the bit is set then the block is allocated. The size of the bitmap is (blocks_per_group / 8) / block_size;// with both divisions rounded up.
It is necessary to find out which group a particular group is in to be able to look up the bitmap. The group = ((block_number - 1) / blocks_per_group) + 1; // rounded up
The block in that group is then block_number - (group * blocks_per_group)
The inode bitmap is essentially the same as the block bitmap, but indicates which inodes are allocated. The size of the inode bitmpap is (inodes_per_group / 8) / block_size;// with both divisions rounded up.
The same calculations can be used for finding the group of a particular inode. The group = ((INode_number - 1) / INodes_per_group) + 1; // rounded up
The inode in that group is then INode_Number - (Group * INodes_per_group)
The inode table is an array of the inodes for that particular group. Again, the first entry is for the first inode in that group.
The file mode is a set of flags that specify the type of file and the access permissions
The i_block entry is an array of block addresses. The first EXT2_NDIR_BLOCKS (12) are direct block addresses. The data in these blocks is the content of the file. (According to ???, ??% of files in a unix environment are less than 12k, assuming a 1k block size the decision to use 12 direct blocks makes a lot of sense).
The next block EXT2_IND_BLOCK in the indirect block. This is the address of a block which contains a list of addresses of blocks which contain the data. There are block_size / sizeof(ULONG) addresses in this block.
The EXT2_DIND_BLOCK is similar, but it is a double indirect block. It contains the address of a block which has a list of indirect block addresses. Each indirect block then has another list is blocks.
The EXT2_TIND_BLOCK is similar again, but it is the triple indirect block. It contains a list of double indirect blocks etc.
Now that you know how to find and read inodes, you can start to read the files. There are a set of special inodes which are reserved for certain purposes. These include
The most important inode here is the root inode. This is the inode at the root of the file system. This inode is a directory, which like all directories has the following structure:
A directory is a list of these structures. The structures can not pass over a block boundary, so the last record is extended to fill the block. And entry with an inode of 0 should be ignored.