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