Mercurial > hg > toybox
comparison toys/mke2fs.c @ 112:aadd28817955
Next iteration of mke2fs development.
author | Rob Landley <rob@landley.net> |
---|---|
date | Wed, 18 Apr 2007 21:39:46 -0400 |
parents | c5b6fb1fe3a4 |
children | 9cbb323f297f |
comparison
equal
deleted
inserted
replaced
111:a3b8838c3908 | 112:aadd28817955 |
---|---|
7 | 7 |
8 #include "toys.h" | 8 #include "toys.h" |
9 | 9 |
10 #define TT toy.mke2fs | 10 #define TT toy.mke2fs |
11 | 11 |
12 // b - block size (1024, 2048, 4096) | |
13 // F - force (run on mounted device or non-block device) | |
14 // i - bytes per inode | |
15 // N - number of inodes | |
16 // m - reserved blocks percentage | |
17 // n - Don't write | |
18 // q - quiet | |
19 | |
20 // L - volume label | |
21 // M - last mounted path | |
22 // o - creator os | |
23 | |
24 // j - create journal | |
25 // J - journal options (size=1024-102400 blocks,device=) | |
26 // device=/dev/blah or LABEL=label UUID=uuid | |
27 | |
28 // E - extended options (stride=stripe-size blocks) | |
29 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super | |
30 | |
31 #define INODES_RESERVED 10 | 12 #define INODES_RESERVED 10 |
32 | 13 |
14 static uint32_t div_round_up(uint32_t a, uint32_t b) | |
15 { | |
16 uint32_t c = a/b; | |
17 | |
18 if (a%b) c++; | |
19 return c; | |
20 } | |
21 | |
33 // Calculate data blocks plus index blocks needed to hold a file. | 22 // Calculate data blocks plus index blocks needed to hold a file. |
34 | 23 |
35 static uint32_t count_blocks_used(uint64_t size) | 24 static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist) |
36 { | 25 { |
37 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); | 26 uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize); |
38 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; | 27 uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0; |
28 | |
29 // Fill out index blocks. | |
30 | |
31 if (blocklist) { | |
32 int i; | |
33 | |
34 for (i=0; i<13 && i<dblocks; i++) blocklist[i] = i; | |
35 if (dblocks > 13+idx) blocklist[13] = 13+idx; | |
36 idx = 13 + idx + (idx*idx); | |
37 if (dblocks > idx) blocklist[14] = idx; | |
38 | |
39 return 0; | |
40 } | |
39 | 41 |
40 // Account for direct, singly, doubly, and triply indirect index blocks | 42 // Account for direct, singly, doubly, and triply indirect index blocks |
41 | 43 |
42 if (dblocks > 12) { | 44 if (dblocks > 12) { |
43 iblocks = ((dblocks-13)/idx)+1; | 45 iblocks = ((dblocks-13)/idx)+1; |
49 } | 51 } |
50 | 52 |
51 return dblocks + iblocks + diblocks + tiblocks; | 53 return dblocks + iblocks + diblocks + tiblocks; |
52 } | 54 } |
53 | 55 |
54 // Calculate the number of blocks used by each inode. Returns blocks used, | 56 // Use the parent pointer to iterate through the tree non-recursively. |
55 // assigns bytes used to *size. Writes total block count to TT.treeblocks | 57 static struct dirtree *treenext(struct dirtree *this) |
56 // and inode count to TT.treeinodes. | 58 { |
59 while (this && !this->next) this = this->parent; | |
60 if (this) this = this->next; | |
61 | |
62 return this; | |
63 } | |
64 | |
65 // Recursively calculate the number of blocks used by each inode in the tree. | |
66 // Returns blocks used by this directory, assigns bytes used to *size. | |
67 // Writes total block count to TT.treeblocks and inode count to TT.treeinodes. | |
57 | 68 |
58 static long check_treesize(struct dirtree *this, off_t *size) | 69 static long check_treesize(struct dirtree *this, off_t *size) |
59 { | 70 { |
60 long blocks; | 71 long blocks; |
61 | 72 |
63 *size += sizeof(struct ext2_dentry) + strlen(this->name); | 74 *size += sizeof(struct ext2_dentry) + strlen(this->name); |
64 | 75 |
65 if (this->child) | 76 if (this->child) |
66 this->st.st_blocks = check_treesize(this->child, &this->st.st_size); | 77 this->st.st_blocks = check_treesize(this->child, &this->st.st_size); |
67 else if (S_ISREG(this->st.st_mode)) { | 78 else if (S_ISREG(this->st.st_mode)) { |
68 this->st.st_blocks = count_blocks_used(this->st.st_size); | 79 this->st.st_blocks = file_blocks_used(this->st.st_size, 0); |
69 TT.treeblocks += this->st.st_blocks; | 80 TT.treeblocks += this->st.st_blocks; |
70 } | 81 } |
71 this = this->next; | 82 this = this->next; |
72 } | 83 } |
73 TT.treeblocks += blocks = count_blocks_used(*size); | 84 TT.treeblocks += blocks = file_blocks_used(*size, 0); |
74 TT.treeinodes++; | 85 TT.treeinodes++; |
75 | 86 |
76 return blocks; | 87 return blocks; |
77 } | 88 } |
78 | 89 |
79 // Use the parent pointer to iterate through the tree non-recursively. | 90 // Calculate inode numbers and link counts. |
80 static struct dirtree *treenext(struct dirtree *this) | 91 // |
81 { | |
82 while (this && !this->next) this = this->parent; | |
83 if (this) this = this->next; | |
84 | |
85 return this; | |
86 } | |
87 | |
88 // To do this right I need to copy the tree and sort it, but here's a really | 92 // To do this right I need to copy the tree and sort it, but here's a really |
89 // ugly n^2 way of dealing with the problem that doesn't scale well to large | 93 // ugly n^2 way of dealing with the problem that doesn't scale well to large |
90 // numbers of files but can be done in very little code. | 94 // numbers of files (> 100,000) but can be done in very little code. |
91 | 95 // This rewrites inode numbers to their final values, allocating depth first. |
92 static void check_treelinks(void) | 96 |
93 { | 97 static void check_treelinks(struct dirtree *tree) |
94 struct dirtree *this, *that; | 98 { |
95 | 99 struct dirtree *this=tree, *that; |
96 for (this = TT.dt; this; this = treenext(this)) { | 100 long inode = INODES_RESERVED; |
101 | |
102 while (this) { | |
103 ++inode; | |
97 // Since we can't hardlink to directories, we know their link count. | 104 // Since we can't hardlink to directories, we know their link count. |
98 if (S_ISDIR(this->st.st_mode)) this->st.st_nlink = 2; | 105 if (S_ISDIR(this->st.st_mode)) this->st.st_nlink = 2; |
99 else { | 106 else { |
107 dev_t new = this->st.st_dev; | |
108 | |
109 if (!new) continue; | |
110 | |
100 this->st.st_nlink = 0; | 111 this->st.st_nlink = 0; |
101 for (that = TT.dt; that; that = treenext(that)) | 112 for (that = tree; that; that = treenext(that)) { |
102 if (this->st.st_ino == that->st.st_ino) | 113 if (this->st.st_ino == that->st.st_ino && |
103 if (this->st.st_dev == that->st.st_dev) | 114 this->st.st_dev == that->st.st_dev) |
104 this->st.st_nlink++; | 115 { |
105 } | 116 this->st.st_nlink++; |
117 this->st.st_ino = inode; | |
118 } | |
119 } | |
120 } | |
121 this->st.st_ino = inode; | |
122 this = treenext(this); | |
106 } | 123 } |
107 } | 124 } |
108 | 125 |
109 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm | 126 // According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm |
110 // we should generate a uuid structure by reading a clock with 100 nanosecond | 127 // we should generate a uuid structure by reading a clock with 100 nanosecond |
112 // and looking up our eth0 mac address. | 129 // and looking up our eth0 mac address. |
113 // | 130 // |
114 // On the other hand, we have 128 bits to come up with a unique identifier, of | 131 // On the other hand, we have 128 bits to come up with a unique identifier, of |
115 // which 6 have a defined value. /dev/urandom it is. | 132 // which 6 have a defined value. /dev/urandom it is. |
116 | 133 |
117 static void create_uuid(char *uuid) | 134 static void fake_uuid(char *uuid) |
118 { | 135 { |
119 // Read 128 random bits | 136 // Read 128 random bits |
120 int fd = xopen("/dev/urandom", O_RDONLY); | 137 int fd = xopen("/dev/urandom", O_RDONLY); |
121 xreadall(fd, uuid, 16); | 138 xreadall(fd, uuid, 16); |
122 close(fd); | 139 close(fd); |
129 // set bit 1 of the node ID, which is the mac multicast bit. This means we | 146 // set bit 1 of the node ID, which is the mac multicast bit. This means we |
130 // should never collide with anybody actually using a macaddr. | 147 // should never collide with anybody actually using a macaddr. |
131 uuid[11] = uuid[11] | 128; | 148 uuid[11] = uuid[11] | 128; |
132 } | 149 } |
133 | 150 |
134 // Figure out inodes per group, rounded up to fill complete inode blocks. | 151 // Calculate inodes per group from total inodes. |
135 static uint32_t get_inodespg(uint32_t inodes) | 152 static uint32_t get_inodespg(uint32_t inodes) |
136 { | 153 { |
137 uint32_t temp; | 154 uint32_t temp; |
138 | 155 |
156 // Round up to fill complete inode blocks. | |
139 temp = (inodes + TT.groups - 1) / TT.groups; | 157 temp = (inodes + TT.groups - 1) / TT.groups; |
140 inodes = TT.blocksize/sizeof(struct ext2_inode); | 158 inodes = TT.blocksize/sizeof(struct ext2_inode); |
141 return ((temp + inodes - 1)/inodes)*inodes; | 159 return ((temp + inodes - 1)/inodes)*inodes; |
142 } | 160 } |
143 | 161 |
144 // Fill out superblock and TT | 162 // Fill out superblock and TT structures. |
145 | 163 |
146 static void init_superblock(struct ext2_superblock *sb) | 164 static void init_superblock(struct ext2_superblock *sb) |
147 { | 165 { |
148 uint32_t temp; | 166 uint32_t temp; |
149 | 167 |
154 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp); | 172 sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp); |
155 | 173 |
156 // Fill out blocks_count, r_blocks_count, first_data_block | 174 // Fill out blocks_count, r_blocks_count, first_data_block |
157 | 175 |
158 sb->blocks_count = SWAP_LE32(TT.blocks); | 176 sb->blocks_count = SWAP_LE32(TT.blocks); |
177 sb->free_blocks_count = SWAP_LE32(TT.freeblocks); | |
159 temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; | 178 temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100; |
160 sb->r_blocks_count = SWAP_LE32(temp); | 179 sb->r_blocks_count = SWAP_LE32(temp); |
161 | 180 |
162 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); | 181 sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0); |
163 | 182 |
164 // Set blocks_per_group and frags_per_group, which is the size of an | 183 // Set blocks_per_group and frags_per_group, which is the size of an |
165 // allocation bitmap that fits in one block (I.E. how many bits per block)? | 184 // allocation bitmap that fits in one block (I.E. how many bits per block)? |
166 | 185 |
167 sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); | 186 sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits); |
168 | |
169 // How many block groups do we need? (Round up avoiding integer overflow.) | |
170 | |
171 TT.groups = (TT.blocks)/TT.blockbits; | |
172 if (TT.blocks & (TT.blockbits-1)) TT.groups++; | |
173 | |
174 // Figure out inodes per group, rounded up to block size. | |
175 | |
176 TT.inodespg = get_inodespg(TT.inodespg); | |
177 | 187 |
178 // Set inodes_per_group and total inodes_count | 188 // Set inodes_per_group and total inodes_count |
179 sb->inodes_per_group = SWAP_LE32(TT.inodespg); | 189 sb->inodes_per_group = SWAP_LE32(TT.inodespg); |
180 sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); | 190 sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups); |
191 | |
192 // Determine free inodes. | |
193 temp = TT.inodespg*TT.groups - INODES_RESERVED; | |
194 if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); | |
195 sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes); | |
181 | 196 |
182 // Fill out the rest of the superblock. | 197 // Fill out the rest of the superblock. |
183 sb->max_mnt_count=0xFFFF; | 198 sb->max_mnt_count=0xFFFF; |
184 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); | 199 sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL)); |
185 sb->magic = SWAP_LE32(0xEF53); | 200 sb->magic = SWAP_LE32(0xEF53); |
189 sb->first_ino = SWAP_LE32(INODES_RESERVED+1); | 204 sb->first_ino = SWAP_LE32(INODES_RESERVED+1); |
190 sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); | 205 sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode)); |
191 sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); | 206 sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE); |
192 sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); | 207 sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER); |
193 | 208 |
194 create_uuid(sb->uuid); | 209 fake_uuid(sb->uuid); |
195 | 210 |
196 // TODO If we're called as mke3fs or mkfs.ext3, do a journal. | 211 // TODO If we're called as mke3fs or mkfs.ext3, do a journal. |
197 | 212 |
198 //if (strchr(toys.which->name,'3')) | 213 //if (strchr(toys.which->name,'3')) |
199 // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); | 214 // sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL); |
200 } | 215 } |
213 } | 228 } |
214 return 0; | 229 return 0; |
215 } | 230 } |
216 | 231 |
217 | 232 |
218 // Number of blocks used in this group by superblock/group list backup. | 233 // Number of blocks used in group by optional superblock/group list backup. |
219 static int group_superblock_used(uint32_t group) | 234 static int group_superblock_overhead(uint32_t group) |
220 { | 235 { |
221 int used; | 236 int used; |
222 | 237 |
223 if (!is_sb_group(group)) return 0; | 238 if (!is_sb_group(group)) return 0; |
224 | 239 |
225 // How blocks does the group table take up? | 240 // How many blocks does the group descriptor table take up? |
226 used = TT.groups * sizeof(struct ext2_group); | 241 used = TT.groups * sizeof(struct ext2_group); |
227 used += TT.blocksize - 1; | 242 used += TT.blocksize - 1; |
228 used /= TT.blocksize; | 243 used /= TT.blocksize; |
229 // Plus the superblock itself. | 244 // Plus the superblock itself. |
230 used++; | 245 used++; |
232 if (!group && TT.blocksize == 1024) used++; | 247 if (!group && TT.blocksize == 1024) used++; |
233 | 248 |
234 return used; | 249 return used; |
235 } | 250 } |
236 | 251 |
237 static uint32_t get_all_group_blocks(void) | 252 // Number of blocks used in group to store superblock/group/inode list |
238 { | 253 static int group_overhead(uint32_t group) |
239 uint32_t i, blocks, inodeblks; | 254 { |
240 | 255 // Return superblock backup overhead (if any), plus block/inode |
241 inodeblks = get_inodespg(TT.inodespg); | 256 // allocation bitmaps, plus inode tables. |
242 inodeblks /= TT.blocksize/sizeof(struct ext2_inode); | 257 return group_superblock_overhead(group) + 2 + get_inodespg(TT.inodespg) |
243 for (i = blocks = 0; i<TT.groups; i++) | 258 / (TT.blocksize/sizeof(struct ext2_inode)); |
244 blocks += group_superblock_used(i) + 2 + inodeblks; | 259 } |
245 | 260 |
246 return blocks; | 261 // In bitmap "array" set "len" bits starting at position "start" (from 0). |
247 } | |
248 | |
249 static void bits_set(char *array, int start, int len) | 262 static void bits_set(char *array, int start, int len) |
250 { | 263 { |
251 while(len) { | 264 while(len) { |
252 if ((start&7) || len<8) { | 265 if ((start&7) || len<8) { |
253 array[start/8]|=(1<<(start&7)); | 266 array[start/8]|=(1<<(start&7)); |
263 | 276 |
264 // Seek past len bytes (to maintain sparse file), or write zeroes if output | 277 // Seek past len bytes (to maintain sparse file), or write zeroes if output |
265 // not seekable | 278 // not seekable |
266 static void put_zeroes(int len) | 279 static void put_zeroes(int len) |
267 { | 280 { |
268 if(TT.noseek || -1 == lseek(TT.fsfd, len, SEEK_SET)) { | 281 if(-1 == lseek(TT.fsfd, len, SEEK_SET)) { |
269 | |
270 TT.noseek=1; | |
271 memset(toybuf, 0, sizeof(toybuf)); | 282 memset(toybuf, 0, sizeof(toybuf)); |
272 while (len) { | 283 while (len) { |
273 int out = len > sizeof(toybuf) ? sizeof(toybuf) : len; | 284 int out = len > sizeof(toybuf) ? sizeof(toybuf) : len; |
274 xwrite(TT.fsfd, toybuf, out); | 285 xwrite(TT.fsfd, toybuf, out); |
275 len -= out; | 286 len -= out; |
276 } | 287 } |
277 } | 288 } |
278 } | 289 } |
279 | 290 |
291 // Fill out an inode structure from struct stat info in dirtree. | |
280 static void fill_inode(struct ext2_inode *in, struct dirtree *this) | 292 static void fill_inode(struct ext2_inode *in, struct dirtree *this) |
281 { | 293 { |
282 memset(in,0,sizeof(struct ext2_inode)); | 294 uint32_t fbu[15]; |
283 | 295 int temp; |
284 // This works on Linux. S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) | 296 |
285 in->mode = this->st.st_mode; | 297 file_blocks_used(this->st.st_size, fbu); |
286 | 298 |
287 in->uid = this->st.st_uid & 0xFFFF; | 299 // If this inode needs data blocks allocated to it. |
288 in->uid_high = this->st.st_uid >> 16; | 300 if (this->st.st_size) { |
289 in->gid = this->st.st_gid & 0xFFFF; | 301 int i, group = TT.nextblock/TT.blockbits; |
290 in->gid_high = this->st.st_gid >> 16; | 302 |
291 in->size = this->st.st_size & 0xFFFFFFFF; | 303 // TODO: teach this about indirect blocks. |
292 | 304 for (i=0; i<15; i++) { |
293 in->atime = this->st.st_atime; | 305 // If we just jumped into a new group, skip group overhead blocks. |
294 in->ctime = this->st.st_ctime; | 306 while (group >= TT.nextgroup) |
295 in->mtime = this->st.st_mtime; | 307 TT.nextblock += group_overhead(TT.nextgroup++); |
296 | 308 } |
297 in->links_count = this->st.st_nlink; | 309 } |
298 in->blocks = this->st.st_blocks; | 310 // TODO : S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m) |
311 in->mode = SWAP_LE32(this->st.st_mode); | |
312 | |
313 in->uid = SWAP_LE16(this->st.st_uid & 0xFFFF); | |
314 in->uid_high = SWAP_LE16(this->st.st_uid >> 16); | |
315 in->gid = SWAP_LE16(this->st.st_gid & 0xFFFF); | |
316 in->gid_high = SWAP_LE16(this->st.st_gid >> 16); | |
317 in->size = SWAP_LE32(this->st.st_size & 0xFFFFFFFF); | |
318 | |
319 // Contortions to make the compiler not generate a warning for x>>32 | |
320 // when x is 32 bits. The optimizer should clean this up. | |
321 if (sizeof(this->st.st_size) > 4) temp = 32; | |
322 else temp = 0; | |
323 if (temp) in->dir_acl = SWAP_LE32(this->st.st_size >> temp); | |
324 | |
325 in->atime = SWAP_LE32(this->st.st_atime); | |
326 in->ctime = SWAP_LE32(this->st.st_ctime); | |
327 in->mtime = SWAP_LE32(this->st.st_mtime); | |
328 | |
329 in->links_count = SWAP_LE16(this->st.st_nlink); | |
330 in->blocks = SWAP_LE32(this->st.st_blocks); | |
331 // in->faddr | |
299 } | 332 } |
300 | 333 |
301 int mke2fs_main(void) | 334 int mke2fs_main(void) |
302 { | 335 { |
303 int i, temp; | 336 int i, temp; |
304 off_t length; | 337 off_t length; |
305 uint32_t usedblocks, usedinodes; | 338 uint32_t usedblocks, usedinodes, dtiblk, dtbblk; |
306 | 339 struct dirtree *dti, *dtb; |
340 | |
307 // Handle command line arguments. | 341 // Handle command line arguments. |
308 | 342 |
309 if (toys.optargs[1]) { | 343 if (toys.optargs[1]) { |
310 sscanf(toys.optargs[1], "%u", &TT.blocks); | 344 sscanf(toys.optargs[1], "%u", &TT.blocks); |
311 temp = O_RDWR|O_CREAT; | 345 temp = O_RDWR|O_CREAT; |
323 length = fdlength(TT.fsfd); | 357 length = fdlength(TT.fsfd); |
324 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; | 358 if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096; |
325 TT.blockbits = 8*TT.blocksize; | 359 TT.blockbits = 8*TT.blocksize; |
326 if (!TT.blocks) TT.blocks = length/TT.blocksize; | 360 if (!TT.blocks) TT.blocks = length/TT.blocksize; |
327 | 361 |
328 // Figure out how many total inodes we need. | |
329 | |
330 if (!TT.inodespg) { | |
331 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; | |
332 TT.inodespg = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; | |
333 } | |
334 | |
335 // Collect gene2fs list or lost+found, calculate requirements. | 362 // Collect gene2fs list or lost+found, calculate requirements. |
336 | 363 |
337 if (TT.gendir) { | 364 if (TT.gendir) { |
338 strncpy(toybuf, TT.gendir, sizeof(toybuf)); | 365 strncpy(toybuf, TT.gendir, sizeof(toybuf)); |
339 TT.dt = read_dirtree(toybuf, NULL); | 366 dti = read_dirtree(toybuf, NULL); |
340 } else { | 367 } else { |
341 TT.dt = xzalloc(sizeof(struct dirtree)+11); | 368 dti = xzalloc(sizeof(struct dirtree)+11); |
342 strcpy(TT.dt->name, "lost+found"); | 369 strcpy(dti->name, "lost+found"); |
343 TT.dt->st.st_mode = S_IFDIR|0755; | 370 dti->st.st_mode = S_IFDIR|0755; |
344 TT.dt->st.st_ctime = TT.dt->st.st_mtime = time(NULL); | 371 dti->st.st_ctime = dti->st.st_mtime = time(NULL); |
345 } | 372 } |
346 | 373 |
374 // Add root directory inode. This is iterated through for when finding | |
375 // blocks, but not when finding inodes. The tree's parent pointers don't | |
376 // point back into this. | |
377 | |
378 dtb = xzalloc(sizeof(struct dirtree)+1); | |
379 dtb->st.st_mode = S_IFDIR|0755; | |
380 dtb->st.st_ctime = dtb->st.st_mtime = time(NULL); | |
381 dtb->child = dti; | |
382 | |
347 // Figure out how much space is used by preset files | 383 // Figure out how much space is used by preset files |
348 length = 0; | 384 length = check_treesize(dtb, &(dtb->st.st_size)); |
349 length = check_treesize(TT.dt, &length); | 385 check_treelinks(dtb); |
350 check_treelinks(); // Calculate st_nlink for each node in tree. | 386 |
351 | 387 // Figure out how many total inodes we need. |
352 if (TT.gendir && !TT.blocks) { | 388 |
353 // Figure out how many blocks of overhead superblock backups and | 389 if (!TT.inodes) { |
354 // group descriptor tables impose. Start with a minimal guess, | 390 if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192; |
355 // find the overhead for that many groups, and loop until this | 391 TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode; |
356 // is enough groups to store this many blocks. | 392 } |
357 TT.groups = (TT.treeblocks/TT.blockbits)+1; | 393 |
358 for (;;) { | 394 // If we're generating a filesystem and have no idea how many blocks it |
359 TT.blocks = TT.treeblocks + get_all_group_blocks(); | 395 // needs, start with a minimal guess, find the overhead of that many |
360 if (TT.blocks <= TT.groups * TT.blockbits) break; | 396 // groups, and loop until this is enough groups to store this many blocks. |
361 TT.groups++; | 397 if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1; |
362 } | 398 else TT.groups = div_round_up(TT.blocks, TT.blockbits); |
363 } | 399 |
364 | 400 for (;;) { |
365 // TT.blocks is now big enough to initialize superblock structure | 401 temp = TT.treeblocks; |
402 | |
403 for (i = 0; i<TT.groups; i++) temp += group_overhead(i); | |
404 | |
405 if (TT.blocks) { | |
406 if (TT.blocks < temp) error_exit("Not enough space.\n"); | |
407 break; | |
408 } | |
409 if (temp <= TT.groups * TT.blockbits) { | |
410 TT.blocks = temp; | |
411 break; | |
412 } | |
413 TT.groups++; | |
414 } | |
415 TT.freeblocks = TT.blocks - temp; | |
416 | |
417 // Now we know all the TT data, initialize superblock structure. | |
366 | 418 |
367 init_superblock(&TT.sb); | 419 init_superblock(&TT.sb); |
368 temp = get_all_group_blocks(); | 420 |
369 if (TT.blocks < TT.treeblocks + temp) error_exit("Not enough space.\n"); | 421 // Start writing. Skip the first 1k to avoid the boot sector (if any). |
370 TT.sb.free_blocks_count = SWAP_LE32(TT.blocks - TT.treeblocks - temp); | |
371 | |
372 temp = TT.inodespg*TT.groups - INODES_RESERVED; | |
373 if (temp < TT.treeinodes) error_exit("Not enough inodes.\n"); | |
374 TT.sb.free_inodes_count = SWAP_LE32(temp - TT.treeinodes); | |
375 | |
376 // Skip the first 1k to avoid the boot sector (if any) | |
377 put_zeroes(1024); | 422 put_zeroes(1024); |
378 | 423 |
379 // Loop through block groups, write out each one. | 424 // Loop through block groups, write out each one. |
380 usedblocks = 0; | 425 dtiblk = dtbblk = usedblocks = usedinodes = 0; |
381 usedinodes = 0; | |
382 for (i=0; i<TT.groups; i++) { | 426 for (i=0; i<TT.groups; i++) { |
383 struct ext2_inode *in = (struct ext2_inode *)toybuf; | 427 struct ext2_inode *in = (struct ext2_inode *)toybuf; |
384 uint32_t start, itable, used, end; | 428 uint32_t start, itable, used, end; |
385 int j, slot; | 429 int j, slot; |
386 | 430 |
390 | 434 |
391 // Blocks used by inode table | 435 // Blocks used by inode table |
392 itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; | 436 itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize; |
393 | 437 |
394 // If a superblock goes here, write it out. | 438 // If a superblock goes here, write it out. |
395 start = group_superblock_used(i); | 439 start = group_superblock_overhead(i); |
396 if (start) { | 440 if (start) { |
397 struct ext2_group *bg = (struct ext2_group *)toybuf; | 441 struct ext2_group *bg = (struct ext2_group *)toybuf; |
398 int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; | 442 int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes; |
399 | 443 |
400 TT.sb.block_group_nr = SWAP_LE16(i); | 444 TT.sb.block_group_nr = SWAP_LE16(i); |
408 | 452 |
409 // Loop through groups to write group descriptor table. | 453 // Loop through groups to write group descriptor table. |
410 for(j=0; j<TT.groups; j++) { | 454 for(j=0; j<TT.groups; j++) { |
411 | 455 |
412 // Figure out what sector this group starts in. | 456 // Figure out what sector this group starts in. |
413 used = group_superblock_used(j); | 457 used = group_superblock_overhead(j); |
414 | 458 |
415 // Find next array slot in this block (flush block if full). | 459 // Find next array slot in this block (flush block if full). |
416 slot = j % (TT.blocksize/sizeof(struct ext2_group)); | 460 slot = j % (TT.blocksize/sizeof(struct ext2_group)); |
417 if (!slot) { | 461 if (!slot) { |
418 if (j) xwrite(TT.fsfd, bg, TT.blocksize); | 462 if (j) xwrite(TT.fsfd, bg, TT.blocksize); |
485 slot = j % (TT.blocksize/sizeof(struct ext2_inode)); | 529 slot = j % (TT.blocksize/sizeof(struct ext2_inode)); |
486 if (!slot) { | 530 if (!slot) { |
487 if (j) xwrite(TT.fsfd, in, TT.blocksize); | 531 if (j) xwrite(TT.fsfd, in, TT.blocksize); |
488 memset(in, 0, TT.blocksize); | 532 memset(in, 0, TT.blocksize); |
489 } | 533 } |
534 if (!i && j<INODES_RESERVED) { | |
535 // Write root inode | |
536 if (j == 2) fill_inode(in+slot, dtb); | |
537 } else if (dti) { | |
538 fill_inode(in+slot, dti); | |
539 dti = treenext(dti); | |
540 } | |
490 } | 541 } |
491 xwrite(TT.fsfd, in, TT.blocksize); | 542 xwrite(TT.fsfd, in, TT.blocksize); |
492 | 543 |
493 // Write empty data blocks | 544 while (dtb) { |
545 // TODO write index data block | |
546 // TODO write root directory data block | |
547 // TODO write directory data block | |
548 // TODO write file data block | |
549 put_zeroes(TT.blocksize); | |
550 start++; | |
551 if (start == end) break; | |
552 } | |
553 // Write data blocks (TODO) | |
494 put_zeroes((end-start) * TT.blocksize); | 554 put_zeroes((end-start) * TT.blocksize); |
495 } | 555 } |
496 | 556 |
497 return 0; | 557 return 0; |
498 } | 558 } |
559 | |
560 // Scratch pad: | |
561 // b - block size (1024, 2048, 4096) | |
562 // F - force (run on mounted device or non-block device) | |
563 // i - bytes per inode | |
564 // N - number of inodes | |
565 // m - reserved blocks percentage | |
566 // n - Don't write | |
567 // q - quiet | |
568 | |
569 // L - volume label | |
570 // M - last mounted path | |
571 // o - creator os | |
572 | |
573 // j - create journal | |
574 // J - journal options (size=1024-102400 blocks,device=) | |
575 // device=/dev/blah or LABEL=label UUID=uuid | |
576 | |
577 // E - extended options (stride=stripe-size blocks) | |
578 // O - none,dir_index,filetype,has_journal,journal_dev,sparse_super | |
579 | |
580 |