aboutsummaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
Diffstat (limited to 'toys')
-rw-r--r--toys/e2fs.h2
-rw-r--r--toys/mke2fs.c149
-rw-r--r--toys/toylist.h4
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;