diff options
Diffstat (limited to 'toys')
-rw-r--r-- | toys/e2fs.h | 2 | ||||
-rw-r--r-- | toys/mke2fs.c | 149 | ||||
-rw-r--r-- | toys/toylist.h | 4 |
3 files changed, 111 insertions, 44 deletions
diff --git a/toys/e2fs.h b/toys/e2fs.h index 5a2cb64d..08d3a901 100644 --- a/toys/e2fs.h +++ b/toys/e2fs.h @@ -99,7 +99,7 @@ struct ext2_inode { uint32_t block[15]; // Pointers to blocks uint32_t generation; // File version (for NFS) uint32_t file_acl; // File ACL - uint32_t dir_acl; // Directory ACL + uint32_t dir_acl; // Directory ACL (or top bits of file length) uint32_t faddr; // Fragment address uint8_t frag; // Fragment number uint8_t fsize; // Fragment size diff --git a/toys/mke2fs.c b/toys/mke2fs.c index bade3d22..7fb45e8c 100644 --- a/toys/mke2fs.c +++ b/toys/mke2fs.c @@ -31,12 +31,13 @@ #define INODES_RESERVED 10 // Calculate data blocks plus index blocks needed to hold a file. -uint32_t blocks_used(uint64_t size) + +static uint32_t count_blocks_used(uint64_t size) { uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; - // Account for direct, singly, doubly, and triply indiret index blocks + // Account for direct, singly, doubly, and triply indirect index blocks if (dblocks > 12) { iblocks = ((dblocks-13)/idx)+1; @@ -46,10 +47,35 @@ uint32_t blocks_used(uint64_t size) tiblocks = ((diblocks-2)/idx)+1; } } - + return dblocks + iblocks + diblocks + tiblocks; } +// Calculate the number of blocks used by each inode. Returns blocks used, +// assigns bytes used to *size. Writes total block count to TT.treeblocks +// and inode count to TT.treeinodes. + +long check_treesize(struct dirtree *this, off_t *size) +{ + long blocks; + + while (this) { + *size += sizeof(struct ext2_dentry) + strlen(this->name); + + if (this->child) + this->st.st_blocks = check_treesize(this->child, &this->st.st_size); + else if (S_ISREG(this->st.st_mode)) { + this->st.st_blocks = count_blocks_used(this->st.st_size); + TT.treeblocks += this->st.st_blocks; + } + this = this->next; + } + TT.treeblocks += blocks = count_blocks_used(*size); + TT.treeinodes++; + + return blocks; +} + // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm // we should generate a uuid structure by reading a clock with 100 nanosecond // precision, normalizing it to the start of the gregorian calendar in 1582, @@ -60,7 +86,7 @@ uint32_t blocks_used(uint64_t size) static void create_uuid(char *uuid) { - // Read 128 random bytes + // Read 128 random bits int fd = xopen("/dev/urandom", O_RDONLY); xreadall(fd, uuid, 16); close(fd); @@ -90,7 +116,6 @@ static void init_superblock(struct ext2_superblock *sb) // Fill out blocks_count, r_blocks_count, first_data_block sb->blocks_count = SWAP_LE32(TT.blocks); - if (!TT.reserved_percent) TT.reserved_percent = 5; temp = (TT.blocks * (uint64_t)TT.reserved_percent) /100; sb->r_blocks_count = SWAP_LE32(temp); @@ -108,27 +133,27 @@ static void init_superblock(struct ext2_superblock *sb) TT.groups = (TT.blocks)/temp; if (TT.blocks & (temp-1)) TT.groups++; - // Figure out how many inodes we need. + // Figure out how many total inodes we need. - if (!TT.inodes) { + if (!TT.inodespg) { if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; - TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; + TT.inodespg = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; } // Figure out inodes per group, rounded up to block size. // How many blocks of inodes total, rounded up - temp = TT.inodes / (TT.blocksize/sizeof(struct ext2_inode)); - if (temp * (TT.blocksize/sizeof(struct ext2_inode)) != TT.inodes) temp++; + temp = TT.inodespg / (TT.blocksize/sizeof(struct ext2_inode)); + if (temp * (TT.blocksize/sizeof(struct ext2_inode)) != TT.inodespg) temp++; // How many blocks of inodes per group, again rounded up - TT.inodes = temp / TT.groups; - if (temp & (TT.groups-1)) TT.inodes++; + TT.inodespg = temp / TT.groups; + if (temp & (TT.groups-1)) TT.inodespg++; // How many inodes per group is that? - TT.inodes *= (TT.blocksize/sizeof(struct ext2_inode)); + TT.inodespg *= (TT.blocksize/sizeof(struct ext2_inode)); // Set inodes_per_group and total inodes_count - sb->inodes_per_group = SWAP_LE32(TT.inodes); - sb->inodes_count = SWAP_LE32(TT.inodes *= TT.groups); + sb->inodes_per_group = SWAP_LE32(TT.inodespg); + sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); // Fill out the rest of the superblock. sb->max_mnt_count=0xFFFF; @@ -195,6 +220,43 @@ static void bits_set(char *array, int start, int len) } } +// Seek past len bytes (to maintain sparse file), or write zeroes if output +// not seekable +static void put_zeroes(int len) +{ + if(TT.noseek || -1 == lseek(TT.fsfd, len, SEEK_SET)) { + + TT.noseek=1; + memset(toybuf, 0, sizeof(toybuf)); + while (len) { + int out = len > sizeof(toybuf) ? sizeof(toybuf) : len; + xwrite(TT.fsfd, toybuf, out); + len -= out; + } + } +} + +static void fill_inode(struct ext2_inode *in, struct dirtree *this) +{ + memset(in,0,sizeof(struct ext2_inode)); + + // This works on Linux. S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) + in->mode = this->st.st_mode; + + in->uid = this->st.st_uid & 0xFFFF; + in->uid_high = this->st.st_uid >> 16; + in->gid = this->st.st_gid & 0xFFFF; + in->gid_high = this->st.st_gid >> 16; + in->size = this->st.st_size & 0xFFFFFFFF; + + in->atime = this->st.st_atime; + in->ctime = this->st.st_ctime; + in->mtime = this->st.st_mtime; + + in->links_count = this->st.st_nlink; // TODO + in->blocks = this->st.st_blocks; +} + int mke2fs_main(void) { int i, temp, blockbits; @@ -219,7 +281,7 @@ int mke2fs_main(void) TT.dt->st.st_ctime = TT.dt->st.st_mtime = time(NULL); } - // Calculate st_nlink for each node in tree. + // TODO: Calculate st_nlink for each node in tree. // TODO: Check if filesystem is mounted here @@ -233,18 +295,26 @@ int mke2fs_main(void) if (!TT.blocks) TT.blocks = length/TT.blocksize; if (!TT.blocks) error_exit("gene2fs is a TODO item"); - // Skip the first 1k to avoid the boot sector (if any). Use this to - // figure out if this file is seekable. - if(-1 == lseek(TT.fsfd, 1024, SEEK_SET)) { - TT.noseek=1; - xwrite(TT.fsfd, &TT.sb, 1024); - } - - // Initialize superblock structure + // Skip the first 1k to avoid the boot sector (if any), then + // initialize superblock structure + put_zeroes(1024); init_superblock(&TT.sb); blockbits = 8*TT.blocksize; + // Figure out how much space is used + length = 0; + length = check_treesize(TT.dt, &length); + for (temp=i=0; i<TT.groups; i++) { + temp += group_superblock_used(i) + 2; + temp += TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)); + } + TT.sb.free_blocks_count = SWAP_LE32(TT.blocks - TT.treeblocks - temp); + TT.sb.free_inodes_count = SWAP_LE32(TT.inodespg*TT.groups - INODES_RESERVED + - TT.treeinodes); + + // Figure out how many inodes are used + // Loop through block groups. for (i=0; i<TT.groups; i++) { @@ -257,7 +327,7 @@ int mke2fs_main(void) if ((i+1)*blockbits > TT.blocks) end = TT.blocks & (blockbits-1); // Blocks used by inode table - itable = ((TT.inodes/TT.groups)*sizeof(struct ext2_inode))/TT.blocksize; + itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; // If a superblock goes here, write it out. start = group_superblock_used(i); @@ -286,18 +356,13 @@ int mke2fs_main(void) memset(bg, 0, TT.blocksize); } - // sb.inodes_per_group is uint32_t, but group.free_inodes_count - // is uint16_t. Add in endianness conversion and this little - // dance is called for. - temp = SWAP_LE32(TT.sb.inodes_per_group); + // How many free inodes in this group? (TODO) + temp = TT.inodespg; if (!i) temp -= INODES_RESERVED; bg[slot].free_inodes_count = SWAP_LE16(temp); - - // How many blocks will the inode table use? - temp *= sizeof(struct ext2_inode); - temp /= TT.blocksize; - // How many does that leave? (TODO: fill it up) + // How many free blocks in this group? (TODO) + temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2; temp = end-used-temp; bg[slot].free_blocks_count = SWAP_LE32(temp); @@ -321,26 +386,28 @@ int mke2fs_main(void) xwrite(TT.fsfd, toybuf, TT.blocksize); // Write inode bitmap (TODO) - temp = TT.inodes/TT.groups; memset(toybuf, 0, TT.blocksize); if (!i) bits_set(toybuf, 0, INODES_RESERVED); - bits_set(toybuf, temp, blockbits-temp); + bits_set(toybuf, TT.inodespg, blockbits-TT.inodespg); xwrite(TT.fsfd, toybuf, TT.blocksize); + start += 3; + // Write inode table for this group - for (j = 0; j<temp; j++) { + for (j = 0; j<TT.inodespg; j++) { slot = j % (TT.blocksize/sizeof(struct ext2_inode)); if (!slot) { - if (j) xwrite(TT.fsfd, in, TT.blocksize); + if (j) { + xwrite(TT.fsfd, in, TT.blocksize); + start++; + } memset(in, 0, TT.blocksize); } } xwrite(TT.fsfd, in, TT.blocksize); // Write empty data blocks - memset(toybuf, 0, TT.blocksize); - for (j = start; j < end; j++) - xwrite(TT.fsfd, toybuf, TT.blocksize); + put_zeroes((end-start) * TT.blocksize); } return 0; diff --git a/toys/toylist.h b/toys/toylist.h index 87aaba84..ae2ff2c5 100644 --- a/toys/toylist.h +++ b/toys/toylist.h @@ -21,11 +21,11 @@ struct df_data { struct mke2fs_data { long blocksize; long bytes_per_inode; - long inodes; + long inodespg; long reserved_percent; char *gendir; - unsigned blocks, groups; + unsigned blocks, groups, treeblocks, treeinodes; int fsfd, noseek; struct ext2_superblock sb; struct dirtree *dt; |