File: | src/sbin/newfs_ext2fs/mke2fs.c |
Warning: | line 325, column 30 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: mke2fs.c,v 1.18 2019/07/01 07:17:26 kevlo Exp $ */ | |||
2 | /* $NetBSD: mke2fs.c,v 1.13 2009/10/19 18:41:08 bouyer Exp $ */ | |||
3 | ||||
4 | /*- | |||
5 | * Copyright (c) 2007 Izumi Tsutsui. All rights reserved. | |||
6 | * | |||
7 | * Redistribution and use in source and binary forms, with or without | |||
8 | * modification, are permitted provided that the following conditions | |||
9 | * are met: | |||
10 | * 1. Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer in the | |||
14 | * documentation and/or other materials provided with the distribution. | |||
15 | * | |||
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
26 | */ | |||
27 | ||||
28 | /* | |||
29 | * Copyright (c) 1980, 1989, 1993 | |||
30 | * The Regents of the University of California. All rights reserved. | |||
31 | * | |||
32 | * Redistribution and use in source and binary forms, with or without | |||
33 | * modification, are permitted provided that the following conditions | |||
34 | * are met: | |||
35 | * 1. Redistributions of source code must retain the above copyright | |||
36 | * notice, this list of conditions and the following disclaimer. | |||
37 | * 2. Redistributions in binary form must reproduce the above copyright | |||
38 | * notice, this list of conditions and the following disclaimer in the | |||
39 | * documentation and/or other materials provided with the distribution. | |||
40 | * 3. Neither the name of the University nor the names of its contributors | |||
41 | * may be used to endorse or promote products derived from this software | |||
42 | * without specific prior written permission. | |||
43 | * | |||
44 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
54 | * SUCH DAMAGE. | |||
55 | */ | |||
56 | ||||
57 | /* | |||
58 | * Copyright (c) 1997 Manuel Bouyer. | |||
59 | * | |||
60 | * Redistribution and use in source and binary forms, with or without | |||
61 | * modification, are permitted provided that the following conditions | |||
62 | * are met: | |||
63 | * 1. Redistributions of source code must retain the above copyright | |||
64 | * notice, this list of conditions and the following disclaimer. | |||
65 | * 2. Redistributions in binary form must reproduce the above copyright | |||
66 | * notice, this list of conditions and the following disclaimer in the | |||
67 | * documentation and/or other materials provided with the distribution. | |||
68 | * | |||
69 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
70 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
71 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
72 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
73 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
74 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
75 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
76 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
77 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
78 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
79 | */ | |||
80 | ||||
81 | /* | |||
82 | * mke2fs.c: "re-invent (dumb but non-GPLed) wheel as a fun project" | |||
83 | * | |||
84 | * In spite of this name, there is no piece of code | |||
85 | * derived from GPLed e2fsprogs written for Linux. | |||
86 | * I referred them only to see how each structure | |||
87 | * member should be initialized. | |||
88 | * | |||
89 | * Reference: | |||
90 | * - All NetBSD sources under src/sys/ufs/ext2fs and src/sbin/fsck_ext2fs | |||
91 | * - Ext2fs Home Page | |||
92 | * http://e2fsprogs.sourceforge.net/ext2.html | |||
93 | * - Design and Implementation of the Second Extended Filesystem | |||
94 | * http://e2fsprogs.sourceforge.net/ext2intro.html | |||
95 | * - Linux Documentation "The Second Extended Filesystem" | |||
96 | * src/linux/Documentation/filesystems/ext2.txt | |||
97 | * in the Linux kernel distribution | |||
98 | */ | |||
99 | ||||
100 | #include <sys/param.h> /* MAXBSIZE powerof2 roundup setbit isset MIN */ | |||
101 | #include <sys/types.h> | |||
102 | #include <sys/mman.h> | |||
103 | #include <sys/time.h> | |||
104 | #include <ufs/ext2fs/ext2fs_dinode.h> | |||
105 | #include <ufs/ext2fs/ext2fs_dir.h> | |||
106 | #include <ufs/ext2fs/ext2fs.h> | |||
107 | #include <sys/ioctl.h> | |||
108 | ||||
109 | #include <err.h> | |||
110 | #include <errno(*__errno()).h> | |||
111 | #include <inttypes.h> | |||
112 | #include <string.h> | |||
113 | #include <unistd.h> | |||
114 | #include <stdint.h> | |||
115 | #include <stdlib.h> | |||
116 | #include <stddef.h> | |||
117 | #include <stdio.h> | |||
118 | ||||
119 | #include "extern.h" | |||
120 | ||||
121 | static void initcg(uint); | |||
122 | static void zap_old_sblock(daddr32_t); | |||
123 | static uint cgoverhead(uint); | |||
124 | static int fsinit(const struct timeval *); | |||
125 | static int makedir(struct ext2fs_direct *, int); | |||
126 | static void copy_dir(struct ext2fs_direct *, struct ext2fs_direct *); | |||
127 | static void init_resizeino(const struct timeval *); | |||
128 | static uint32_t alloc(uint32_t, uint16_t); | |||
129 | static void iput(struct ext2fs_dinode *, ino_t); | |||
130 | static void rdfs(daddr32_t, int, void *); | |||
131 | static void wtfs(daddr32_t, int, void *); | |||
132 | static int ilog2(uint); | |||
133 | static int skpc(int, size_t, uint8_t *); | |||
134 | static void uuid_get(struct m_ext2fs *); | |||
135 | ||||
136 | /* XXX: some of these macro should be into <ufs/ext2fs/ext2fs.h>? */ | |||
137 | #define EXT2_DEF_MAX_MNT_COUNT20 20 | |||
138 | #define EXT2_DEF_FSCKINTV(180 * 24 * 60 * 60) (180 * 24 * 60 * 60) /* 180 days */ | |||
139 | #define EXT2_RESERVED_INODES(((ufsino_t)11) - 1) (EXT2_FIRSTINO((ufsino_t)11) - 1) | |||
140 | #define EXT2_UMASK0755 0755 | |||
141 | ||||
142 | #define EXT2_INO_INDEX(ino)((ino) - 1) ((ino) - 1) /* no inode zero */ | |||
143 | ||||
144 | #define EXT2_LOSTFOUNDSIZE16384 16384 | |||
145 | #define EXT2_LOSTFOUNDINO((ufsino_t)11) EXT2_FIRSTINO((ufsino_t)11) /* XXX: not quite */ | |||
146 | #define EXT2_LOSTFOUNDUMASK0700 0700 | |||
147 | ||||
148 | #define EXT2_RESIZEINOUMASK0600 0600 | |||
149 | ||||
150 | #define NBLOCK_SUPERBLOCK1 1 | |||
151 | #define NBLOCK_BLOCK_BITMAP1 1 | |||
152 | #define NBLOCK_INODE_BITMAP1 1 | |||
153 | ||||
154 | #define cgbase(fs, c)((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * ( c)) \ | |||
155 | ((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * (c)) | |||
156 | ||||
157 | #define rounddown(x,y)(((x)/(y))*(y)) (((x)/(y))*(y)) | |||
158 | ||||
159 | /* | |||
160 | * ext2fs super block and group descriptor structures | |||
161 | * | |||
162 | * We don't have to use or setup whole in-memory m_ext2fs structure, | |||
163 | * but prepare it to use several macro defined in kernel headers. | |||
164 | */ | |||
165 | union { | |||
166 | struct m_ext2fs m_ext2fs; | |||
167 | char pad[SBSIZE1024]; | |||
168 | } ext2fsun; | |||
169 | #define sblockext2fsun.m_ext2fs ext2fsun.m_ext2fs | |||
170 | #define gdext2fsun.m_ext2fs.e2fs_gd ext2fsun.m_ext2fs.e2fs_gd | |||
171 | ||||
172 | static uint8_t *iobuf; /* for superblock and group descriptors */ | |||
173 | static int iobufsize; | |||
174 | ||||
175 | static uint8_t buf[MAXBSIZE(64 * 1024)]; /* for initcg() and makedir() ops */ | |||
176 | ||||
177 | static int fd; | |||
178 | ||||
179 | extern int max_cols; | |||
180 | ||||
181 | void | |||
182 | mke2fs(const char *fsys, int f) | |||
183 | { | |||
184 | struct timeval tv; | |||
185 | int64_t minfssize; | |||
186 | uint bcount, fbcount, ficount; | |||
187 | uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg; | |||
188 | uint minblocks_per_cg, blocks_lastcg; | |||
189 | uint ncg, cylno, sboff; | |||
190 | int i, len, col, delta, fld_width; | |||
191 | ||||
192 | gettimeofday(&tv, NULL((void*)0)); | |||
193 | fd = f; | |||
194 | ||||
195 | /* | |||
196 | * collect and verify the block and fragment sizes | |||
197 | */ | |||
198 | if (!powerof2(bsize)((((bsize)-1)&(bsize))==0)) { | |||
| ||||
199 | errx(EXIT_FAILURE1, | |||
200 | "block size must be a power of 2, not %u\n", | |||
201 | bsize); | |||
202 | } | |||
203 | if (!powerof2(fsize)((((fsize)-1)&(fsize))==0)) { | |||
204 | errx(EXIT_FAILURE1, | |||
205 | "fragment size must be a power of 2, not %u\n", | |||
206 | fsize); | |||
207 | } | |||
208 | if (fsize < sectorsize) { | |||
209 | errx(EXIT_FAILURE1, | |||
210 | "fragment size %u is too small, minimum is %u\n", | |||
211 | fsize, sectorsize); | |||
212 | } | |||
213 | if (bsize < MINBSIZE(1 << 10)) { | |||
214 | errx(EXIT_FAILURE1, | |||
215 | "block size %u is too small, minimum is %u\n", | |||
216 | bsize, MINBSIZE(1 << 10)); | |||
217 | } | |||
218 | if (bsize > EXT2_MAXBSIZE(1 << 12)) { | |||
219 | errx(EXIT_FAILURE1, | |||
220 | "block size %u is too large, maximum is %u\n", | |||
221 | bsize, MAXBSIZE(64 * 1024)); | |||
222 | } | |||
223 | if (bsize != fsize) { | |||
224 | /* | |||
225 | * There is no fragment support on current ext2fs (yet?), | |||
226 | * but some kernel code refers fsize or fpg as bsize or bpg | |||
227 | * and Linux seems to set the same values to them. | |||
228 | */ | |||
229 | errx(EXIT_FAILURE1, | |||
230 | "block size (%u) can't be different from " | |||
231 | "fragment size (%u)\n", | |||
232 | bsize, fsize); | |||
233 | } | |||
234 | ||||
235 | /* variable inodesize is REV1 feature */ | |||
236 | if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE128) { | |||
237 | errx(EXIT_FAILURE1, "GOOD_OLD_REV file system format" | |||
238 | " doesn't support %d byte inode\n", inodesize); | |||
239 | } | |||
240 | ||||
241 | sblockext2fsun.m_ext2fs.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE10; | |||
242 | sblockext2fsun.m_ext2fs.e2fs.e2fs_log_fsize = ilog2(fsize) - LOG_MINFSIZE10; | |||
243 | ||||
244 | sblockext2fsun.m_ext2fs.e2fs_bsize = bsize; | |||
245 | sblockext2fsun.m_ext2fs.e2fs_fsize = fsize; | |||
246 | sblockext2fsun.m_ext2fs.e2fs_bshift = sblockext2fsun.m_ext2fs.e2fs.e2fs_log_bsize + LOG_MINBSIZE10; | |||
247 | sblockext2fsun.m_ext2fs.e2fs_qbmask = sblockext2fsun.m_ext2fs.e2fs_bsize - 1; | |||
248 | sblockext2fsun.m_ext2fs.e2fs_bmask = ~sblockext2fsun.m_ext2fs.e2fs_qbmask; | |||
249 | sblockext2fsun.m_ext2fs.e2fs_fsbtodb = ilog2(sblockext2fsun.m_ext2fs.e2fs_bsize) - ilog2(sectorsize); | |||
250 | sblockext2fsun.m_ext2fs.e2fs_ipb = sblockext2fsun.m_ext2fs.e2fs_bsize / inodesize; | |||
251 | ||||
252 | /* | |||
253 | * Ext2fs preserves BBSIZE (1024 bytes) space at the top for | |||
254 | * bootloader (though it is not enough at all for our bootloader). | |||
255 | * If bsize == BBSIZE we have to preserve one block. | |||
256 | * If bsize > BBSIZE, the first block already contains BBSIZE space | |||
257 | * before superblock because superblock is allocated at SBOFF and | |||
258 | * bsize is a power of two (i.e. 2048 bytes or more). | |||
259 | */ | |||
260 | sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock = (sblockext2fsun.m_ext2fs.e2fs_bsize > BBSIZE1024) ? 0 : 1; | |||
261 | minfssize = fsbtodb(&sblock,((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
262 | sblock.e2fs.e2fs_first_dblock +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
263 | NBLOCK_SUPERBLOCK +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
264 | 1 /* at least one group descriptor */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
265 | NBLOCK_BLOCK_BITMAP +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
266 | NBLOCK_INODE_BITMAP +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
267 | 1 /* at least one inode table block */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
268 | 1 /* at least one data block for rootdir */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
269 | 1 /* at least one data block for data */((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
270 | )((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); /* XXX and more? */ | |||
271 | ||||
272 | if (fssize < minfssize) | |||
273 | errx(EXIT_FAILURE1, "Filesystem size %" PRId64"lld" | |||
274 | " < minimum size of %" PRId64"lld" "\n", fssize, minfssize); | |||
275 | ||||
276 | bcount = dbtofsb(&sblock, fssize)((fssize) >> (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
277 | ||||
278 | /* | |||
279 | * While many people claim that ext2fs is a (bad) clone of ufs/ffs, | |||
280 | * it isn't actual ffs so maybe we should call it "block group" | |||
281 | * as their native name rather than ffs derived "cylinder group." | |||
282 | * But we'll use the latter here since other kernel sources use it. | |||
283 | * (I also agree "cylinder" based allocation is obsolete though) | |||
284 | */ | |||
285 | ||||
286 | /* maybe "simple is the best" */ | |||
287 | blocks_per_cg = sblockext2fsun.m_ext2fs.e2fs_bsize * NBBY8; | |||
288 | ||||
289 | ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg)(((bcount - ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock) + ((blocks_per_cg ) - 1)) / (blocks_per_cg)); | |||
290 | blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize)(((sizeof(struct ext2_gd) * ncg) + ((bsize) - 1)) / (bsize)); | |||
291 | ||||
292 | /* check range of inode number */ | |||
293 | if (num_inodes < EXT2_FIRSTINO((ufsino_t)11)) | |||
294 | num_inodes = EXT2_FIRSTINO((ufsino_t)11); /* needs reserved inodes + 1 */ | |||
295 | if (num_inodes > UINT16_MAX0xffff * ncg) | |||
296 | num_inodes = UINT16_MAX0xffff * ncg; /* ext2bgd_nifree is uint16_t */ | |||
297 | ||||
298 | inodes_per_cg = num_inodes / ncg; | |||
299 | iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize)(((inodesize * inodes_per_cg) + ((bsize) - 1)) / (bsize)); | |||
300 | ||||
301 | /* Check that the last cylinder group has enough space for inodes */ | |||
302 | minblocks_per_cg = | |||
303 | NBLOCK_BLOCK_BITMAP1 + | |||
304 | NBLOCK_INODE_BITMAP1 + | |||
305 | iblocks_per_cg + | |||
306 | 1; /* at least one data block */ | |||
307 | if (Oflag
| |||
308 | minblocks_per_cg += NBLOCK_SUPERBLOCK1 + blocks_gd; | |||
309 | ||||
310 | blocks_lastcg = bcount - sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock - | |||
311 | blocks_per_cg * (ncg - 1); | |||
312 | if (blocks_lastcg < minblocks_per_cg) { | |||
313 | /* | |||
314 | * Since we make all the cylinder groups the same size, the | |||
315 | * last will only be small if there are more than one | |||
316 | * cylinder groups. If the last one is too small to store | |||
317 | * filesystem data, just kill it. | |||
318 | * | |||
319 | * XXX: Does fsck_ext2fs(8) properly handle this case? | |||
320 | */ | |||
321 | bcount -= blocks_lastcg; | |||
322 | ncg--; | |||
323 | blocks_lastcg = blocks_per_cg; | |||
324 | blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize)(((sizeof(struct ext2_gd) * ncg) + ((bsize) - 1)) / (bsize)); | |||
325 | inodes_per_cg = num_inodes / ncg; | |||
| ||||
326 | } | |||
327 | /* roundup inodes_per_cg to make it use whole inode table blocks */ | |||
328 | inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb)((((inodes_per_cg)+((ext2fsun.m_ext2fs.e2fs_ipb)-1))/(ext2fsun .m_ext2fs.e2fs_ipb))*(ext2fsun.m_ext2fs.e2fs_ipb)); | |||
329 | num_inodes = inodes_per_cg * ncg; | |||
330 | iblocks_per_cg = inodes_per_cg / sblockext2fsun.m_ext2fs.e2fs_ipb; | |||
331 | ||||
332 | /* XXX: probably we should check these adjusted values again */ | |||
333 | ||||
334 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount = bcount; | |||
335 | sblockext2fsun.m_ext2fs.e2fs.e2fs_icount = num_inodes; | |||
336 | ||||
337 | sblockext2fsun.m_ext2fs.e2fs_ncg = ncg; | |||
338 | sblockext2fsun.m_ext2fs.e2fs_ngdb = blocks_gd; | |||
339 | sblockext2fsun.m_ext2fs.e2fs_itpg = iblocks_per_cg; | |||
340 | ||||
341 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rbcount = sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount * minfree / 100; | |||
342 | /* e2fs_fbcount will be accounted later */ | |||
343 | /* e2fs_ficount will be accounted later */ | |||
344 | ||||
345 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg = blocks_per_cg; | |||
346 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fpg = blocks_per_cg; | |||
347 | ||||
348 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg = inodes_per_cg; | |||
349 | ||||
350 | sblockext2fsun.m_ext2fs.e2fs.e2fs_mtime = 0; | |||
351 | sblockext2fsun.m_ext2fs.e2fs.e2fs_wtime = (u_int32_t)tv.tv_sec; | |||
352 | sblockext2fsun.m_ext2fs.e2fs.e2fs_mnt_count = 0; | |||
353 | /* XXX: should add some entropy to avoid checking all fs at once? */ | |||
354 | sblockext2fsun.m_ext2fs.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT20; | |||
355 | ||||
356 | sblockext2fsun.m_ext2fs.e2fs.e2fs_magic = E2FS_MAGIC0xef53; | |||
357 | sblockext2fsun.m_ext2fs.e2fs.e2fs_state = E2FS_ISCLEAN0x01; | |||
358 | sblockext2fsun.m_ext2fs.e2fs.e2fs_beh = E2FS_BEH_DEFAULT1; | |||
359 | sblockext2fsun.m_ext2fs.e2fs.e2fs_minrev = 0; | |||
360 | sblockext2fsun.m_ext2fs.e2fs.e2fs_lastfsck = (u_int32_t)tv.tv_sec; | |||
361 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV(180 * 24 * 60 * 60); | |||
362 | ||||
363 | /* | |||
364 | * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper, | |||
365 | * but the purpose of this newfs_ext2fs(8) command is to provide | |||
366 | * a filesystem which can be recognized by firmware on some | |||
367 | * Linux based appliances that can load bootstrap files only from | |||
368 | * (their native) ext2fs, and anyway we will (and should) try to | |||
369 | * act like them as much as possible. | |||
370 | * | |||
371 | * Anyway, I hope that all newer such boxes will keep their support | |||
372 | * for the "GOOD_OLD_REV" ext2fs. | |||
373 | */ | |||
374 | sblockext2fsun.m_ext2fs.e2fs.e2fs_creator = E2FS_OS_LINUX0; | |||
375 | ||||
376 | if (Oflag == 0) { | |||
377 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rev = E2FS_REV00; | |||
378 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat = 0; | |||
379 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat = 0; | |||
380 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat = 0; | |||
381 | } else { | |||
382 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rev = E2FS_REV11; | |||
383 | /* | |||
384 | * e2fsprogs say "REV1" is "dynamic" so | |||
385 | * it isn't quite a version and maybe it means | |||
386 | * "extended from REV0 so check compat features." | |||
387 | * | |||
388 | * XXX: We don't have any native tool to activate | |||
389 | * the EXT2F_COMPAT_RESIZE feature and | |||
390 | * fsck_ext2fs(8) might not fix structures for it. | |||
391 | */ | |||
392 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat = EXT2F_COMPAT_RESIZE0x0010; | |||
393 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE0x0002; | |||
394 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat = | |||
395 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001 | EXT2F_ROCOMPAT_LARGE_FILE0x0002; | |||
396 | } | |||
397 | ||||
398 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ruid = geteuid(); | |||
399 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rgid = getegid(); | |||
400 | ||||
401 | sblockext2fsun.m_ext2fs.e2fs.e2fs_first_ino = EXT2_FIRSTINO((ufsino_t)11); | |||
402 | sblockext2fsun.m_ext2fs.e2fs.e2fs_inode_size = inodesize; | |||
403 | ||||
404 | /* e2fs_block_group_nr is set on writing superblock to each group */ | |||
405 | ||||
406 | uuid_get(&sblockext2fsun.m_ext2fs); | |||
407 | if (volname != NULL((void*)0)) { | |||
408 | if (strlen(volname) > sizeof(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname)) | |||
409 | errx(EXIT_FAILURE1, "Volume name is too long"); | |||
410 | strlcpy(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname, volname, | |||
411 | sizeof(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname)); | |||
412 | } | |||
413 | ||||
414 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fsmnt[0] = '\0'; | |||
415 | sblockext2fsun.m_ext2fs.e2fs_fsmnt[0] = '\0'; | |||
416 | ||||
417 | sblockext2fsun.m_ext2fs.e2fs.e2fs_algo = 0; /* XXX unsupported? */ | |||
418 | sblockext2fsun.m_ext2fs.e2fs.e2fs_prealloc = 0; /* XXX unsupported? */ | |||
419 | sblockext2fsun.m_ext2fs.e2fs.e2fs_dir_prealloc = 0; /* XXX unsupported? */ | |||
420 | ||||
421 | /* calculate blocks for reserved group descriptors for resize */ | |||
422 | sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb = 0; | |||
423 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
424 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE0x0010) != 0) { | |||
425 | uint64_t target_blocks; | |||
426 | uint target_ncg, target_ngdb, reserved_ngdb; | |||
427 | ||||
428 | /* reserve descriptors for size as 1024 times as current */ | |||
429 | target_blocks = | |||
430 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount - sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock) | |||
431 | * 1024ULL; | |||
432 | /* number of blocks must be in uint32_t */ | |||
433 | if (target_blocks > UINT32_MAX0xffffffffU) | |||
434 | target_blocks = UINT32_MAX0xffffffffU; | |||
435 | target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg)(((target_blocks) + ((ext2fsun.m_ext2fs.e2fs.e2fs_bpg) - 1)) / (ext2fsun.m_ext2fs.e2fs.e2fs_bpg)); | |||
436 | target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg,(((sizeof(struct ext2_gd) * target_ncg) + ((ext2fsun.m_ext2fs .e2fs_bsize) - 1)) / (ext2fsun.m_ext2fs.e2fs_bsize)) | |||
437 | sblock.e2fs_bsize)(((sizeof(struct ext2_gd) * target_ncg) + ((ext2fsun.m_ext2fs .e2fs_bsize) - 1)) / (ext2fsun.m_ext2fs.e2fs_bsize)); | |||
438 | /* | |||
439 | * Reserved group descriptor blocks are preserved as | |||
440 | * the second level double indirect reference blocks in | |||
441 | * the EXT2_RESIZEINO inode, so the maximum number of | |||
442 | * the blocks is NINDIR(fs). | |||
443 | * (see also descriptions in init_resizeino() function) | |||
444 | * | |||
445 | * We check a number including current e2fs_ngdb here | |||
446 | * because they will be moved into reserved gdb on | |||
447 | * possible future size shrink, though e2fsprogs don't | |||
448 | * seem to care about it. | |||
449 | */ | |||
450 | if (target_ngdb > NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
451 | target_ngdb = NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); | |||
452 | ||||
453 | reserved_ngdb = target_ngdb - sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
454 | ||||
455 | /* make sure reserved_ngdb fits in the last cg */ | |||
456 | if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1)) | |||
457 | reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1); | |||
458 | if (reserved_ngdb == 0) { | |||
459 | /* if no space for reserved gdb, disable the feature */ | |||
460 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat &= | |||
461 | ~EXT2F_COMPAT_RESIZE0x0010; | |||
462 | } | |||
463 | sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb = reserved_ngdb; | |||
464 | } | |||
465 | ||||
466 | /* | |||
467 | * Initialize group descriptors | |||
468 | */ | |||
469 | gdext2fsun.m_ext2fs.e2fs_gd = calloc(sblockext2fsun.m_ext2fs.e2fs_ngdb, bsize); | |||
470 | if (gdext2fsun.m_ext2fs.e2fs_gd == NULL((void*)0)) | |||
471 | errx(EXIT_FAILURE1, "Can't allocate descriptors buffer"); | |||
472 | ||||
473 | fbcount = 0; | |||
474 | ficount = 0; | |||
475 | for (cylno = 0; cylno < ncg; cylno++) { | |||
476 | uint boffset; | |||
477 | ||||
478 | boffset = cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)); | |||
479 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
480 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
481 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
482 | cg_has_sb(cylno)) { | |||
483 | boffset += NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
484 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
485 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & | |||
486 | EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
487 | boffset += sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; | |||
488 | } | |||
489 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_b_bitmap = boffset; | |||
490 | boffset += NBLOCK_BLOCK_BITMAP1; | |||
491 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_bitmap = boffset; | |||
492 | boffset += NBLOCK_INODE_BITMAP1; | |||
493 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_tables = boffset; | |||
494 | if (cylno == (ncg - 1)) | |||
495 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree = | |||
496 | blocks_lastcg - cgoverhead(cylno); | |||
497 | else | |||
498 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree = | |||
499 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg - cgoverhead(cylno); | |||
500 | fbcount += gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree; | |||
501 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree = sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg; | |||
502 | if (cylno == 0) { | |||
503 | /* take reserved inodes off nifree */ | |||
504 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES(((ufsino_t)11) - 1); | |||
505 | } | |||
506 | ficount += gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree; | |||
507 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_ndirs = 0; | |||
508 | } | |||
509 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fbcount = fbcount; | |||
510 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ficount = ficount; | |||
511 | ||||
512 | /* | |||
513 | * Dump out summary information about file system. | |||
514 | */ | |||
515 | if (verbosity > 0) { | |||
516 | printf("%s: %u.%1uMB (%" PRId64"lld" " sectors) " | |||
517 | "block size %u, fragment size %u\n", | |||
518 | fsys, | |||
519 | (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)), | |||
520 | (uint)((uint64_t)bcount * bsize - | |||
521 | rounddown((uint64_t)bcount * bsize, 1024 * 1024)((((uint64_t)bcount * bsize)/(1024 * 1024))*(1024 * 1024))) | |||
522 | / 1024 / 100, | |||
523 | fssize, bsize, fsize); | |||
524 | printf("\tusing %u block groups of %u.0MB, %u blks, " | |||
525 | "%u inodes.\n", | |||
526 | ncg, bsize * sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg / (1024 * 1024), | |||
527 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg, sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg); | |||
528 | } | |||
529 | ||||
530 | /* | |||
531 | * allocate space for superblock and group descriptors | |||
532 | */ | |||
533 | iobufsize = (NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb) * sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
534 | iobuf = mmap(0, iobufsize, PROT_READ0x01|PROT_WRITE0x02, | |||
535 | MAP_ANON0x1000|MAP_PRIVATE0x0002, -1, 0); | |||
536 | if (iobuf == MAP_FAILED((void *)-1)) | |||
537 | errx(EXIT_FAILURE1, "Cannot allocate I/O buffer\n"); | |||
538 | ||||
539 | /* | |||
540 | * We now start writing to the filesystem | |||
541 | */ | |||
542 | ||||
543 | if (!Nflag) { | |||
544 | static const uint pbsize[] = { 1024, 2048, 4096, 0 }; | |||
545 | uint pblock, epblock; | |||
546 | /* | |||
547 | * Validate the given file system size. | |||
548 | * Verify that its last block can actually be accessed. | |||
549 | * Convert to file system fragment sized units. | |||
550 | */ | |||
551 | if (fssize <= 0) | |||
552 | errx(EXIT_FAILURE1, "Preposterous size %" PRId64"lld" "\n", | |||
553 | fssize); | |||
554 | wtfs(fssize - 1, sectorsize, iobuf); | |||
555 | ||||
556 | /* | |||
557 | * Ensure there is nothing that looks like a filesystem | |||
558 | * superblock anywhere other than where ours will be. | |||
559 | * If fsck_ext2fs finds the wrong one all hell breaks loose! | |||
560 | * | |||
561 | * XXX: needs to check how fsck_ext2fs programs even | |||
562 | * on other OSes determine alternate superblocks | |||
563 | */ | |||
564 | for (i = 0; pbsize[i] != 0; i++) { | |||
565 | epblock = (uint64_t)bcount * bsize / pbsize[i]; | |||
566 | for (pblock = ((pbsize[i] == SBSIZE1024) ? 1 : 0); | |||
567 | pblock < epblock; | |||
568 | pblock += pbsize[i] * NBBY8 /* bpg */) | |||
569 | zap_old_sblock((daddr32_t)pblock * | |||
570 | pbsize[i] / sectorsize); | |||
571 | } | |||
572 | } | |||
573 | ||||
574 | if (verbosity >= 3) | |||
575 | printf("super-block backups (for fsck_ext2fs -b #) at:\n"); | |||
576 | /* If we are printing more than one line of numbers, line up columns */ | |||
577 | fld_width = verbosity < 4 ? 1 : snprintf(NULL((void*)0), 0, "%" PRIu64"llu", | |||
578 | (uint64_t)cgbase(&sblock, ncg - 1)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (ncg - 1))); | |||
579 | if (Nflag && verbosity == 3) | |||
580 | /* Leave space to add " ..." after one row of numbers */ | |||
581 | max_cols -= 4; | |||
582 | #define BASE 0x10000 /* For some fixed-point maths */ | |||
583 | col = 0; | |||
584 | delta = verbosity > 2 ? 0 : max_cols * BASE / ncg; | |||
585 | for (cylno = 0; cylno < ncg; cylno++) { | |||
586 | fflush(stdout(&__sF[1])); | |||
587 | initcg(cylno); | |||
588 | if (verbosity < 2) | |||
589 | continue; | |||
590 | /* the first one is a master, not backup */ | |||
591 | if (cylno == 0) | |||
592 | continue; | |||
593 | /* skip if this cylinder doesn't have a backup */ | |||
594 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
595 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
596 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) != 0 && | |||
597 | cg_has_sb(cylno) == 0) | |||
598 | continue; | |||
599 | ||||
600 | if (delta > 0) { | |||
601 | if (Nflag) | |||
602 | /* No point doing dots for -N */ | |||
603 | break; | |||
604 | /* Print dots scaled to end near RH margin */ | |||
605 | for (col += delta; col > BASE; col -= BASE) | |||
606 | printf("."); | |||
607 | continue; | |||
608 | } | |||
609 | /* Print superblock numbers */ | |||
610 | len = printf("%s%*" PRIu64"llu" ",", (col ? " " : ""), fld_width, | |||
611 | (uint64_t)cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno))); | |||
612 | col += len; | |||
613 | if (col + len < max_cols) | |||
614 | /* Next number fits */ | |||
615 | continue; | |||
616 | /* Next number won't fit, need a newline */ | |||
617 | if (verbosity <= 3) { | |||
618 | /* Print dots for subsequent cylinder groups */ | |||
619 | delta = sblockext2fsun.m_ext2fs.e2fs_ncg - cylno - 1; | |||
620 | if (delta != 0) { | |||
621 | if (Nflag) { | |||
622 | printf(" ..."); | |||
623 | break; | |||
624 | } | |||
625 | delta = max_cols * BASE / delta; | |||
626 | } | |||
627 | } | |||
628 | col = 0; | |||
629 | printf("\n"); | |||
630 | } | |||
631 | #undef BASE | |||
632 | if (col > 0) | |||
633 | printf("\n"); | |||
634 | if (Nflag) | |||
635 | return; | |||
636 | ||||
637 | /* | |||
638 | * Now construct the initial file system, | |||
639 | */ | |||
640 | if (fsinit(&tv) == 0) | |||
641 | errx(EXIT_FAILURE1, "Error making filesystem"); | |||
642 | /* | |||
643 | * Write out the superblock and group descriptors | |||
644 | */ | |||
645 | sblockext2fsun.m_ext2fs.e2fs.e2fs_block_group_nr = 0; | |||
646 | sboff = 0; | |||
647 | if (cgbase(&sblock, 0)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0)) == 0) { | |||
648 | /* | |||
649 | * If the first block contains the boot block sectors, | |||
650 | * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE) | |||
651 | * we have to preserve data in it. | |||
652 | */ | |||
653 | sboff = SBOFF((off_t)(((off_t)(0)) + 1024)); | |||
654 | } | |||
655 | e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff))memcpy(((struct ext2fs *)(iobuf + sboff)), (&ext2fsun.m_ext2fs .e2fs), 1024);; | |||
656 | e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize),memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize )), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun .m_ext2fs.e2fs_ncg)); | |||
657 | sizeof(struct ext2_gd) * sblock.e2fs_ncg)memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize )), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun .m_ext2fs.e2fs_ncg));; | |||
658 | wtfs(fsbtodb(&sblock, cgbase(&sblock, 0))((((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0))) << (&ext2fsun .m_ext2fs)->e2fs_fsbtodb) + sboff / sectorsize, | |||
659 | iobufsize - sboff, iobuf + sboff); | |||
660 | ||||
661 | munmap(iobuf, iobufsize); | |||
662 | } | |||
663 | ||||
664 | /* | |||
665 | * Initialize a cylinder (block) group. | |||
666 | */ | |||
667 | void | |||
668 | initcg(uint cylno) | |||
669 | { | |||
670 | uint nblcg, i, j, sboff; | |||
671 | struct ext2fs_dinode *dp; | |||
672 | ||||
673 | /* | |||
674 | * Make a copy of the superblock and group descriptors. | |||
675 | */ | |||
676 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
677 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
678 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
679 | cg_has_sb(cylno)) { | |||
680 | sblockext2fsun.m_ext2fs.e2fs.e2fs_block_group_nr = cylno; | |||
681 | sboff = 0; | |||
682 | if (cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) == 0) { | |||
683 | /* preserve data in bootblock in cg0 */ | |||
684 | sboff = SBOFF((off_t)(((off_t)(0)) + 1024)); | |||
685 | } | |||
686 | e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff))memcpy(((struct ext2fs *)(iobuf + sboff)), (&ext2fsun.m_ext2fs .e2fs), 1024);; | |||
687 | e2fs_cgsave(gd, (struct ext2_gd *)(iobuf +memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg)); | |||
688 | sblock.e2fs_bsize * NBLOCK_SUPERBLOCK),memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg)); | |||
689 | sizeof(struct ext2_gd) * sblock.e2fs_ncg)memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg));; | |||
690 | /* write superblock and group descriptor backups */ | |||
691 | wtfs(fsbtodb(&sblock, cgbase(&sblock, cylno))((((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno))) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb) + | |||
692 | sboff / sectorsize, iobufsize - sboff, iobuf + sboff); | |||
693 | } | |||
694 | ||||
695 | /* | |||
696 | * Initialize block bitmap. | |||
697 | */ | |||
698 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
699 | if (cylno == (sblockext2fsun.m_ext2fs.e2fs_ncg - 1)) { | |||
700 | /* The last group could have less blocks than e2fs_bpg. */ | |||
701 | nblcg = sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount - | |||
702 | cgbase(&sblock, sblock.e2fs_ncg - 1)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (ext2fsun.m_ext2fs.e2fs_ncg - 1)); | |||
703 | for (i = nblcg; i < roundup(nblcg, NBBY)((((nblcg)+((8)-1))/(8))*(8)); i++) | |||
704 | setbit(buf, i)((buf)[(i)>>3] |= 1<<((i)&(8 -1))); | |||
705 | memset(&buf[i / NBBY8], ~0U, sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg - i); | |||
706 | } | |||
707 | /* set overhead (superblock, group descriptor etc.) blocks used */ | |||
708 | for (i = 0; i < cgoverhead(cylno) / NBBY8; i++) | |||
709 | buf[i] = ~0; | |||
710 | i = i * NBBY8; | |||
711 | for (; i < cgoverhead(cylno); i++) | |||
712 | setbit(buf, i)((buf)[(i)>>3] |= 1<<((i)&(8 -1))); | |||
713 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_b_bitmap) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
714 | buf); | |||
715 | ||||
716 | /* | |||
717 | * Initialize inode bitmap. | |||
718 | * | |||
719 | * Assume e2fs_ipg is a multiple of NBBY since | |||
720 | * it's a multiple of e2fs_ipb (as we did above). | |||
721 | * Note even (possibly smaller) the last group has the same e2fs_ipg. | |||
722 | */ | |||
723 | i = sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg / NBBY8; | |||
724 | memset(buf, 0, i); | |||
725 | memset(buf + i, ~0U, sblockext2fsun.m_ext2fs.e2fs_bsize - i); | |||
726 | if (cylno == 0) { | |||
727 | /* mark reserved inodes */ | |||
728 | for (i = 1; i < EXT2_FIRSTINO((ufsino_t)11); i++) | |||
729 | setbit(buf, EXT2_INO_INDEX(i))((buf)[(((i) - 1))>>3] |= 1<<((((i) - 1))&(8 - 1))); | |||
730 | } | |||
731 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_bitmap) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
732 | buf); | |||
733 | ||||
734 | /* | |||
735 | * Initialize inode tables. | |||
736 | * | |||
737 | * Just initialize generation numbers for NFS security. | |||
738 | * XXX: sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_valloc() seems | |||
739 | * to override these generated numbers. | |||
740 | */ | |||
741 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
742 | for (i = 0; i < sblockext2fsun.m_ext2fs.e2fs_itpg; i++) { | |||
743 | for (j = 0; j < sblockext2fsun.m_ext2fs.e2fs_ipb; j++) { | |||
744 | dp = (struct ext2fs_dinode *)(buf + inodesize * j); | |||
745 | /* If there is some bias in arc4random(), keep it. */ | |||
746 | dp->e2di_gen = htole32(arc4random())((__uint32_t)(arc4random())); | |||
747 | } | |||
748 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_tables + i)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_tables + i) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
749 | sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
750 | } | |||
751 | } | |||
752 | ||||
753 | /* | |||
754 | * Zap possible lingering old superblock data | |||
755 | */ | |||
756 | static void | |||
757 | zap_old_sblock(daddr32_t sec) | |||
758 | { | |||
759 | static daddr32_t cg0_data; | |||
760 | uint32_t oldfs[SBSIZE1024 / sizeof(uint32_t)]; | |||
761 | static const struct fsm { | |||
762 | uint32_t offset; | |||
763 | uint32_t magic; | |||
764 | uint32_t mask; | |||
765 | } fs_magics[] = { | |||
766 | {offsetof(struct ext2fs, e2fs_magic)__builtin_offsetof(struct ext2fs, e2fs_magic) / 4, E2FS_MAGIC0xef53, 0xffff}, | |||
767 | {offsetof(struct ext2fs, e2fs_magic)__builtin_offsetof(struct ext2fs, e2fs_magic) / 4, | |||
768 | E2FS_MAGIC0xef53 << 16, 0xffff0000}, | |||
769 | {14, 0xef530000, 0xffff0000}, /* EXT2FS (big) */ | |||
770 | {0x55c / 4, 0x00011954, ~0U}, /* FS_UFS1_MAGIC */ | |||
771 | {0x55c / 4, 0x19540119, ~0U}, /* FS_UFS2_MAGIC */ | |||
772 | {0, 0x70162, ~0U}, /* LFS_MAGIC */ | |||
773 | {.offset = ~0U}, | |||
774 | }; | |||
775 | const struct fsm *fsm; | |||
776 | ||||
777 | if (Nflag) | |||
778 | return; | |||
779 | ||||
780 | /* don't override data before superblock */ | |||
781 | if (sec < SBOFF((off_t)(((off_t)(0)) + 1024)) / sectorsize) | |||
782 | return; | |||
783 | ||||
784 | if (cg0_data == 0) { | |||
785 | cg0_data = | |||
786 | ((daddr32_t)sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + cgoverhead(0)) * | |||
787 | sblockext2fsun.m_ext2fs.e2fs_bsize / sectorsize; | |||
788 | } | |||
789 | ||||
790 | /* Ignore anything that is beyond our filesystem */ | |||
791 | if (sec >= fssize) | |||
792 | return; | |||
793 | /* Zero anything inside our filesystem... */ | |||
794 | if (sec >= sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock * bsize / sectorsize) { | |||
795 | /* ...unless we will write that area anyway */ | |||
796 | if (sec >= cg0_data) | |||
797 | /* assume iobuf is zero'ed here */ | |||
798 | wtfs(sec, roundup(SBSIZE, sectorsize)((((1024)+((sectorsize)-1))/(sectorsize))*(sectorsize)), iobuf); | |||
799 | return; | |||
800 | } | |||
801 | ||||
802 | /* | |||
803 | * The sector might contain boot code, so we must validate it | |||
804 | * | |||
805 | * XXX: ext2fs won't preserve data after SBOFF, | |||
806 | * but first_dblock could have a different value. | |||
807 | */ | |||
808 | rdfs(sec, sizeof(oldfs), &oldfs); | |||
809 | for (fsm = fs_magics;; fsm++) { | |||
810 | uint32_t v; | |||
811 | if (fsm->mask == 0) | |||
812 | return; | |||
813 | v = oldfs[fsm->offset]; | |||
814 | if ((v & fsm->mask) == fsm->magic || | |||
815 | (swap32(v)(__uint32_t)(__builtin_constant_p(v) ? (__uint32_t)(((__uint32_t )(v) & 0xff) << 24 | ((__uint32_t)(v) & 0xff00) << 8 | ((__uint32_t)(v) & 0xff0000) >> 8 | ( (__uint32_t)(v) & 0xff000000) >> 24) : __swap32md(v )) & fsm->mask) == fsm->magic) | |||
816 | break; | |||
817 | } | |||
818 | ||||
819 | /* Just zap the magic number */ | |||
820 | oldfs[fsm->offset] = 0; | |||
821 | wtfs(sec, sizeof(oldfs), &oldfs); | |||
822 | } | |||
823 | ||||
824 | /* | |||
825 | * uint cgoverhead(uint c) | |||
826 | * | |||
827 | * Return a number of reserved blocks on the specified group. | |||
828 | * XXX: should be shared with src/sbin/fsck_ext2fs/setup.c | |||
829 | */ | |||
830 | uint | |||
831 | cgoverhead(uint c) | |||
832 | { | |||
833 | uint overh; | |||
834 | ||||
835 | overh = NBLOCK_BLOCK_BITMAP1 + NBLOCK_INODE_BITMAP1 + sblockext2fsun.m_ext2fs.e2fs_itpg; | |||
836 | ||||
837 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
838 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
839 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
840 | cg_has_sb(c) != 0) { | |||
841 | overh += NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
842 | ||||
843 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
844 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & | |||
845 | EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
846 | overh += sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; | |||
847 | } | |||
848 | ||||
849 | return overh; | |||
850 | } | |||
851 | ||||
852 | /* | |||
853 | * Initialize the file system | |||
854 | */ | |||
855 | ||||
856 | #define LOSTDIR /* e2fsck complains if there is no lost+found */ | |||
857 | ||||
858 | #define PREDEFDIR2 2 | |||
859 | ||||
860 | #ifdef LOSTDIR | |||
861 | #define PREDEFROOTDIR(2 + 1) (PREDEFDIR2 + 1) | |||
862 | #else | |||
863 | #define PREDEFROOTDIR(2 + 1) PREDEFDIR2 | |||
864 | #endif | |||
865 | ||||
866 | struct ext2fs_direct root_dir[] = { | |||
867 | { EXT2_ROOTINO((ufsino_t)2), 0, 1, 0, "." }, | |||
868 | { EXT2_ROOTINO((ufsino_t)2), 0, 2, 0, ".." }, | |||
869 | #ifdef LOSTDIR | |||
870 | { EXT2_LOSTFOUNDINO((ufsino_t)11), 0, 10, 0, "lost+found" }, | |||
871 | #endif | |||
872 | }; | |||
873 | ||||
874 | #ifdef LOSTDIR | |||
875 | struct ext2fs_direct lost_found_dir[] = { | |||
876 | { EXT2_LOSTFOUNDINO((ufsino_t)11), 0, 1, 0, "." }, | |||
877 | { EXT2_ROOTINO((ufsino_t)2), 0, 2, 0, ".." }, | |||
878 | }; | |||
879 | struct ext2fs_direct pad_dir = { 0, sizeof(struct ext2fs_direct), 0, 0, "" }; | |||
880 | #endif | |||
881 | ||||
882 | int | |||
883 | fsinit(const struct timeval *tv) | |||
884 | { | |||
885 | struct ext2fs_dinode node; | |||
886 | #ifdef LOSTDIR | |||
887 | uint i, nblks_lostfound, blk; | |||
888 | #endif | |||
889 | ||||
890 | /* | |||
891 | * Initialize the inode for the resizefs feature | |||
892 | */ | |||
893 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
894 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
895 | init_resizeino(tv); | |||
896 | ||||
897 | /* | |||
898 | * Initialize the node | |||
899 | */ | |||
900 | ||||
901 | #ifdef LOSTDIR | |||
902 | /* | |||
903 | * Create the lost+found directory | |||
904 | */ | |||
905 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
906 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002) { | |||
907 | lost_found_dir[0].e2d_type = EXT2_FT_DIR2; | |||
908 | lost_found_dir[1].e2d_type = EXT2_FT_DIR2; | |||
909 | } | |||
910 | (void)makedir(lost_found_dir, nitems(lost_found_dir)(sizeof((lost_found_dir)) / sizeof((lost_found_dir)[0]))); | |||
911 | ||||
912 | /* prepare a bit large directory for preserved files */ | |||
913 | nblks_lostfound = EXT2_LOSTFOUNDSIZE16384 / sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
914 | /* ...but only with direct blocks */ | |||
915 | if (nblks_lostfound > NDADDR12) | |||
916 | nblks_lostfound = NDADDR12; | |||
917 | ||||
918 | memset(&node, 0, sizeof(node)); | |||
919 | node.e2di_mode = EXT2_IFDIR0040000 | EXT2_LOSTFOUNDUMASK0700; | |||
920 | node.e2di_uid_low = geteuid(); | |||
921 | node.e2di_size = sblockext2fsun.m_ext2fs.e2fs_bsize * nblks_lostfound; | |||
922 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
923 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
924 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
925 | node.e2di_gid_low = getegid(); | |||
926 | node.e2di_nlink = PREDEFDIR2; | |||
927 | /* e2di_nblock is a number of disk blocks, not ext2fs blocks */ | |||
928 | node.e2di_nblock = fsbtodb(&sblock, nblks_lostfound)((nblks_lostfound) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb ); | |||
929 | node.e2di_blocks[0] = alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, node.e2di_mode); | |||
930 | if (node.e2di_blocks[0] == 0) { | |||
931 | printf("%s: can't allocate block for lost+found\n", __func__); | |||
932 | return 0; | |||
933 | } | |||
934 | for (i = 1; i < nblks_lostfound; i++) { | |||
935 | blk = alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, 0); | |||
936 | if (blk == 0) { | |||
937 | printf("%s: can't allocate blocks for lost+found\n", | |||
938 | __func__); | |||
939 | return 0; | |||
940 | } | |||
941 | node.e2di_blocks[i] = blk; | |||
942 | } | |||
943 | wtfs(fsbtodb(&sblock, node.e2di_blocks[0])((node.e2di_blocks[0]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
944 | pad_dir.e2d_reclen = sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
945 | for (i = 1; i < nblks_lostfound; i++) { | |||
946 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
947 | copy_dir(&pad_dir, (struct ext2fs_direct *)buf); | |||
948 | wtfs(fsbtodb(&sblock, node.e2di_blocks[i])((node.e2di_blocks[i]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
949 | buf); | |||
950 | } | |||
951 | iput(&node, EXT2_LOSTFOUNDINO((ufsino_t)11)); | |||
952 | #endif | |||
953 | /* | |||
954 | * create the root directory | |||
955 | */ | |||
956 | memset(&node, 0, sizeof(node)); | |||
957 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
958 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002) { | |||
959 | root_dir[0].e2d_type = EXT2_FT_DIR2; | |||
960 | root_dir[1].e2d_type = EXT2_FT_DIR2; | |||
961 | #ifdef LOSTDIR | |||
962 | root_dir[2].e2d_type = EXT2_FT_DIR2; | |||
963 | #endif | |||
964 | } | |||
965 | node.e2di_mode = EXT2_IFDIR0040000 | EXT2_UMASK0755; | |||
966 | node.e2di_uid_low = geteuid(); | |||
967 | node.e2di_size = makedir(root_dir, nitems(root_dir)(sizeof((root_dir)) / sizeof((root_dir)[0]))); | |||
968 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
969 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
970 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
971 | node.e2di_gid_low = getegid(); | |||
972 | node.e2di_nlink = PREDEFROOTDIR(2 + 1); | |||
973 | /* e2di_nblock is a number of disk block, not ext2fs block */ | |||
974 | node.e2di_nblock = fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
975 | node.e2di_blocks[0] = alloc(node.e2di_size, node.e2di_mode); | |||
976 | if (node.e2di_blocks[0] == 0) { | |||
977 | printf("%s: can't allocate block for root dir\n", __func__); | |||
978 | return 0; | |||
979 | } | |||
980 | wtfs(fsbtodb(&sblock, node.e2di_blocks[0])((node.e2di_blocks[0]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
981 | iput(&node, EXT2_ROOTINO((ufsino_t)2)); | |||
982 | return 1; | |||
983 | } | |||
984 | ||||
985 | /* | |||
986 | * Construct a set of directory entries in "buf". | |||
987 | * return size of directory. | |||
988 | */ | |||
989 | int | |||
990 | makedir(struct ext2fs_direct *protodir, int entries) | |||
991 | { | |||
992 | uint8_t *cp; | |||
993 | uint i, spcleft; | |||
994 | uint dirblksiz; | |||
995 | ||||
996 | dirblksiz = sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
997 | memset(buf, 0, dirblksiz); | |||
998 | spcleft = dirblksiz; | |||
999 | for (cp = buf, i = 0; i < entries - 1; i++) { | |||
1000 | protodir[i].e2d_reclen = EXT2FS_DIRSIZ(protodir[i].e2d_namlen)(( 8 + protodir[i].e2d_namlen + 3) &~ 3); | |||
1001 | copy_dir(&protodir[i], (struct ext2fs_direct *)cp); | |||
1002 | cp += protodir[i].e2d_reclen; | |||
1003 | spcleft -= protodir[i].e2d_reclen; | |||
1004 | } | |||
1005 | protodir[i].e2d_reclen = spcleft; | |||
1006 | copy_dir(&protodir[i], (struct ext2fs_direct *)cp); | |||
1007 | return dirblksiz; | |||
1008 | } | |||
1009 | ||||
1010 | /* | |||
1011 | * Copy a direntry to a buffer, in fs byte order | |||
1012 | */ | |||
1013 | static void | |||
1014 | copy_dir(struct ext2fs_direct *dir, struct ext2fs_direct *dbuf) | |||
1015 | { | |||
1016 | ||||
1017 | memcpy(dbuf, dir, EXT2FS_DIRSIZ(dir->e2d_namlen)(( 8 + dir->e2d_namlen + 3) &~ 3)); | |||
1018 | dbuf->e2d_ino = htole32(dir->e2d_ino)((__uint32_t)(dir->e2d_ino)); | |||
1019 | dbuf->e2d_reclen = htole16(dir->e2d_reclen)((__uint16_t)(dir->e2d_reclen)); | |||
1020 | } | |||
1021 | ||||
1022 | /* | |||
1023 | * void init_resizeino(const struct timeval *tv); | |||
1024 | * | |||
1025 | * Initialize the EXT2_RESEIZE_INO inode to preserve | |||
1026 | * reserved group descriptor blocks for future growth of this ext2fs. | |||
1027 | */ | |||
1028 | void | |||
1029 | init_resizeino(const struct timeval *tv) | |||
1030 | { | |||
1031 | struct ext2fs_dinode node; | |||
1032 | uint64_t isize; | |||
1033 | uint32_t *dindir_block, *reserved_gdb; | |||
1034 | uint nblock, i, cylno, n; | |||
1035 | ||||
1036 | memset(&node, 0, sizeof(node)); | |||
1037 | ||||
1038 | /* | |||
1039 | * Note this function only prepares required structures for | |||
1040 | * future resize. It's a quite different work to implement | |||
1041 | * a utility like resize_ext2fs(8) which handles actual | |||
1042 | * resize ops even on offline. | |||
1043 | * | |||
1044 | * Anyway, I'm not sure if there is any documentation about | |||
1045 | * this resize ext2fs feature and related data structures, | |||
1046 | * and I've written this function based on things what I see | |||
1047 | * on some existing implementation and real file system data | |||
1048 | * created by existing tools. To be honest, they are not | |||
1049 | * so easy to read, so I will try to implement it here without | |||
1050 | * any dumb optimization for people who would eventually | |||
1051 | * work on "yet another wheel" like resize_ext2fs(8). | |||
1052 | */ | |||
1053 | ||||
1054 | /* | |||
1055 | * I'm not sure what type is appropriate for this inode. | |||
1056 | * The release notes of e2fsprogs says they changed e2fsck to allow | |||
1057 | * IFREG for RESIZEINO since a certain resize tool used it. Hmm. | |||
1058 | */ | |||
1059 | node.e2di_mode = EXT2_IFREG0100000 | EXT2_RESIZEINOUMASK0600; | |||
1060 | node.e2di_uid_low = geteuid(); | |||
1061 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
1062 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
1063 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
1064 | node.e2di_gid_low = getegid(); | |||
1065 | node.e2di_nlink = 1; | |||
1066 | ||||
1067 | /* | |||
1068 | * To preserve the reserved group descriptor blocks, | |||
1069 | * EXT2_RESIZEINO uses only double indirect reference | |||
1070 | * blocks in its inode entries. | |||
1071 | * | |||
1072 | * All entries for direct, single indirect and triple | |||
1073 | * indirect references are left zero'ed. Maybe it's safe | |||
1074 | * because no write operation will happen with this inode. | |||
1075 | * | |||
1076 | * We have to allocate a block for the first level double | |||
1077 | * indirect reference block. Indexes of inode entries in | |||
1078 | * this first level dindirect block are corresponding to | |||
1079 | * indexes of group descriptors including both used (e2fs_ngdb) | |||
1080 | * and reserved (e2fs_reserved_ngdb) group descriptor blocks. | |||
1081 | * | |||
1082 | * Inode entries of indexes for used (e2fs_ngdb) descriptors are | |||
1083 | * left zero'ed. Entries for reserved (e2fs_reserved_ngdb) ones | |||
1084 | * have block numbers of actual reserved group descriptors | |||
1085 | * allocated at block group zero. This means e2fs_reserved_ngdb | |||
1086 | * blocks are reserved as the second level dindirect reference | |||
1087 | * blocks, and they actually contain block numbers of indirect | |||
1088 | * references. It may be safe since they don't have to keep any | |||
1089 | * data yet. | |||
1090 | * | |||
1091 | * Each these second dindirect blocks (i.e. reserved group | |||
1092 | * descriptor blocks in the first block group) should have | |||
1093 | * block numbers of its backups in all other block groups. | |||
1094 | * I.e. reserved_ngdb[0] block in block group 0 contains block | |||
1095 | * numbers of resreved_ngdb[0] from group 1 through (e2fs_ncg - 1). | |||
1096 | * The number of backups can be determined by the | |||
1097 | * EXT2_ROCOMPAT_SPARSESUPER feature and cg_has_sb() macro | |||
1098 | * as done in the above initcg() function. | |||
1099 | */ | |||
1100 | ||||
1101 | /* set e2di_size which occupies whole blocks through DINDIR blocks */ | |||
1102 | isize = (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NDADDR12 + | |||
1103 | (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)) + | |||
1104 | (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)) * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); | |||
1105 | if (isize > UINT32_MAX0xffffffffU && | |||
1106 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
1107 | EXT2F_ROCOMPAT_LARGE_FILE0x0002) == 0) { | |||
1108 | /* XXX should enable it here and update all backups? */ | |||
1109 | errx(EXIT_FAILURE1, "%s: large_file rocompat feature is " | |||
1110 | "required to enable resize feature for this filesystem\n", | |||
1111 | __func__); | |||
1112 | } | |||
1113 | /* upper 32bit is stored into e2di_size_hi on REV1 feature */ | |||
1114 | node.e2di_size = isize & UINT32_MAX0xffffffffU; | |||
1115 | node.e2di_size_hi = isize >> 32; | |||
1116 | ||||
1117 | #define SINGLE0 0 /* index of single indirect block */ | |||
1118 | #define DOUBLE1 1 /* index of double indirect block */ | |||
1119 | #define TRIPLE2 2 /* index of triple indirect block */ | |||
1120 | ||||
1121 | /* zero out entries for direct references */ | |||
1122 | for (i = 0; i < NDADDR12; i++) | |||
1123 | node.e2di_blocks[i] = 0; | |||
1124 | /* also zero out entries for single and triple indirect references */ | |||
1125 | node.e2di_blocks[NDADDR12 + SINGLE0] = 0; | |||
1126 | node.e2di_blocks[NDADDR12 + TRIPLE2] = 0; | |||
1127 | ||||
1128 | /* allocate a block for the first level double indirect reference */ | |||
1129 | node.e2di_blocks[NDADDR12 + DOUBLE1] = | |||
1130 | alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, node.e2di_mode); | |||
1131 | if (node.e2di_blocks[NDADDR12 + DOUBLE1] == 0) | |||
1132 | errx(EXIT_FAILURE1, "%s: Can't allocate a dindirect block", | |||
1133 | __func__); | |||
1134 | ||||
1135 | /* account this first block */ | |||
1136 | nblock = fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
1137 | ||||
1138 | /* allocate buffer to set data in the dindirect block */ | |||
1139 | dindir_block = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
1140 | if (dindir_block == NULL((void*)0)) | |||
1141 | errx(EXIT_FAILURE1, | |||
1142 | "%s: Can't allocate buffer for a dindirect block", | |||
1143 | __func__); | |||
1144 | ||||
1145 | /* allocate buffer to set data in the group descriptor blocks */ | |||
1146 | reserved_gdb = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
1147 | if (reserved_gdb == NULL((void*)0)) | |||
1148 | errx(EXIT_FAILURE1, | |||
1149 | "%s: Can't allocate buffer for group descriptor blocks", | |||
1150 | __func__); | |||
1151 | ||||
1152 | /* | |||
1153 | * Setup block entries in the first level dindirect blocks | |||
1154 | */ | |||
1155 | for (i = 0; i < sblockext2fsun.m_ext2fs.e2fs_ngdb; i++) { | |||
1156 | /* no need to handle used group descriptor blocks */ | |||
1157 | dindir_block[i] = 0; | |||
1158 | } | |||
1159 | for (; i < sblockext2fsun.m_ext2fs.e2fs_ngdb + sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; i++) { | |||
1160 | /* | |||
1161 | * point reserved group descriptor block in the first | |||
1162 | * (i.e. master) block group | |||
1163 | * | |||
1164 | * XXX: e2fsprogs seem to use "(i % NINDIR(&sblock))" here | |||
1165 | * to store maximum NINDIR(&sblock) reserved gdbs. | |||
1166 | * I'm not sure what will be done on future filesystem | |||
1167 | * shrink in that case on their way. | |||
1168 | */ | |||
1169 | if (i >= NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
1170 | errx(EXIT_FAILURE1, "%s: too many reserved " | |||
1171 | "group descriptors (%u) for resize inode", | |||
1172 | __func__, sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb); | |||
1173 | dindir_block[i] = | |||
1174 | htole32(cgbase(&sblock, 0) + NBLOCK_SUPERBLOCK + i)((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0)) + 1 + i) ); | |||
1175 | ||||
1176 | /* | |||
1177 | * Setup block entries in the second dindirect blocks | |||
1178 | * (which are primary reserved group descriptor blocks) | |||
1179 | * to point their backups. | |||
1180 | */ | |||
1181 | for (n = 0, cylno = 1; cylno < sblockext2fsun.m_ext2fs.e2fs_ncg; cylno++) { | |||
1182 | /* skip block groups without backup */ | |||
1183 | if ((sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
1184 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) != 0 && | |||
1185 | cg_has_sb(cylno) == 0) | |||
1186 | continue; | |||
1187 | ||||
1188 | if (n >= NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
1189 | errx(EXIT_FAILURE1, "%s: too many block groups " | |||
1190 | "for the resize feature", __func__); | |||
1191 | /* | |||
1192 | * These blocks are already reserved in | |||
1193 | * initcg() so no need to use alloc() here. | |||
1194 | */ | |||
1195 | reserved_gdb[n++] = htole32(cgbase(&sblock, cylno) +((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) + 1 + i)) | |||
1196 | NBLOCK_SUPERBLOCK + i)((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) + 1 + i)); | |||
1197 | nblock += fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
1198 | } | |||
1199 | for (; n < NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); n++) | |||
1200 | reserved_gdb[n] = 0; | |||
1201 | ||||
1202 | /* write group descriptor block as the second dindirect refs */ | |||
1203 | wtfs(fsbtodb(&sblock, letoh32(dindir_block[i]))((((__uint32_t)(dindir_block[i]))) << (&ext2fsun.m_ext2fs )->e2fs_fsbtodb), | |||
1204 | sblockext2fsun.m_ext2fs.e2fs_bsize, reserved_gdb); | |||
1205 | nblock += fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
1206 | } | |||
1207 | for (; i < NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); i++) { | |||
1208 | /* leave trailing entries unallocated */ | |||
1209 | dindir_block[i] = 0; | |||
1210 | } | |||
1211 | free(reserved_gdb); | |||
1212 | ||||
1213 | /* finally write the first level dindirect block */ | |||
1214 | wtfs(fsbtodb(&sblock, node.e2di_blocks[NDADDR + DOUBLE])((node.e2di_blocks[12 + 1]) << (&ext2fsun.m_ext2fs) ->e2fs_fsbtodb), | |||
1215 | sblockext2fsun.m_ext2fs.e2fs_bsize, dindir_block); | |||
1216 | free(dindir_block); | |||
1217 | ||||
1218 | node.e2di_nblock = nblock; | |||
1219 | iput(&node, EXT2_RESIZEINO((ufsino_t)7)); | |||
1220 | } | |||
1221 | ||||
1222 | /* | |||
1223 | * uint32_t alloc(uint32_t size, uint16_t mode) | |||
1224 | * | |||
1225 | * Allocate a block (from cylinder group 0) | |||
1226 | * Reference: src/sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_alloccg() | |||
1227 | */ | |||
1228 | uint32_t | |||
1229 | alloc(uint32_t size, uint16_t mode) | |||
1230 | { | |||
1231 | uint32_t loc, bno; | |||
1232 | uint8_t *bbp; | |||
1233 | uint len, map, i; | |||
1234 | ||||
1235 | if (gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_nbfree == 0) | |||
1236 | return 0; | |||
1237 | ||||
1238 | if (size > sblockext2fsun.m_ext2fs.e2fs_bsize) | |||
1239 | return 0; | |||
1240 | ||||
1241 | bbp = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
1242 | if (bbp == NULL((void*)0)) | |||
1243 | return 0; | |||
1244 | rdfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_b_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, bbp); | |||
1245 | ||||
1246 | /* XXX: kernel uses e2fs_fpg here */ | |||
1247 | len = sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg / NBBY8; | |||
1248 | ||||
1249 | #if 0 /* no need block allocation for root or lost+found dir */ | |||
1250 | for (loc = 0; loc < len; loc++) { | |||
1251 | if (bbp[loc] == 0) { | |||
1252 | bno = loc * NBBY8; | |||
1253 | goto gotit; | |||
1254 | } | |||
1255 | } | |||
1256 | #endif | |||
1257 | ||||
1258 | loc = skpc(~0U, len, bbp); | |||
1259 | if (loc == 0) { | |||
1260 | free(bbp); | |||
1261 | return 0; | |||
1262 | } | |||
1263 | loc = len - loc; | |||
1264 | map = bbp[loc]; | |||
1265 | bno = loc * NBBY8; | |||
1266 | for (i = 0; i < NBBY8; i++, bno++) { | |||
1267 | if ((map & (1 << i)) == 0) | |||
1268 | goto gotit; | |||
1269 | } | |||
1270 | free(bbp); | |||
1271 | return 0; | |||
1272 | ||||
1273 | gotit: | |||
1274 | if (isset(bbp, bno)((bbp)[(bno)>>3] & (1<<((bno)&(8 -1))))) | |||
1275 | errx(EXIT_FAILURE1, "%s: inconsistent bitmap\n", __func__); | |||
1276 | ||||
1277 | setbit(bbp, bno)((bbp)[(bno)>>3] |= 1<<((bno)&(8 -1))); | |||
1278 | wtfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_b_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, bbp); | |||
1279 | free(bbp); | |||
1280 | /* XXX: modified group descriptors won't be written into backups */ | |||
1281 | gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_nbfree--; | |||
1282 | if ((mode & EXT2_IFDIR0040000) != 0) | |||
1283 | gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_ndirs++; | |||
1284 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fbcount--; | |||
1285 | ||||
1286 | return sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + bno; | |||
1287 | } | |||
1288 | ||||
1289 | /* | |||
1290 | * void iput(struct ext2fs_dinode *ip, ino_t ino) | |||
1291 | * | |||
1292 | * Put an inode entry into the corresponding table. | |||
1293 | */ | |||
1294 | static void | |||
1295 | iput(struct ext2fs_dinode *ip, ino_t ino) | |||
1296 | { | |||
1297 | daddr32_t d; | |||
1298 | uint c, i; | |||
1299 | struct ext2fs_dinode *dp; | |||
1300 | uint8_t *bp; | |||
1301 | ||||
1302 | bp = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
1303 | if (bp == NULL((void*)0)) | |||
1304 | errx(EXIT_FAILURE1, "%s: can't allocate buffer for inode\n", | |||
1305 | __func__); | |||
1306 | ||||
1307 | /* | |||
1308 | * Reserved inodes are allocated and accounted in initcg() | |||
1309 | * so skip checks of the bitmap and allocation for them. | |||
1310 | */ | |||
1311 | if (ino >= EXT2_FIRSTINO((ufsino_t)11)) { | |||
1312 | c = ino_to_cg(&sblock, ino)(((ino) - 1) / (&ext2fsun.m_ext2fs)->e2fs.e2fs_ipg); | |||
1313 | ||||
1314 | /* sanity check */ | |||
1315 | if (gdext2fsun.m_ext2fs.e2fs_gd[c].ext2bgd_nifree == 0) | |||
1316 | errx(EXIT_FAILURE1, | |||
1317 | "%s: no free inode %" PRIu64"llu" " in block group %u\n", | |||
1318 | __func__, (uint64_t)ino, c); | |||
1319 | ||||
1320 | /* update inode bitmap */ | |||
1321 | rdfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_i_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
1322 | sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
1323 | ||||
1324 | /* more sanity */ | |||
1325 | if (isset(bp, EXT2_INO_INDEX(ino))((bp)[(((ino) - 1))>>3] & (1<<((((ino) - 1))& (8 -1))))) | |||
1326 | errx(EXIT_FAILURE1, "%s: inode %" PRIu64"llu" | |||
1327 | " already in use\n", __func__, (uint64_t)ino); | |||
1328 | setbit(bp, EXT2_INO_INDEX(ino))((bp)[(((ino) - 1))>>3] |= 1<<((((ino) - 1))& (8 -1))); | |||
1329 | wtfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_i_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
1330 | sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
1331 | gdext2fsun.m_ext2fs.e2fs_gd[c].ext2bgd_nifree--; | |||
1332 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ficount--; | |||
1333 | } | |||
1334 | ||||
1335 | if (ino >= sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg * sblockext2fsun.m_ext2fs.e2fs_ncg) | |||
1336 | errx(EXIT_FAILURE1, "%s: inode value out of range (%" PRIu64"llu" | |||
1337 | ").\n", __func__, (uint64_t)ino); | |||
1338 | ||||
1339 | /* update an inode entry in the table */ | |||
1340 | d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino))((((&ext2fsun.m_ext2fs)->e2fs_gd[(((ino) - 1) / (& ext2fsun.m_ext2fs)->e2fs.e2fs_ipg)].ext2bgd_i_tables + ((( ino)-1) % (&ext2fsun.m_ext2fs)->e2fs.e2fs_ipg)/(&ext2fsun .m_ext2fs)->e2fs_ipb)) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb); | |||
1341 | rdfs(d, sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
1342 | ||||
1343 | dp = (struct ext2fs_dinode *)(bp + | |||
1344 | inodesize * ino_to_fsbo(&sblock, ino)(((ino)-1) % (&ext2fsun.m_ext2fs)->e2fs_ipb)); | |||
1345 | e2fs_isave(&sblock, ip, dp)memcpy((dp),(ip), (((((&ext2fsun.m_ext2fs)->e2fs.e2fs_rev > 0 ? (&ext2fsun.m_ext2fs)->e2fs.e2fs_inode_size : 128))<(sizeof(*dp)))?(((&ext2fsun.m_ext2fs)->e2fs. e2fs_rev > 0 ? (&ext2fsun.m_ext2fs)->e2fs.e2fs_inode_size : 128)):(sizeof(*dp)))); | |||
1346 | /* e2fs_i_bswap() doesn't swap e2di_blocks addrs */ | |||
1347 | if ((ip->e2di_mode & EXT2_IFMT0170000) != EXT2_IFLNK0120000) { | |||
1348 | for (i = 0; i < NDADDR12 + NIADDR3; i++) | |||
1349 | dp->e2di_blocks[i] = htole32(ip->e2di_blocks[i])((__uint32_t)(ip->e2di_blocks[i])); | |||
1350 | } | |||
1351 | /* If there is some bias in arc4random(), keep it. */ | |||
1352 | dp->e2di_gen = htole32(arc4random())((__uint32_t)(arc4random())); | |||
1353 | ||||
1354 | wtfs(d, sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
1355 | free(bp); | |||
1356 | } | |||
1357 | ||||
1358 | /* | |||
1359 | * Read a block from the file system | |||
1360 | */ | |||
1361 | void | |||
1362 | rdfs(daddr32_t bno, int size, void *bf) | |||
1363 | { | |||
1364 | int n; | |||
1365 | off_t offset; | |||
1366 | ||||
1367 | offset = bno; | |||
1368 | n = pread(fd, bf, size, offset * sectorsize); | |||
1369 | if (n != size) | |||
1370 | err(EXIT_FAILURE1, "%s: read error for sector %" PRId64"lld", | |||
1371 | __func__, (int64_t)bno); | |||
1372 | } | |||
1373 | ||||
1374 | /* | |||
1375 | * Write a block to the file system | |||
1376 | */ | |||
1377 | void | |||
1378 | wtfs(daddr32_t bno, int size, void *bf) | |||
1379 | { | |||
1380 | int n; | |||
1381 | off_t offset; | |||
1382 | ||||
1383 | if (Nflag) | |||
1384 | return; | |||
1385 | offset = bno; | |||
1386 | n = pwrite(fd, bf, size, offset * sectorsize); | |||
1387 | if (n != size) | |||
1388 | err(EXIT_FAILURE1, "%s: write error for sector %" PRId64"lld", | |||
1389 | __func__, (int64_t)bno); | |||
1390 | } | |||
1391 | ||||
1392 | int | |||
1393 | ilog2(uint val) | |||
1394 | { | |||
1395 | ||||
1396 | if (val == 0 || !powerof2(val)((((val)-1)&(val))==0)) | |||
1397 | errx(EXIT_FAILURE1, "%s: %u is not a power of 2\n", | |||
1398 | __func__, val); | |||
1399 | ||||
1400 | return ffs(val) - 1; | |||
1401 | } | |||
1402 | ||||
1403 | /* | |||
1404 | * int skpc(int mask, size_t size, uint8_t *cp) | |||
1405 | * | |||
1406 | * Locate an unsigned character of value mask inside cp[]. | |||
1407 | * (from src/sys/lib/libkern/skpc.c) | |||
1408 | */ | |||
1409 | int | |||
1410 | skpc(int mask, size_t size, uint8_t *cp) | |||
1411 | { | |||
1412 | uint8_t *end; | |||
1413 | ||||
1414 | end = &cp[size]; | |||
1415 | while (cp < end && *cp == (uint8_t)mask) | |||
1416 | cp++; | |||
1417 | ||||
1418 | return end - cp; | |||
1419 | } | |||
1420 | ||||
1421 | static void | |||
1422 | uuid_get(struct m_ext2fs *sb) | |||
1423 | { | |||
1424 | unsigned char buf[sizeof(sb->e2fs.e2fs_uuid)]; | |||
1425 | ||||
1426 | arc4random_buf(buf, sizeof(buf)); | |||
1427 | /* UUID version 4: random */ | |||
1428 | buf[6] &= 0x0f; | |||
1429 | buf[6] |= 0x40; | |||
1430 | /* RFC4122 variant */ | |||
1431 | buf[8] &= 0x3f; | |||
1432 | buf[8] |= 0x80; | |||
1433 | memcpy(sb->e2fs.e2fs_uuid, buf, sizeof(sb->e2fs.e2fs_uuid)); | |||
1434 | } |