17aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley/* mke2fs.c - Create an ext2 filesystem image. 2055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley * 3fece5cb6d796119eccb1ae0074e5b3aaccbb74eeRob Landley * Copyright 2006, 2007 Rob Landley <rob@landley.net> 42896480c4918f2accccb8301bec457a7bff7377eRob Landley 5eb9b8da0698aacd14f5aa0879d2a8e390c0c6c13Rob Landley// Still to go: "E:jJ:L:m:O:" 6eb9b8da0698aacd14f5aa0879d2a8e390c0c6c13Rob LandleyUSE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN)) 755928b1e0a08d84a5cbc50020f0a8c1024f5b6ceRob Landley 82896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig MKE2FS 9e3f0787a94c1727a4c59bbd46c612bcff298e027Rob Landley bool "mke2fs" 107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default n 117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 127aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device 132896480c4918f2accccb8301bec457a7bff7377eRob Landley 147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley Create an ext2 filesystem on a block device or filesystem image. 152896480c4918f2accccb8301bec457a7bff7377eRob Landley 167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -F Force to run on a mounted device 177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -n Don't write to device 187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -q Quiet (no output) 197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -b size Block size (1024, 2048, or 4096) 207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -N inodes Allocate this many inodes 217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -i bytes Allocate one inode for every XXX bytes of device 227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -m percent Reserve this percent of filesystem space for root user 232896480c4918f2accccb8301bec457a7bff7377eRob Landley 242896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig MKE2FS_JOURNAL 257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bool "Journaling support (ext3)" 267aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default n 277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley depends on MKE2FS 287aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 295486075caee329fcc5ab7766a8a571fd3a45d363Rob Landley usage: mke2fs [-j] [-J size=###,device=XXX] 302896480c4918f2accccb8301bec457a7bff7377eRob Landley 317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -j Create journal (ext3) 327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -J Journal options 337aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley size: Number of blocks (1024-102400) 347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley device: Specify an external journal 352896480c4918f2accccb8301bec457a7bff7377eRob Landley 362896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig MKE2FS_GEN 377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bool "Generate (gene2fs)" 387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default n 397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley depends on MKE2FS 407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley usage: gene2fs [options] device filename 422896480c4918f2accccb8301bec457a7bff7377eRob Landley 437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley The [options] are the same as mke2fs. 442896480c4918f2accccb8301bec457a7bff7377eRob Landley 452896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig MKE2FS_LABEL 467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bool "Label support" 477aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default n 487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley depends on MKE2FS 497aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley usage: mke2fs [-L label] [-M path] [-o string] 512896480c4918f2accccb8301bec457a7bff7377eRob Landley 527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -L Volume label 537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -M Path to mount point 547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -o Created by 552896480c4918f2accccb8301bec457a7bff7377eRob Landley 562896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig MKE2FS_EXTENDED 577aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bool "Extended options" 587aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley default n 597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley depends on MKE2FS 607aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley help 617aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley usage: mke2fs [-E stride=###] [-O option[,option]] 627aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 637aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -E stride= Set RAID stripe size (in blocks) 647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley -O [opts] Specify fewer ext2 option flags (for old kernels) 657aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley All of these are on by default (as appropriate) 667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley none Clear default options (all but journaling) 677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dir_index Use htree indexes for large directories 687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley filetype Store file type info in directory entry 697aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley has_journal Set by -j 707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley journal_dev Set by -J device=XXX 717aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sparse_super Don't allocate huge numbers of redundant superblocks 722896480c4918f2accccb8301bec457a7bff7377eRob Landley*/ 73055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 74c0e56edaf256adb6c60c5a052525a1ffbb927901Rob Landley#define FOR_mke2fs 75055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley#include "toys.h" 76055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 77c0e56edaf256adb6c60c5a052525a1ffbb927901Rob LandleyGLOBALS( 787aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Command line arguments. 797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long blocksize; 807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long bytes_per_inode; 817aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long inodes; // Total inodes in filesystem. 827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long reserved_percent; // Integer precent of space to reserve for root. 837aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley char *gendir; // Where to read dirtree from. 847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 857aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Internal data. 867aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct dirtree *dt; // Tree of files to copy into the new filesystem. 877aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned treeblocks; // Blocks used by dt 887aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned treeinodes; // Inodes used by dt 897aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 907aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned blocks; // Total blocks in the filesystem. 917aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned freeblocks; // Free blocks in the filesystem. 927aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned inodespg; // Inodes per group 937aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned groups; // Total number of block groups. 947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned blockbits; // Bits per block. (Also blocks per group.) 957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // For gene2fs 977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned nextblock; // Next data block to allocate 987aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley unsigned nextgroup; // Next group we'll be allocating from 997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int fsfd; // File descriptor of filesystem (to output to). 1007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 1017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct ext2_superblock sb; 102b1aaba1fc8176ac0b7c202a664d2554aa0967116Rob Landley) 103b1aaba1fc8176ac0b7c202a664d2554aa0967116Rob Landley 1048f4119a5a68b4fcec6543b593e90271faff11005Rob Landley#define INODES_RESERVED 10 105055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 1068f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic uint32_t div_round_up(uint32_t a, uint32_t b) 1078f4119a5a68b4fcec6543b593e90271faff11005Rob Landley{ 1087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t c = a/b; 109055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 1107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (a%b) c++; 1117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return c; 1128f4119a5a68b4fcec6543b593e90271faff11005Rob Landley} 113055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 114720fc26d33352407715cb286a4edc23d15906d5fRob Landley// Calculate data blocks plus index blocks needed to hold a file. 1154f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 1168f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist) 117720fc26d33352407715cb286a4edc23d15906d5fRob Landley{ 1187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); 1197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; 120720fc26d33352407715cb286a4edc23d15906d5fRob Landley 1217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Fill out index blocks in inode. 1228f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (blocklist) { 1247aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int i; 1258f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1267aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Direct index blocks 1277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (i=0; i<13 && i<dblocks; i++) blocklist[i] = i; 1287aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Singly indirect index blocks 1297aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (dblocks > 13+idx) blocklist[13] = 13+idx; 1307aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Doubly indirect index blocks 1317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley idx = 13 + idx + (idx*idx); 1327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (dblocks > idx) blocklist[14] = idx; 1338f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return 0; 1357aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1368f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Account for direct, singly, doubly, and triply indirect index blocks 138720fc26d33352407715cb286a4edc23d15906d5fRob Landley 1397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (dblocks > 12) { 1407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley iblocks = ((dblocks-13)/idx)+1; 1417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (iblocks > 1) { 1427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley diblocks = ((iblocks-2)/idx)+1; 1437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (diblocks > 1) 1447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley tiblocks = ((diblocks-2)/idx)+1; 1457aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1474f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 1487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return dblocks + iblocks + diblocks + tiblocks; 149720fc26d33352407715cb286a4edc23d15906d5fRob Landley} 150720fc26d33352407715cb286a4edc23d15906d5fRob Landley 1518f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Use the parent pointer to iterate through the tree non-recursively. 1528f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic struct dirtree *treenext(struct dirtree *this) 1538f4119a5a68b4fcec6543b593e90271faff11005Rob Landley{ 1547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (this && !this->next) this = this->parent; 1557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (this) this = this->next; 1568f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1577aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return this; 1588f4119a5a68b4fcec6543b593e90271faff11005Rob Landley} 1598f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 1608f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Recursively calculate the number of blocks used by each inode in the tree. 1618f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Returns blocks used by this directory, assigns bytes used to *size. 1628f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Writes total block count to TT.treeblocks and inode count to TT.treeinodes. 1634f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 164b1aaba1fc8176ac0b7c202a664d2554aa0967116Rob Landleystatic long check_treesize(struct dirtree *that, off_t *size) 1654f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley{ 1667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long blocks; 1677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 1687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (that) { 1697aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley *size += sizeof(struct ext2_dentry) + strlen(that->name); 1707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 1717aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (that->child) 1727aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley that->st.st_blocks = check_treesize(that->child, &that->st.st_size); 1737aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley else if (S_ISREG(that->st.st_mode)) { 1747aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley that->st.st_blocks = file_blocks_used(that->st.st_size, 0); 1757aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.treeblocks += that->st.st_blocks; 1767aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1777aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley that = that->next; 1787aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 1797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.treeblocks += blocks = file_blocks_used(*size, 0); 1807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.treeinodes++; 1817aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 1827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return blocks; 1834f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley} 1844f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 1858f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Calculate inode numbers and link counts. 1867aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley// 187fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley// To do this right I need to copy the tree and sort it, but here's a really 188fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley// ugly n^2 way of dealing with the problem that doesn't scale well to large 1898f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// numbers of files (> 100,000) but can be done in very little code. 1908f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// This rewrites inode numbers to their final values, allocating depth first. 191fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley 1928f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic void check_treelinks(struct dirtree *tree) 193fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley{ 1947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct dirtree *current=tree, *that; 1957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley long inode = INODES_RESERVED; 1967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 1977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (current) { 1987aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley ++inode; 1997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Since we can't hardlink to directories, we know their link count. 2007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (S_ISDIR(current->st.st_mode)) current->st.st_nlink = 2; 2017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley else { 2027aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dev_t new = current->st.st_dev; 2037aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 2047aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!new) continue; 2057aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 2067aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Look for other copies of current node 2077aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current->st.st_nlink = 0; 2087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (that = tree; that; that = treenext(that)) { 2097aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (current->st.st_ino == that->st.st_ino && 2107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current->st.st_dev == that->st.st_dev) 2117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley { 2127aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current->st.st_nlink++; 2137aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current->st.st_ino = inode; 2147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 2157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 2167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 2177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current->st.st_ino = inode; 2187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley current = treenext(current); 2197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 220fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley} 221fb6c09e63653b619f6645617d66ba605077d1d42Rob Landley 222055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm 223055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// we should generate a uuid structure by reading a clock with 100 nanosecond 224055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// precision, normalizing it to the start of the gregorian calendar in 1582, 225055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// and looking up our eth0 mac address. 226055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// 227055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// On the other hand, we have 128 bits to come up with a unique identifier, of 228055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley// which 6 have a defined value. /dev/urandom it is. 229055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 230103b7e031c4de0f9753e02d2217aa81819242278Rob Landleystatic void create_uuid(char *uuid) 231055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley{ 2327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Read 128 random bits 2337aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int fd = xopen("/dev/urandom", O_RDONLY); 2347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xreadall(fd, uuid, 16); 2357aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley close(fd); 2367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 2377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Claim to be a DCE format UUID. 2387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uuid[6] = (uuid[6] & 0x0F) | 0x40; 2397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uuid[8] = (uuid[8] & 0x3F) | 0x80; 2407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 2417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // rfc2518 section 6.4.1 suggests if we're not using a macaddr, we should 2427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // set bit 1 of the node ID, which is the mac multicast bit. This means we 2437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // should never collide with anybody actually using a macaddr. 2447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uuid[11] = uuid[11] | 128; 245055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley} 246055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 2478f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Calculate inodes per group from total inodes. 248cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landleystatic uint32_t get_inodespg(uint32_t inodes) 249cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley{ 2507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t temp; 251cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley 2527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Round up to fill complete inode blocks. 2537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = (inodes + TT.groups - 1) / TT.groups; 2547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley inodes = TT.blocksize/sizeof(struct ext2_inode); 2557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return ((temp + inodes - 1)/inodes)*inodes; 256cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley} 257cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley 2588f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Fill out superblock and TT structures. 25943d7e909cb98e02ea11877f7516e721ac0aa5b5dRob Landley 2603ac8d261fd430c45f4827570cb5146336cbc656aRob Landleystatic void init_superblock(struct ext2_superblock *sb) 261055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley{ 2627aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t temp; 263055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 2647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Set log_block_size and log_frag_size. 265055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 2667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (temp = 0; temp < 4; temp++) if (TT.blocksize == 1024<<temp) break; 2677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp==4) error_exit("bad blocksize"); 2687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp); 269055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 2707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Fill out blocks_count, r_blocks_count, first_data_block 2716b7092fd084070daeef5aeb60b608a633d56f252Rob Landley 2727aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->blocks_count = SWAP_LE32(TT.blocks); 2737aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->free_blocks_count = SWAP_LE32(TT.freeblocks); 2747aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; 2757aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->r_blocks_count = SWAP_LE32(temp); 2766b7092fd084070daeef5aeb60b608a633d56f252Rob Landley 2777aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); 27822eca62ff07e97063eb77dc61660a91e12fed182Rob Landley 2797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Set blocks_per_group and frags_per_group, which is the size of an 2807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // allocation bitmap that fits in one block (I.E. how many bits per block)? 2816b7092fd084070daeef5aeb60b608a633d56f252Rob Landley 2827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); 2836b7092fd084070daeef5aeb60b608a633d56f252Rob Landley 2847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Set inodes_per_group and total inodes_count 2857aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->inodes_per_group = SWAP_LE32(TT.inodespg); 2867aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); 2876b7092fd084070daeef5aeb60b608a633d56f252Rob Landley 2887aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Determine free inodes. 2897aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.inodespg*TT.groups - INODES_RESERVED; 2907aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); 2917aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes); 2928f4119a5a68b4fcec6543b593e90271faff11005Rob Landley 2937aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Fill out the rest of the superblock. 2947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->max_mnt_count=0xFFFF; 2957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); 2967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->magic = SWAP_LE32(0xEF53); 2977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->state = sb->errors = SWAP_LE16(1); 298055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 2997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->rev_level = SWAP_LE32(1); 3007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->first_ino = SWAP_LE32(INODES_RESERVED+1); 3017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); 3027aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); 3037aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); 304055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 3057aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley create_uuid(sb->uuid); 306055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley 3077aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO If we're called as mke3fs or mkfs.ext3, do a journal. 3087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3097aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley //if (strchr(toys.which->name,'3')) 3107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); 31143d7e909cb98e02ea11877f7516e721ac0aa5b5dRob Landley} 31243d7e909cb98e02ea11877f7516e721ac0aa5b5dRob Landley 313cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley// Does this group contain a superblock backup (and group descriptor table)? 314cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landleystatic int is_sb_group(uint32_t group) 3153ac8d261fd430c45f4827570cb5146336cbc656aRob Landley{ 3167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int i; 3177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Superblock backups are on groups 0, 1, and powers of 3, 5, and 7. 3197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if(!group || group==1) return 1; 3207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (i=3; i<9; i+=2) { 3217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int j = i; 3227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (j<group) j*=i; 3237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (j==group) return 1; 3247aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 3257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return 0; 326cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley} 3273ac8d261fd430c45f4827570cb5146336cbc656aRob Landley 3287aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3298f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Number of blocks used in group by optional superblock/group list backup. 3308f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic int group_superblock_overhead(uint32_t group) 331cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley{ 3327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int used; 333cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley 3347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!is_sb_group(group)) return 0; 335cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley 3367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // How many blocks does the group descriptor table take up? 3377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used = TT.groups * sizeof(struct ext2_group); 3387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used += TT.blocksize - 1; 3397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used /= TT.blocksize; 3407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Plus the superblock itself. 3417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used++; 3427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // And a corner case. 3437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!group && TT.blocksize == 1024) used++; 3443ac8d261fd430c45f4827570cb5146336cbc656aRob Landley 3457aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return used; 3463ac8d261fd430c45f4827570cb5146336cbc656aRob Landley} 3473ac8d261fd430c45f4827570cb5146336cbc656aRob Landley 3488f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Number of blocks used in group to store superblock/group/inode list 3498f4119a5a68b4fcec6543b593e90271faff11005Rob Landleystatic int group_overhead(uint32_t group) 350cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley{ 3517aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Return superblock backup overhead (if any), plus block/inode 3527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // allocation bitmaps, plus inode tables. 3537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley return group_superblock_overhead(group) + 2 + get_inodespg(TT.inodespg) 3547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley / (TT.blocksize/sizeof(struct ext2_inode)); 355cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley} 356cff28b7bcda93a5ac1a3203a6ac8cbef55f23856Rob Landley 3578f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// In bitmap "array" set "len" bits starting at position "start" (from 0). 3589568d5afcfea1b5a5019c23e25bba33283970f30Rob Landleystatic void bits_set(char *array, int start, int len) 3599568d5afcfea1b5a5019c23e25bba33283970f30Rob Landley{ 3607aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while(len) { 3617aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if ((start&7) || len<8) { 3627aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley array[start/8]|=(1<<(start&7)); 3637aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley start++; 3647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley len--; 3657aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else { 3667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley array[start/8]=255; 3677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley start+=8; 3687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley len-=8; 3697aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 3707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 3719568d5afcfea1b5a5019c23e25bba33283970f30Rob Landley} 3729568d5afcfea1b5a5019c23e25bba33283970f30Rob Landley 3734f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley// Seek past len bytes (to maintain sparse file), or write zeroes if output 3744f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley// not seekable 3754f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landleystatic void put_zeroes(int len) 3764f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley{ 3777aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if(-1 == lseek(TT.fsfd, len, SEEK_SET)) { 3787aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(toybuf, 0, sizeof(toybuf)); 3797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (len) { 3807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int out = len > sizeof(toybuf) ? sizeof(toybuf) : len; 3817aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, toybuf, out); 3827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley len -= out; 3837aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 3847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 3854f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley} 3864f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 3878f4119a5a68b4fcec6543b593e90271faff11005Rob Landley// Fill out an inode structure from struct stat info in dirtree. 388b1aaba1fc8176ac0b7c202a664d2554aa0967116Rob Landleystatic void fill_inode(struct ext2_inode *in, struct dirtree *that) 3894f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley{ 3907aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t fbu[15]; 3917aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int temp; 3927aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3937aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley file_blocks_used(that->st.st_size, fbu); 3947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // If that inode needs data blocks allocated to it. 3967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (that->st.st_size) { 3977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int i, group = TT.nextblock/TT.blockbits; 3987aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 3997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO: teach this about indirect blocks. 4007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (i=0; i<15; i++) { 4017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // If we just jumped into a new group, skip group overhead blocks. 4027aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (group >= TT.nextgroup) 4037aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.nextblock += group_overhead(TT.nextgroup++); 4047aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 4057aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 4067aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) 4077aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->mode = SWAP_LE32(that->st.st_mode); 4087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4097aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->uid = SWAP_LE16(that->st.st_uid & 0xFFFF); 4107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->uid_high = SWAP_LE16(that->st.st_uid >> 16); 4117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->gid = SWAP_LE16(that->st.st_gid & 0xFFFF); 4127aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->gid_high = SWAP_LE16(that->st.st_gid >> 16); 4137aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->size = SWAP_LE32(that->st.st_size & 0xFFFFFFFF); 4147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Contortions to make the compiler not generate a warning for x>>32 4167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // when x is 32 bits. The optimizer should clean this up. 4177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (sizeof(that->st.st_size) > 4) temp = 32; 4187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley else temp = 0; 4197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp) in->dir_acl = SWAP_LE32(that->st.st_size >> temp); 4207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->atime = SWAP_LE32(that->st.st_atime); 4227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->ctime = SWAP_LE32(that->st.st_ctime); 4237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->mtime = SWAP_LE32(that->st.st_mtime); 4247aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->links_count = SWAP_LE16(that->st.st_nlink); 4267aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley in->blocks = SWAP_LE32(that->st.st_blocks); 4277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // in->faddr 4284f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley} 4294f5a671bf49bcce98be1a0be847cf4f5eaeacd2aRob Landley 430103b7e031c4de0f9753e02d2217aa81819242278Rob Landley// Works like an archiver. 431103b7e031c4de0f9753e02d2217aa81819242278Rob Landley// The first argument is the name of the file to create. If it already 432103b7e031c4de0f9753e02d2217aa81819242278Rob Landley// exists, that size will be used. 433103b7e031c4de0f9753e02d2217aa81819242278Rob Landley 434efda21ca931766eed6cfc49d1b2122c53827d9fcRob Landleyvoid mke2fs_main(void) 43543d7e909cb98e02ea11877f7516e721ac0aa5b5dRob Landley{ 4367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int i, temp; 4377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley off_t length; 4387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t usedblocks, usedinodes, dtiblk, dtbblk; 4397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct dirtree *dti, *dtb; 4407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Handle command line arguments. 4427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (toys.optargs[1]) { 4447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley sscanf(toys.optargs[1], "%u", &TT.blocks); 4457aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = O_RDWR|O_CREAT; 4467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else temp = O_RDWR; 4477aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.reserved_percent) TT.reserved_percent = 5; 4487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4497aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO: Check if filesystem is mounted here 4507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4517aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // For mke?fs, open file. For gene?fs, create file. 4527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.fsfd = xcreate(*toys.optargs, temp, 0777); 4537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Determine appropriate block size and block count from file length. 4557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // (If no length, default to 4k. They can override it on the cmdline.) 4567aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4577aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley length = fdlength(TT.fsfd); 4587aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; 4597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.blockbits = 8*TT.blocksize; 4607aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.blocks) TT.blocks = length/TT.blocksize; 4617aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4627aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Collect gene2fs list or lost+found, calculate requirements. 4637aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (TT.gendir) { 4657aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley strncpy(toybuf, TT.gendir, sizeof(toybuf)); 466e3f0787a94c1727a4c59bbd46c612bcff298e027Rob Landley dti = dirtree_read(toybuf, dirtree_notdotdot); 4677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else { 4687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dti = xzalloc(sizeof(struct dirtree)+11); 4697aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley strcpy(dti->name, "lost+found"); 4707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dti->st.st_mode = S_IFDIR|0755; 4717aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dti->st.st_ctime = dti->st.st_mtime = time(NULL); 4727aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 4737aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4747aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Add root directory inode. This is iterated through for when finding 4757aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // blocks, but not when finding inodes. The tree's parent pointers don't 4767aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // point back into this. 4777aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4787aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dtb = xzalloc(sizeof(struct dirtree)+1); 4797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dtb->st.st_mode = S_IFDIR|0755; 4807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dtb->st.st_ctime = dtb->st.st_mtime = time(NULL); 4817aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dtb->child = dti; 4827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4837aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Figure out how much space is used by preset files 4847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley length = check_treesize(dtb, &(dtb->st.st_size)); 4857aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley check_treelinks(dtb); 4867aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4877aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Figure out how many total inodes we need. 4887aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4897aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.inodes) { 4907aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; 4917aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; 4927aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 4937aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 4947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // If we're generating a filesystem and have no idea how many blocks it 4957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // needs, start with a minimal guess, find the overhead of that many 4967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // groups, and loop until this is enough groups to store this many blocks. 4977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1; 4987aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley else TT.groups = div_round_up(TT.blocks, TT.blockbits); 4997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (;;) { 5017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.treeblocks; 5027aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5037aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (i = 0; i<TT.groups; i++) temp += group_overhead(i); 5047aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5057aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (TT.blocks) { 5067aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (TT.blocks < temp) error_exit("Not enough space.\n"); 5077aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley break; 5087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5097aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp <= TT.groups * TT.blockbits) { 5107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.blocks = temp; 5117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley break; 5127aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5137aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.groups++; 5147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.freeblocks = TT.blocks - temp; 5167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Now we know all the TT data, initialize superblock structure. 5187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley init_superblock(&TT.sb); 5207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Start writing. Skip the first 1k to avoid the boot sector (if any). 5227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley put_zeroes(1024); 5237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5247aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Loop through block groups, write out each one. 5257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dtiblk = dtbblk = usedblocks = usedinodes = 0; 5267aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (i=0; i<TT.groups; i++) { 5277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct ext2_inode *in = (struct ext2_inode *)toybuf; 5287aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley uint32_t start, itable, used, end; 5297aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int j, slot; 5307aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Where does this group end? 5327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley end = TT.blockbits; 5337aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if ((i+1)*TT.blockbits > TT.blocks) end = TT.blocks & (TT.blockbits-1); 5347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5357aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Blocks used by inode table 5367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; 5377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // If a superblock goes here, write it out. 5397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley start = group_superblock_overhead(i); 5407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (start) { 5417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley struct ext2_group *bg = (struct ext2_group *)toybuf; 5427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; 5437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley TT.sb.block_group_nr = SWAP_LE16(i); 5457aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write superblock and pad it up to block size 5477aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, &TT.sb, sizeof(struct ext2_superblock)); 5487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.blocksize - sizeof(struct ext2_superblock); 5497aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!i && TT.blocksize > 1024) temp -= 1024; 5507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(toybuf, 0, TT.blocksize); 5517aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, toybuf, temp); 5527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Loop through groups to write group descriptor table. 5547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for(j=0; j<TT.groups; j++) { 5557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5567aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Figure out what sector this group starts in. 5577aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used = group_superblock_overhead(j); 5587aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Find next array slot in this block (flush block if full). 5607aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley slot = j % (TT.blocksize/sizeof(struct ext2_group)); 5617aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!slot) { 5627aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (j) xwrite(TT.fsfd, bg, TT.blocksize); 5637aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(bg, 0, TT.blocksize); 5647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5657aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // How many free inodes in this group? 5677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.inodespg; 5687aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!i) temp -= INODES_RESERVED; 5697aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp > treeinodes) { 5707aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley treeinodes -= temp; 5717aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = 0; 5727aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else { 5737aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp -= treeinodes; 5747aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley treeinodes = 0; 5757aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5767aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].free_inodes_count = SWAP_LE16(temp); 5777aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5787aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // How many free blocks in this group? 5797aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2; 5807aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = end-used-temp; 5817aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp > treeblocks) { 5827aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley treeblocks -= temp; 5837aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = 0; 5847aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else { 5857aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp -= treeblocks; 5867aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley treeblocks = 0; 5877aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5887aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].free_blocks_count = SWAP_LE32(temp); 5897aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 5907aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Fill out rest of group structure 5917aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley used += j*TT.blockbits; 5927aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].block_bitmap = SWAP_LE32(used++); 5937aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].inode_bitmap = SWAP_LE32(used++); 5947aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].inode_table = SWAP_LE32(used); 5957aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bg[slot].used_dirs_count = 0; // (TODO) 5967aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5977aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, bg, TT.blocksize); 5987aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 5997aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6007aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Now write out stuff that every block group has. 6017aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6027aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write block usage bitmap 6037aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6047aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley start += 2 + itable; 6057aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(toybuf, 0, TT.blocksize); 6067aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bits_set(toybuf, 0, start); 6077aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bits_set(toybuf, end, TT.blockbits-end); 6087aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.treeblocks - usedblocks; 6097aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp) { 6107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (end-start > temp) temp = end-start; 6117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bits_set(toybuf, start, temp); 6127aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6137aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, toybuf, TT.blocksize); 6147aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write inode bitmap 6167aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(toybuf, 0, TT.blocksize); 6177aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley j = 0; 6187aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!i) bits_set(toybuf, 0, j = INODES_RESERVED); 6197aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bits_set(toybuf, TT.inodespg, slot = TT.blockbits-TT.inodespg); 6207aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley temp = TT.treeinodes - usedinodes; 6217aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (temp) { 6227aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (slot-j > temp) temp = slot-j; 6237aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley bits_set(toybuf, j, temp); 6247aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, toybuf, TT.blocksize); 6267aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write inode table for this group (TODO) 6287aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley for (j = 0; j<TT.inodespg; j++) { 6297aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley slot = j % (TT.blocksize/sizeof(struct ext2_inode)); 6307aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!slot) { 6317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (j) xwrite(TT.fsfd, in, TT.blocksize); 6327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley memset(in, 0, TT.blocksize); 6337aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (!i && j<INODES_RESERVED) { 6357aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write root inode 6367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (j == 2) fill_inode(in+slot, dtb); 6377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } else if (dti) { 6387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley fill_inode(in+slot, dti); 6397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley dti = treenext(dti); 6407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6417aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley xwrite(TT.fsfd, in, TT.blocksize); 6437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley 6447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley while (dtb) { 6457aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO write index data block 6467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO write root directory data block 6477aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO write directory data block 6487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // TODO write file data block 6497aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley put_zeroes(TT.blocksize); 6507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley start++; 6517aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley if (start == end) break; 6527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 6537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley // Write data blocks (TODO) 6547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley put_zeroes((end-start) * TT.blocksize); 6557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley } 656055cfcbe5b0534c700b30216f54336b7581f7be4Rob Landley} 657