1 |
|
|
/* $OpenBSD: ffs.c,v 1.31 2017/01/21 21:58:32 natano Exp $ */ |
2 |
|
|
/* $NetBSD: ffs.c,v 1.66 2015/12/21 00:58:08 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2001 Wasabi Systems, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Written by Luke Mewburn for Wasabi Systems, Inc. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. All advertising materials mentioning features or use of this software |
19 |
|
|
* must display the following acknowledgement: |
20 |
|
|
* This product includes software developed for the NetBSD Project by |
21 |
|
|
* Wasabi Systems, Inc. |
22 |
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse |
23 |
|
|
* or promote products derived from this software without specific prior |
24 |
|
|
* written permission. |
25 |
|
|
* |
26 |
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
27 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
28 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
29 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
30 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
31 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
32 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
33 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
34 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
35 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
36 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
37 |
|
|
*/ |
38 |
|
|
/* |
39 |
|
|
* Copyright (c) 1982, 1986, 1989, 1993 |
40 |
|
|
* The Regents of the University of California. All rights reserved. |
41 |
|
|
* |
42 |
|
|
* Redistribution and use in source and binary forms, with or without |
43 |
|
|
* modification, are permitted provided that the following conditions |
44 |
|
|
* are met: |
45 |
|
|
* 1. Redistributions of source code must retain the above copyright |
46 |
|
|
* notice, this list of conditions and the following disclaimer. |
47 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
48 |
|
|
* notice, this list of conditions and the following disclaimer in the |
49 |
|
|
* documentation and/or other materials provided with the distribution. |
50 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
51 |
|
|
* may be used to endorse or promote products derived from this software |
52 |
|
|
* without specific prior written permission. |
53 |
|
|
* |
54 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
55 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
56 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
57 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
58 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
59 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
60 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
61 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
62 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
63 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
64 |
|
|
* SUCH DAMAGE. |
65 |
|
|
* |
66 |
|
|
* @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 |
67 |
|
|
*/ |
68 |
|
|
|
69 |
|
|
#include <sys/param.h> |
70 |
|
|
#include <sys/disklabel.h> |
71 |
|
|
|
72 |
|
|
#include <assert.h> |
73 |
|
|
#include <errno.h> |
74 |
|
|
#include <fcntl.h> |
75 |
|
|
#include <stdarg.h> |
76 |
|
|
#include <stdio.h> |
77 |
|
|
#include <stdint.h> |
78 |
|
|
#include <stdlib.h> |
79 |
|
|
#include <string.h> |
80 |
|
|
#include <unistd.h> |
81 |
|
|
|
82 |
|
|
#include <ufs/ufs/dinode.h> |
83 |
|
|
#include <ufs/ufs/dir.h> |
84 |
|
|
#include <ufs/ffs/fs.h> |
85 |
|
|
|
86 |
|
|
#include "ffs/ufs_inode.h" |
87 |
|
|
#include "ffs/ffs_extern.h" |
88 |
|
|
|
89 |
|
|
#include "makefs.h" |
90 |
|
|
#include "ffs.h" |
91 |
|
|
#include "ffs/newfs_extern.h" |
92 |
|
|
|
93 |
|
|
#undef DIP |
94 |
|
|
#define DIP(dp, field) \ |
95 |
|
|
((ffs_opts->version == 1) ? \ |
96 |
|
|
(dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field) |
97 |
|
|
|
98 |
|
|
/* |
99 |
|
|
* Various file system defaults (cribbed from newfs(8)). |
100 |
|
|
*/ |
101 |
|
|
#define DFL_FRAGSIZE 2048 /* fragment size */ |
102 |
|
|
#define DFL_BLKSIZE 16384 /* block size */ |
103 |
|
|
#define DFL_SECSIZE 512 /* sector size */ |
104 |
|
|
|
105 |
|
|
|
106 |
|
|
typedef struct { |
107 |
|
|
u_char *buf; /* buf for directory */ |
108 |
|
|
doff_t size; /* full size of buf */ |
109 |
|
|
doff_t cur; /* offset of current entry */ |
110 |
|
|
} dirbuf_t; |
111 |
|
|
|
112 |
|
|
|
113 |
|
|
static int ffs_create_image(const char *, fsinfo_t *); |
114 |
|
|
static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *); |
115 |
|
|
static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *); |
116 |
|
|
static void ffs_size_dir(fsnode *, fsinfo_t *); |
117 |
|
|
static void ffs_validate(const char *, fsnode *, fsinfo_t *); |
118 |
|
|
static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *); |
119 |
|
|
static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *); |
120 |
|
|
static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *, |
121 |
|
|
fsnode *, fsinfo_t *); |
122 |
|
|
static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, |
123 |
|
|
fsnode *, fsinfo_t *); |
124 |
|
|
|
125 |
|
|
|
126 |
|
|
|
127 |
|
|
/* publically visible functions */ |
128 |
|
|
void |
129 |
|
|
ffs_prep_opts(fsinfo_t *fsopts) |
130 |
|
|
{ |
131 |
|
|
ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts)); |
132 |
|
|
|
133 |
|
|
const option_t ffs_options[] = { |
134 |
|
|
{ "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, 1, INT_MAX }, |
135 |
|
|
{ "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, 1, INT_MAX }, |
136 |
|
|
{ "bsize", &ffs_opts->bsize, OPT_INT32, 1, INT_MAX }, |
137 |
|
|
{ "density", &ffs_opts->density, OPT_INT32, 1, INT_MAX }, |
138 |
|
|
{ "disklabel", NULL, OPT_STRBUF, 0, 0 }, |
139 |
|
|
{ "extent", &ffs_opts->maxbsize, OPT_INT32, 1, INT_MAX }, |
140 |
|
|
{ "fsize", &ffs_opts->fsize, OPT_INT32, 1, INT_MAX }, |
141 |
|
|
{ "label", ffs_opts->label, OPT_STRARRAY, 1, MAXVOLLEN }, |
142 |
|
|
{ "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, 1, INT_MAX }, |
143 |
|
|
{ "maxbpg", &ffs_opts->maxbpg, OPT_INT32, 1, INT_MAX }, |
144 |
|
|
{ "minfree", &ffs_opts->minfree, OPT_INT32, 0, 99 }, |
145 |
|
|
{ "optimization", NULL, OPT_STRBUF, 0, 0 }, |
146 |
|
|
{ "version", &ffs_opts->version, OPT_INT32, 1, 2 }, |
147 |
|
|
{ .name = NULL } |
148 |
|
|
}; |
149 |
|
|
|
150 |
|
|
ffs_opts->bsize = -1; |
151 |
|
|
ffs_opts->fsize = -1; |
152 |
|
|
ffs_opts->density = -1; |
153 |
|
|
ffs_opts->minfree = MINFREE; |
154 |
|
|
ffs_opts->optimization = FS_OPTSPACE; |
155 |
|
|
ffs_opts->maxbpg = -1; |
156 |
|
|
ffs_opts->avgfilesize = AVFILESIZ; |
157 |
|
|
ffs_opts->avgfpdir = AFPDIR; |
158 |
|
|
ffs_opts->version = 1; |
159 |
|
|
ffs_opts->lp = NULL; |
160 |
|
|
ffs_opts->pp = NULL; |
161 |
|
|
|
162 |
|
|
fsopts->fs_specific = ffs_opts; |
163 |
|
|
fsopts->fs_options = copy_opts(ffs_options); |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
void |
167 |
|
|
ffs_cleanup_opts(fsinfo_t *fsopts) |
168 |
|
|
{ |
169 |
|
|
free(fsopts->fs_specific); |
170 |
|
|
free(fsopts->fs_options); |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
int |
174 |
|
|
ffs_parse_opts(const char *option, fsinfo_t *fsopts) |
175 |
|
|
{ |
176 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
177 |
|
|
option_t *ffs_options = fsopts->fs_options; |
178 |
|
|
char buf[1024]; |
179 |
|
|
|
180 |
|
|
int rv; |
181 |
|
|
|
182 |
|
|
assert(option != NULL); |
183 |
|
|
assert(fsopts != NULL); |
184 |
|
|
assert(ffs_opts != NULL); |
185 |
|
|
|
186 |
|
|
rv = set_option(ffs_options, option, buf, sizeof(buf)); |
187 |
|
|
if (rv == -1) |
188 |
|
|
return 0; |
189 |
|
|
|
190 |
|
|
if (ffs_options[rv].name == NULL) |
191 |
|
|
abort(); |
192 |
|
|
|
193 |
|
|
if (strcmp(ffs_options[rv].name, "disklabel") == 0) { |
194 |
|
|
struct disklabel *dp; |
195 |
|
|
|
196 |
|
|
dp = getdiskbyname(buf); |
197 |
|
|
if (dp == NULL) |
198 |
|
|
errx(1, "unknown disk type: %s", buf); |
199 |
|
|
|
200 |
|
|
ffs_opts->lp = emalloc(sizeof(struct disklabel)); |
201 |
|
|
*ffs_opts->lp = *dp; |
202 |
|
|
} else if (strcmp(ffs_options[rv].name, "optimization") == 0) { |
203 |
|
|
if (strcmp(buf, "time") == 0) { |
204 |
|
|
ffs_opts->optimization = FS_OPTTIME; |
205 |
|
|
} else if (strcmp(buf, "space") == 0) { |
206 |
|
|
ffs_opts->optimization = FS_OPTSPACE; |
207 |
|
|
} else { |
208 |
|
|
warnx("Invalid optimization `%s'", buf); |
209 |
|
|
return 0; |
210 |
|
|
} |
211 |
|
|
} |
212 |
|
|
return 1; |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
|
216 |
|
|
void |
217 |
|
|
ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) |
218 |
|
|
{ |
219 |
|
|
struct fs *superblock; |
220 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
221 |
|
|
|
222 |
|
|
assert(image != NULL); |
223 |
|
|
assert(dir != NULL); |
224 |
|
|
assert(root != NULL); |
225 |
|
|
assert(fsopts != NULL); |
226 |
|
|
|
227 |
|
|
/* validate tree and options */ |
228 |
|
|
ffs_validate(dir, root, fsopts); |
229 |
|
|
|
230 |
|
|
printf("Calculated size of `%s': %lld bytes, %lld inodes\n", |
231 |
|
|
image, (long long)fsopts->size, (long long)fsopts->inodes); |
232 |
|
|
|
233 |
|
|
/* create image */ |
234 |
|
|
if (ffs_create_image(image, fsopts) == -1) |
235 |
|
|
errx(1, "Image file `%s' not created.", image); |
236 |
|
|
|
237 |
|
|
fsopts->curinode = ROOTINO; |
238 |
|
|
|
239 |
|
|
/* populate image */ |
240 |
|
|
printf("Populating `%s'\n", image); |
241 |
|
|
if (! ffs_populate_dir(dir, root, fsopts)) |
242 |
|
|
errx(1, "Image file `%s' not populated.", image); |
243 |
|
|
|
244 |
|
|
bcleanup(); |
245 |
|
|
|
246 |
|
|
/* update various superblock parameters */ |
247 |
|
|
superblock = fsopts->superblock; |
248 |
|
|
superblock->fs_fmod = 0; |
249 |
|
|
superblock->fs_ffs1_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir; |
250 |
|
|
superblock->fs_ffs1_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree; |
251 |
|
|
superblock->fs_ffs1_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree; |
252 |
|
|
superblock->fs_ffs1_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree; |
253 |
|
|
|
254 |
|
|
/* write out superblock; image is now complete */ |
255 |
|
|
ffs_write_superblock(fsopts->superblock, fsopts); |
256 |
|
|
|
257 |
|
|
if (ffs_opts->lp != NULL) { |
258 |
|
|
struct disklabel *lp = ffs_opts->lp; |
259 |
|
|
uint16_t *p, *end, sum = 0; |
260 |
|
|
ssize_t n; |
261 |
|
|
uint32_t bpg; |
262 |
|
|
|
263 |
|
|
bpg = superblock->fs_fpg / superblock->fs_frag; |
264 |
|
|
while (bpg > UINT16_MAX) |
265 |
|
|
bpg >>= 1; |
266 |
|
|
ffs_opts->pp->p_cpg = bpg; |
267 |
|
|
|
268 |
|
|
lp->d_magic = DISKMAGIC; |
269 |
|
|
lp->d_magic2 = DISKMAGIC; |
270 |
|
|
arc4random_buf(lp->d_uid, sizeof(lp->d_uid)); |
271 |
|
|
lp->d_checksum = 0; |
272 |
|
|
|
273 |
|
|
p = (uint16_t *)lp; |
274 |
|
|
end = (uint16_t *)&lp->d_partitions[lp->d_npartitions]; |
275 |
|
|
while (p < end) |
276 |
|
|
sum ^= *p++; |
277 |
|
|
lp->d_checksum = sum; |
278 |
|
|
|
279 |
|
|
n = pwrite(fsopts->fd, lp, sizeof(struct disklabel), |
280 |
|
|
fsopts->offset + LABELSECTOR * DEV_BSIZE + LABELOFFSET); |
281 |
|
|
if (n == -1) |
282 |
|
|
err(1, "failed to write disklabel"); |
283 |
|
|
else if (n < sizeof(struct disklabel)) |
284 |
|
|
errx(1, "failed to write disklabel: short write"); |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
if (close(fsopts->fd) == -1) |
288 |
|
|
err(1, "Closing `%s'", image); |
289 |
|
|
fsopts->fd = -1; |
290 |
|
|
printf("Image `%s' complete\n", image); |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
/* end of public functions */ |
294 |
|
|
|
295 |
|
|
|
296 |
|
|
static void |
297 |
|
|
ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) |
298 |
|
|
{ |
299 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
300 |
|
|
struct disklabel *lp = ffs_opts->lp; |
301 |
|
|
struct partition *pp = NULL; |
302 |
|
|
int32_t ncg = 1; |
303 |
|
|
int i; |
304 |
|
|
|
305 |
|
|
assert(dir != NULL); |
306 |
|
|
assert(root != NULL); |
307 |
|
|
assert(fsopts != NULL); |
308 |
|
|
assert(ffs_opts != NULL); |
309 |
|
|
|
310 |
|
|
if (lp != NULL) { |
311 |
|
|
for (i = 0; i < lp->d_npartitions; i++) { |
312 |
|
|
pp = &lp->d_partitions[i]; |
313 |
|
|
if (pp->p_fstype == FS_BSDFFS && |
314 |
|
|
pp->p_offset * lp->d_secsize == fsopts->offset) { |
315 |
|
|
break; |
316 |
|
|
} |
317 |
|
|
} |
318 |
|
|
if (i == lp->d_npartitions) |
319 |
|
|
errx(1, "no matching partition found in the disklabel"); |
320 |
|
|
ffs_opts->pp = pp; |
321 |
|
|
|
322 |
|
|
if (pp->p_fragblock == 0) |
323 |
|
|
errx(1, "fragment size missing in disktab"); |
324 |
|
|
if (fsopts->freeblocks != 0 || fsopts->freeblockpc != 0 || |
325 |
|
|
fsopts->freefiles != 0 || fsopts->freefilepc != 0 || |
326 |
|
|
fsopts->minsize != 0 || fsopts->maxsize != 0 || |
327 |
|
|
fsopts->sectorsize != -1 || fsopts->size != 0) |
328 |
|
|
errx(1, "-bfMmSs and disklabel are mutually exclusive"); |
329 |
|
|
if (ffs_opts->fsize != -1 || ffs_opts->bsize != -1) |
330 |
|
|
errx(1, "b/fsize and disklabel are mutually exclusive"); |
331 |
|
|
|
332 |
|
|
fsopts->sectorsize = lp->d_secsize; |
333 |
|
|
fsopts->minsize = fsopts->maxsize = |
334 |
|
|
DL_GETPSIZE(pp) * lp->d_secsize; |
335 |
|
|
ffs_opts->fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); |
336 |
|
|
ffs_opts->bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
/* set FFS defaults */ |
340 |
|
|
if (fsopts->sectorsize == -1) |
341 |
|
|
fsopts->sectorsize = DFL_SECSIZE; |
342 |
|
|
if (ffs_opts->fsize == -1) |
343 |
|
|
ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize); |
344 |
|
|
if (ffs_opts->bsize == -1) |
345 |
|
|
ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize); |
346 |
|
|
/* fsopts->density is set below */ |
347 |
|
|
/* XXX ondisk32 */ |
348 |
|
|
if (ffs_opts->maxbpg == -1) |
349 |
|
|
ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t); |
350 |
|
|
|
351 |
|
|
/* calculate size of tree */ |
352 |
|
|
ffs_size_dir(root, fsopts); |
353 |
|
|
fsopts->inodes += ROOTINO; /* include first two inodes */ |
354 |
|
|
|
355 |
|
|
/* add requested slop */ |
356 |
|
|
fsopts->size += fsopts->freeblocks; |
357 |
|
|
fsopts->inodes += fsopts->freefiles; |
358 |
|
|
if (fsopts->freefilepc > 0) |
359 |
|
|
fsopts->inodes = |
360 |
|
|
fsopts->inodes * (100 + fsopts->freefilepc) / 100; |
361 |
|
|
if (fsopts->freeblockpc > 0) |
362 |
|
|
fsopts->size = |
363 |
|
|
fsopts->size * (100 + fsopts->freeblockpc) / 100; |
364 |
|
|
|
365 |
|
|
/* add space needed for superblocks */ |
366 |
|
|
/* |
367 |
|
|
* The old SBOFF (SBLOCK_UFS1) is used here because makefs is |
368 |
|
|
* typically used for small filesystems where space matters. |
369 |
|
|
* XXX make this an option. |
370 |
|
|
*/ |
371 |
|
|
fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg; |
372 |
|
|
/* add space needed to store inodes, x3 for blockmaps, etc */ |
373 |
|
|
if (ffs_opts->version == 1) |
374 |
|
|
fsopts->size += ncg * sizeof(struct ufs1_dinode) * |
375 |
|
|
roundup(fsopts->inodes / ncg, |
376 |
|
|
ffs_opts->bsize / sizeof(struct ufs1_dinode)); |
377 |
|
|
else |
378 |
|
|
fsopts->size += ncg * sizeof(struct ufs2_dinode) * |
379 |
|
|
roundup(fsopts->inodes / ncg, |
380 |
|
|
ffs_opts->bsize / sizeof(struct ufs2_dinode)); |
381 |
|
|
|
382 |
|
|
/* add minfree */ |
383 |
|
|
if (ffs_opts->minfree > 0) |
384 |
|
|
fsopts->size = |
385 |
|
|
fsopts->size * (100 + ffs_opts->minfree) / 100; |
386 |
|
|
/* |
387 |
|
|
* XXX any other fs slop to add, such as csum's, bitmaps, etc ?? |
388 |
|
|
*/ |
389 |
|
|
|
390 |
|
|
if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */ |
391 |
|
|
fsopts->size = fsopts->minsize; |
392 |
|
|
|
393 |
|
|
/* round up to the next block */ |
394 |
|
|
fsopts->size = roundup(fsopts->size, ffs_opts->bsize); |
395 |
|
|
|
396 |
|
|
/* calculate density if necessary */ |
397 |
|
|
if (ffs_opts->density == -1) |
398 |
|
|
ffs_opts->density = fsopts->size / fsopts->inodes + 1; |
399 |
|
|
|
400 |
|
|
/* now check calculated sizes vs requested sizes */ |
401 |
|
|
if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { |
402 |
|
|
errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", |
403 |
|
|
dir, (long long)fsopts->size, (long long)fsopts->maxsize); |
404 |
|
|
} |
405 |
|
|
} |
406 |
|
|
|
407 |
|
|
|
408 |
|
|
static int |
409 |
|
|
ffs_create_image(const char *image, fsinfo_t *fsopts) |
410 |
|
|
{ |
411 |
|
|
struct fs *fs; |
412 |
|
|
char *buf; |
413 |
|
|
int i, bufsize; |
414 |
|
|
off_t bufrem; |
415 |
|
|
time_t tstamp; |
416 |
|
|
int oflags = O_RDWR | O_CREAT; |
417 |
|
|
|
418 |
|
|
assert (image != NULL); |
419 |
|
|
assert (fsopts != NULL); |
420 |
|
|
|
421 |
|
|
/* create image */ |
422 |
|
|
if (fsopts->offset == 0) |
423 |
|
|
oflags |= O_TRUNC; |
424 |
|
|
if ((fsopts->fd = open(image, oflags, 0666)) == -1) { |
425 |
|
|
warn("Can't open `%s' for writing", image); |
426 |
|
|
return (-1); |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
/* zero image */ |
430 |
|
|
bufsize = 8192; |
431 |
|
|
bufrem = fsopts->size; |
432 |
|
|
|
433 |
|
|
if (fsopts->offset != 0) |
434 |
|
|
if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) { |
435 |
|
|
warn("can't seek"); |
436 |
|
|
return -1; |
437 |
|
|
} |
438 |
|
|
|
439 |
|
|
if (bufrem > 0) |
440 |
|
|
buf = ecalloc(1, bufsize); |
441 |
|
|
while (bufrem > 0) { |
442 |
|
|
i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); |
443 |
|
|
if (i == -1) { |
444 |
|
|
warn("zeroing image, %lld bytes to go", |
445 |
|
|
(long long)bufrem); |
446 |
|
|
free(buf); |
447 |
|
|
return (-1); |
448 |
|
|
} |
449 |
|
|
bufrem -= i; |
450 |
|
|
} |
451 |
|
|
if (buf) |
452 |
|
|
free(buf); |
453 |
|
|
|
454 |
|
|
/* make the file system */ |
455 |
|
|
if (Tflag) { |
456 |
|
|
tstamp = stampts; |
457 |
|
|
srandom_deterministic(stampts); |
458 |
|
|
} else |
459 |
|
|
tstamp = start_time.tv_sec; |
460 |
|
|
|
461 |
|
|
fs = ffs_mkfs(image, fsopts, tstamp); |
462 |
|
|
fsopts->superblock = (void *)fs; |
463 |
|
|
|
464 |
|
|
if ((off_t)(fs->fs_cstotal.cs_nifree + ROOTINO) < fsopts->inodes) { |
465 |
|
|
warnx( |
466 |
|
|
"Image file `%s' has %lld free inodes; %lld are required.", |
467 |
|
|
image, |
468 |
|
|
(long long)(fs->fs_cstotal.cs_nifree + ROOTINO), |
469 |
|
|
(long long)fsopts->inodes); |
470 |
|
|
return (-1); |
471 |
|
|
} |
472 |
|
|
return (fsopts->fd); |
473 |
|
|
} |
474 |
|
|
|
475 |
|
|
|
476 |
|
|
static void |
477 |
|
|
ffs_size_dir(fsnode *root, fsinfo_t *fsopts) |
478 |
|
|
{ |
479 |
|
|
struct direct tmpdir; |
480 |
|
|
fsnode * node; |
481 |
|
|
int curdirsize, this; |
482 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
483 |
|
|
|
484 |
|
|
/* node may be NULL (empty directory) */ |
485 |
|
|
assert(fsopts != NULL); |
486 |
|
|
assert(ffs_opts != NULL); |
487 |
|
|
|
488 |
|
|
#define ADDDIRENT(e) do { \ |
489 |
|
|
tmpdir.d_namlen = strlen((e)); \ |
490 |
|
|
this = DIRSIZ(NEWDIRFMT, &tmpdir); \ |
491 |
|
|
if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)) \ |
492 |
|
|
curdirsize = roundup(curdirsize, DIRBLKSIZ); \ |
493 |
|
|
curdirsize += this; \ |
494 |
|
|
} while (0); |
495 |
|
|
|
496 |
|
|
/* |
497 |
|
|
* XXX this needs to take into account extra space consumed |
498 |
|
|
* by indirect blocks, etc. |
499 |
|
|
*/ |
500 |
|
|
#define ADDSIZE(x) do { \ |
501 |
|
|
fsopts->size += roundup((x), ffs_opts->fsize); \ |
502 |
|
|
} while (0); |
503 |
|
|
|
504 |
|
|
curdirsize = 0; |
505 |
|
|
for (node = root; node != NULL; node = node->next) { |
506 |
|
|
ADDDIRENT(node->name); |
507 |
|
|
if (node == root) { /* we're at "." */ |
508 |
|
|
assert(strcmp(node->name, ".") == 0); |
509 |
|
|
ADDDIRENT(".."); |
510 |
|
|
} else if ((node->inode->flags & FI_SIZED) == 0) { |
511 |
|
|
/* don't count duplicate names */ |
512 |
|
|
node->inode->flags |= FI_SIZED; |
513 |
|
|
fsopts->inodes++; |
514 |
|
|
if (node->type == S_IFREG) |
515 |
|
|
ADDSIZE(node->inode->st.st_size); |
516 |
|
|
if (node->type == S_IFLNK) { |
517 |
|
|
size_t slen; |
518 |
|
|
|
519 |
|
|
slen = strlen(node->symlink) + 1; |
520 |
|
|
if (slen >= (ffs_opts->version == 1 ? |
521 |
|
|
MAXSYMLINKLEN_UFS1 : |
522 |
|
|
MAXSYMLINKLEN_UFS2)) |
523 |
|
|
ADDSIZE(slen); |
524 |
|
|
} |
525 |
|
|
} |
526 |
|
|
if (node->type == S_IFDIR) |
527 |
|
|
ffs_size_dir(node->child, fsopts); |
528 |
|
|
} |
529 |
|
|
ADDSIZE(curdirsize); |
530 |
|
|
} |
531 |
|
|
|
532 |
|
|
static void * |
533 |
|
|
ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, |
534 |
|
|
fsnode *root, fsinfo_t *fsopts) |
535 |
|
|
{ |
536 |
|
|
size_t slen; |
537 |
|
|
void *membuf; |
538 |
|
|
|
539 |
|
|
memset(dinp, 0, sizeof(*dinp)); |
540 |
|
|
dinp->di_mode = cur->inode->st.st_mode; |
541 |
|
|
dinp->di_nlink = cur->inode->nlink; |
542 |
|
|
dinp->di_size = cur->inode->st.st_size; |
543 |
|
|
dinp->di_flags = cur->inode->st.st_flags; |
544 |
|
|
dinp->di_gen = cur->inode->st.st_gen; |
545 |
|
|
dinp->di_uid = cur->inode->st.st_uid; |
546 |
|
|
dinp->di_gid = cur->inode->st.st_gid; |
547 |
|
|
|
548 |
|
|
dinp->di_atime = cur->inode->st.st_atime; |
549 |
|
|
dinp->di_mtime = cur->inode->st.st_mtime; |
550 |
|
|
dinp->di_ctime = cur->inode->st.st_ctime; |
551 |
|
|
dinp->di_atimensec = cur->inode->st.st_atimensec; |
552 |
|
|
dinp->di_mtimensec = cur->inode->st.st_mtimensec; |
553 |
|
|
dinp->di_ctimensec = cur->inode->st.st_ctimensec; |
554 |
|
|
/* not set: di_db, di_ib, di_blocks, di_spare */ |
555 |
|
|
|
556 |
|
|
membuf = NULL; |
557 |
|
|
if (cur == root) { /* "."; write dirbuf */ |
558 |
|
|
membuf = dbufp->buf; |
559 |
|
|
dinp->di_size = dbufp->size; |
560 |
|
|
} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { |
561 |
|
|
dinp->di_size = 0; /* a device */ |
562 |
|
|
dinp->di_rdev = cur->inode->st.st_rdev; |
563 |
|
|
} else if (S_ISLNK(cur->type)) { /* symlink */ |
564 |
|
|
slen = strlen(cur->symlink); |
565 |
|
|
if (slen < MAXSYMLINKLEN_UFS1) { /* short link */ |
566 |
|
|
memcpy(dinp->di_db, cur->symlink, slen); |
567 |
|
|
} else |
568 |
|
|
membuf = cur->symlink; |
569 |
|
|
dinp->di_size = slen; |
570 |
|
|
} |
571 |
|
|
return membuf; |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
static void * |
575 |
|
|
ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, |
576 |
|
|
fsnode *root, fsinfo_t *fsopts) |
577 |
|
|
{ |
578 |
|
|
size_t slen; |
579 |
|
|
void *membuf; |
580 |
|
|
|
581 |
|
|
memset(dinp, 0, sizeof(*dinp)); |
582 |
|
|
dinp->di_mode = cur->inode->st.st_mode; |
583 |
|
|
dinp->di_nlink = cur->inode->nlink; |
584 |
|
|
dinp->di_size = cur->inode->st.st_size; |
585 |
|
|
dinp->di_flags = cur->inode->st.st_flags; |
586 |
|
|
dinp->di_gen = cur->inode->st.st_gen; |
587 |
|
|
dinp->di_uid = cur->inode->st.st_uid; |
588 |
|
|
dinp->di_gid = cur->inode->st.st_gid; |
589 |
|
|
|
590 |
|
|
dinp->di_atime = cur->inode->st.st_atime; |
591 |
|
|
dinp->di_mtime = cur->inode->st.st_mtime; |
592 |
|
|
dinp->di_ctime = cur->inode->st.st_ctime; |
593 |
|
|
dinp->di_atimensec = cur->inode->st.st_atimensec; |
594 |
|
|
dinp->di_mtimensec = cur->inode->st.st_mtimensec; |
595 |
|
|
dinp->di_ctimensec = cur->inode->st.st_ctimensec; |
596 |
|
|
/* not set: di_db, di_ib, di_blocks, di_spare */ |
597 |
|
|
|
598 |
|
|
membuf = NULL; |
599 |
|
|
if (cur == root) { /* "."; write dirbuf */ |
600 |
|
|
membuf = dbufp->buf; |
601 |
|
|
dinp->di_size = dbufp->size; |
602 |
|
|
} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { |
603 |
|
|
dinp->di_size = 0; /* a device */ |
604 |
|
|
dinp->di_rdev = cur->inode->st.st_rdev; |
605 |
|
|
} else if (S_ISLNK(cur->type)) { /* symlink */ |
606 |
|
|
slen = strlen(cur->symlink); |
607 |
|
|
if (slen < MAXSYMLINKLEN_UFS2) { /* short link */ |
608 |
|
|
memcpy(dinp->di_db, cur->symlink, slen); |
609 |
|
|
} else |
610 |
|
|
membuf = cur->symlink; |
611 |
|
|
dinp->di_size = slen; |
612 |
|
|
} |
613 |
|
|
return membuf; |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
static int |
617 |
|
|
ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts) |
618 |
|
|
{ |
619 |
|
|
fsnode *cur; |
620 |
|
|
dirbuf_t dirbuf; |
621 |
|
|
union dinode din; |
622 |
|
|
void *membuf; |
623 |
|
|
char path[MAXPATHLEN + 1]; |
624 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
625 |
|
|
|
626 |
|
|
assert(dir != NULL); |
627 |
|
|
assert(root != NULL); |
628 |
|
|
assert(fsopts != NULL); |
629 |
|
|
assert(ffs_opts != NULL); |
630 |
|
|
|
631 |
|
|
(void)memset(&dirbuf, 0, sizeof(dirbuf)); |
632 |
|
|
|
633 |
|
|
/* |
634 |
|
|
* pass 1: allocate inode numbers, build directory `file' |
635 |
|
|
*/ |
636 |
|
|
for (cur = root; cur != NULL; cur = cur->next) { |
637 |
|
|
if ((cur->inode->flags & FI_ALLOCATED) == 0) { |
638 |
|
|
cur->inode->flags |= FI_ALLOCATED; |
639 |
|
|
if (cur == root && cur->parent != NULL) |
640 |
|
|
cur->inode->ino = cur->parent->inode->ino; |
641 |
|
|
else { |
642 |
|
|
cur->inode->ino = fsopts->curinode; |
643 |
|
|
fsopts->curinode++; |
644 |
|
|
} |
645 |
|
|
} |
646 |
|
|
ffs_make_dirbuf(&dirbuf, cur->name, cur); |
647 |
|
|
if (cur == root) { /* we're at "."; add ".." */ |
648 |
|
|
ffs_make_dirbuf(&dirbuf, "..", |
649 |
|
|
cur->parent == NULL ? cur : cur->parent->first); |
650 |
|
|
root->inode->nlink++; /* count my parent's link */ |
651 |
|
|
} else if (cur->child != NULL) |
652 |
|
|
root->inode->nlink++; /* count my child's link */ |
653 |
|
|
|
654 |
|
|
/* |
655 |
|
|
* XXX possibly write file and long symlinks here, |
656 |
|
|
* ensuring that blocks get written before inodes? |
657 |
|
|
* otoh, this isn't a real filesystem, so who |
658 |
|
|
* cares about ordering? :-) |
659 |
|
|
*/ |
660 |
|
|
} |
661 |
|
|
|
662 |
|
|
/* |
663 |
|
|
* pass 2: write out dirbuf, then non-directories at this level |
664 |
|
|
*/ |
665 |
|
|
for (cur = root; cur != NULL; cur = cur->next) { |
666 |
|
|
if (cur->inode->flags & FI_WRITTEN) |
667 |
|
|
continue; /* skip hard-linked entries */ |
668 |
|
|
cur->inode->flags |= FI_WRITTEN; |
669 |
|
|
|
670 |
|
|
if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root, |
671 |
|
|
cur->path, cur->name) >= sizeof(path)) |
672 |
|
|
errx(1, "Pathname too long."); |
673 |
|
|
|
674 |
|
|
if (cur->child != NULL) |
675 |
|
|
continue; /* child creates own inode */ |
676 |
|
|
|
677 |
|
|
/* build on-disk inode */ |
678 |
|
|
if (ffs_opts->version == 1) |
679 |
|
|
membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur, |
680 |
|
|
root, fsopts); |
681 |
|
|
else |
682 |
|
|
membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur, |
683 |
|
|
root, fsopts); |
684 |
|
|
|
685 |
|
|
if (membuf != NULL) { |
686 |
|
|
ffs_write_file(&din, cur->inode->ino, membuf, fsopts); |
687 |
|
|
} else if (S_ISREG(cur->type)) { |
688 |
|
|
ffs_write_file(&din, cur->inode->ino, path, fsopts); |
689 |
|
|
} else { |
690 |
|
|
assert (! S_ISDIR(cur->type)); |
691 |
|
|
ffs_write_inode(&din, cur->inode->ino, fsopts); |
692 |
|
|
} |
693 |
|
|
} |
694 |
|
|
|
695 |
|
|
/* |
696 |
|
|
* pass 3: write out sub-directories |
697 |
|
|
*/ |
698 |
|
|
for (cur = root; cur != NULL; cur = cur->next) { |
699 |
|
|
if (cur->child == NULL) |
700 |
|
|
continue; |
701 |
|
|
if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, |
702 |
|
|
cur->name) >= sizeof(path)) |
703 |
|
|
errx(1, "Pathname too long."); |
704 |
|
|
if (! ffs_populate_dir(path, cur->child, fsopts)) |
705 |
|
|
return (0); |
706 |
|
|
} |
707 |
|
|
|
708 |
|
|
/* cleanup */ |
709 |
|
|
if (dirbuf.buf != NULL) |
710 |
|
|
free(dirbuf.buf); |
711 |
|
|
return (1); |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
|
715 |
|
|
static void |
716 |
|
|
ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) |
717 |
|
|
{ |
718 |
|
|
int isfile, ffd; |
719 |
|
|
char *fbuf, *p; |
720 |
|
|
off_t bufleft, chunk, offset; |
721 |
|
|
ssize_t nread; |
722 |
|
|
struct inode in; |
723 |
|
|
struct mkfsbuf * bp; |
724 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
725 |
|
|
struct mkfsvnode vp = { fsopts, NULL }; |
726 |
|
|
|
727 |
|
|
assert (din != NULL); |
728 |
|
|
assert (buf != NULL); |
729 |
|
|
assert (fsopts != NULL); |
730 |
|
|
assert (ffs_opts != NULL); |
731 |
|
|
|
732 |
|
|
isfile = S_ISREG(DIP(din, mode)); |
733 |
|
|
fbuf = NULL; |
734 |
|
|
ffd = -1; |
735 |
|
|
p = NULL; |
736 |
|
|
|
737 |
|
|
in.i_fs = (struct fs *)fsopts->superblock; |
738 |
|
|
in.i_devvp = &vp; |
739 |
|
|
|
740 |
|
|
in.i_number = ino; |
741 |
|
|
in.i_size = DIP(din, size); |
742 |
|
|
if (ffs_opts->version == 1) |
743 |
|
|
memcpy(&in.i_din.ffs1_din, &din->ffs1_din, |
744 |
|
|
sizeof(in.i_din.ffs1_din)); |
745 |
|
|
else |
746 |
|
|
memcpy(&in.i_din.ffs2_din, &din->ffs2_din, |
747 |
|
|
sizeof(in.i_din.ffs2_din)); |
748 |
|
|
|
749 |
|
|
if (DIP(din, size) == 0) |
750 |
|
|
goto write_inode_and_leave; /* mmm, cheating */ |
751 |
|
|
|
752 |
|
|
if (isfile) { |
753 |
|
|
fbuf = emalloc(ffs_opts->bsize); |
754 |
|
|
if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) { |
755 |
|
|
warn("Can't open `%s' for reading", (char *)buf); |
756 |
|
|
goto leave_ffs_write_file; |
757 |
|
|
} |
758 |
|
|
} else { |
759 |
|
|
p = buf; |
760 |
|
|
} |
761 |
|
|
|
762 |
|
|
chunk = 0; |
763 |
|
|
for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) { |
764 |
|
|
chunk = MIN(bufleft, ffs_opts->bsize); |
765 |
|
|
if (!isfile) |
766 |
|
|
; |
767 |
|
|
else if ((nread = read(ffd, fbuf, chunk)) == -1) |
768 |
|
|
err(1, "Reading `%s', %lld bytes to go", (char *)buf, |
769 |
|
|
(long long)bufleft); |
770 |
|
|
else if (nread != chunk) |
771 |
|
|
errx(1, "Reading `%s', %lld bytes to go, " |
772 |
|
|
"read %zd bytes, expected %ju bytes, does " |
773 |
|
|
"metalog size= attribute mismatch source size?", |
774 |
|
|
(char *)buf, (long long)bufleft, nread, |
775 |
|
|
(uintmax_t)chunk); |
776 |
|
|
else |
777 |
|
|
p = fbuf; |
778 |
|
|
offset = DIP(din, size) - bufleft; |
779 |
|
|
/* |
780 |
|
|
* XXX if holey support is desired, do the check here |
781 |
|
|
* |
782 |
|
|
* XXX might need to write out last bit in fragroundup |
783 |
|
|
* sized chunk. however, ffs_balloc() handles this for us |
784 |
|
|
*/ |
785 |
|
|
errno = ffs_balloc(&in, offset, chunk, &bp); |
786 |
|
|
bad_ffs_write_file: |
787 |
|
|
if (errno != 0) |
788 |
|
|
err(1, |
789 |
|
|
"Writing inode %d (%s), bytes %lld + %lld", |
790 |
|
|
ino, |
791 |
|
|
isfile ? (char *)buf : |
792 |
|
|
inode_type(DIP(din, mode) & S_IFMT), |
793 |
|
|
(long long)offset, (long long)chunk); |
794 |
|
|
memcpy(bp->b_data, p, chunk); |
795 |
|
|
errno = bwrite(bp); |
796 |
|
|
if (errno != 0) |
797 |
|
|
goto bad_ffs_write_file; |
798 |
|
|
if (!isfile) |
799 |
|
|
p += chunk; |
800 |
|
|
} |
801 |
|
|
|
802 |
|
|
write_inode_and_leave: |
803 |
|
|
ffs_write_inode(&in.i_din, in.i_number, fsopts); |
804 |
|
|
|
805 |
|
|
leave_ffs_write_file: |
806 |
|
|
if (fbuf) |
807 |
|
|
free(fbuf); |
808 |
|
|
if (ffd != -1) |
809 |
|
|
close(ffd); |
810 |
|
|
} |
811 |
|
|
|
812 |
|
|
|
813 |
|
|
static void |
814 |
|
|
ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node) |
815 |
|
|
{ |
816 |
|
|
struct direct de, *dp; |
817 |
|
|
uint16_t llen; |
818 |
|
|
u_char *newbuf; |
819 |
|
|
|
820 |
|
|
assert (dbuf != NULL); |
821 |
|
|
assert (name != NULL); |
822 |
|
|
assert (node != NULL); |
823 |
|
|
/* create direct entry */ |
824 |
|
|
(void)memset(&de, 0, sizeof(de)); |
825 |
|
|
de.d_ino = node->inode->ino; |
826 |
|
|
de.d_type = IFTODT(node->type); |
827 |
|
|
de.d_namlen = (uint8_t)strlen(name); |
828 |
|
|
strlcpy(de.d_name, name, sizeof de.d_name); |
829 |
|
|
de.d_reclen = DIRSIZ(NEWDIRFMT, &de); |
830 |
|
|
|
831 |
|
|
dp = (struct direct *)(dbuf->buf + dbuf->cur); |
832 |
|
|
llen = 0; |
833 |
|
|
if (dp != NULL) |
834 |
|
|
llen = DIRSIZ(NEWDIRFMT, dp); |
835 |
|
|
|
836 |
|
|
if (de.d_reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) { |
837 |
|
|
newbuf = erealloc(dbuf->buf, dbuf->size + DIRBLKSIZ); |
838 |
|
|
dbuf->buf = newbuf; |
839 |
|
|
dbuf->size += DIRBLKSIZ; |
840 |
|
|
memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ); |
841 |
|
|
dbuf->cur = dbuf->size - DIRBLKSIZ; |
842 |
|
|
} else if (dp) { /* shrink end of previous */ |
843 |
|
|
dp->d_reclen = llen; |
844 |
|
|
dbuf->cur += llen; |
845 |
|
|
} |
846 |
|
|
dp = (struct direct *)(dbuf->buf + dbuf->cur); |
847 |
|
|
memcpy(dp, &de, de.d_reclen); |
848 |
|
|
dp->d_reclen = dbuf->size - dbuf->cur; |
849 |
|
|
} |
850 |
|
|
|
851 |
|
|
/* |
852 |
|
|
* cribbed from sys/ufs/ffs/ffs_alloc.c |
853 |
|
|
*/ |
854 |
|
|
static void |
855 |
|
|
ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts) |
856 |
|
|
{ |
857 |
|
|
char *buf; |
858 |
|
|
struct ufs1_dinode *dp1; |
859 |
|
|
struct ufs2_dinode *dp2, *dip; |
860 |
|
|
struct cg *cgp; |
861 |
|
|
struct fs *fs; |
862 |
|
|
int cg, cgino, i; |
863 |
|
|
daddr_t d; |
864 |
|
|
char sbbuf[FFS_MAXBSIZE]; |
865 |
|
|
uint32_t initediblk; |
866 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
867 |
|
|
|
868 |
|
|
assert (dp != NULL); |
869 |
|
|
assert (ino > 0); |
870 |
|
|
assert (fsopts != NULL); |
871 |
|
|
assert (ffs_opts != NULL); |
872 |
|
|
|
873 |
|
|
fs = (struct fs *)fsopts->superblock; |
874 |
|
|
cg = ino_to_cg(fs, ino); |
875 |
|
|
cgino = ino % fs->fs_ipg; |
876 |
|
|
|
877 |
|
|
ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, |
878 |
|
|
fsopts); |
879 |
|
|
cgp = (struct cg *)sbbuf; |
880 |
|
|
if (!cg_chkmagic(cgp)) |
881 |
|
|
errx(1, "ffs_write_inode: cg %d: bad magic number", cg); |
882 |
|
|
|
883 |
|
|
assert (isclr(cg_inosused(cgp), cgino)); |
884 |
|
|
|
885 |
|
|
buf = emalloc(fs->fs_bsize); |
886 |
|
|
dp1 = (struct ufs1_dinode *)buf; |
887 |
|
|
dp2 = (struct ufs2_dinode *)buf; |
888 |
|
|
|
889 |
|
|
if (fs->fs_cstotal.cs_nifree == 0) |
890 |
|
|
errx(1, "ffs_write_inode: fs out of inodes for ino %u", |
891 |
|
|
ino); |
892 |
|
|
if (fs->fs_cs(fs, cg).cs_nifree == 0) |
893 |
|
|
errx(1, |
894 |
|
|
"ffs_write_inode: cg %d out of inodes for ino %u", |
895 |
|
|
cg, ino); |
896 |
|
|
setbit(cg_inosused(cgp), cgino); |
897 |
|
|
cgp->cg_cs.cs_nifree -= 1; |
898 |
|
|
fs->fs_cstotal.cs_nifree--; |
899 |
|
|
fs->fs_cs(fs, cg).cs_nifree--; |
900 |
|
|
if (S_ISDIR(DIP(dp, mode))) { |
901 |
|
|
cgp->cg_cs.cs_ndir += 1; |
902 |
|
|
fs->fs_cstotal.cs_ndir++; |
903 |
|
|
fs->fs_cs(fs, cg).cs_ndir++; |
904 |
|
|
} |
905 |
|
|
|
906 |
|
|
/* |
907 |
|
|
* Initialize inode blocks on the fly for UFS2. |
908 |
|
|
*/ |
909 |
|
|
initediblk = cgp->cg_initediblk; |
910 |
|
|
if (ffs_opts->version == 2 && |
911 |
|
|
(uint32_t)(cgino + INOPB(fs)) > initediblk && |
912 |
|
|
initediblk < cgp->cg_ffs2_niblk) { |
913 |
|
|
memset(buf, 0, fs->fs_bsize); |
914 |
|
|
dip = (struct ufs2_dinode *)buf; |
915 |
|
|
for (i = 0; i < INOPB(fs); i++) { |
916 |
|
|
dip->di_gen = random() / 2 + 1; |
917 |
|
|
dip++; |
918 |
|
|
} |
919 |
|
|
ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs, |
920 |
|
|
cg * fs->fs_ipg + initediblk)), |
921 |
|
|
fs->fs_bsize, buf, fsopts); |
922 |
|
|
initediblk += INOPB(fs); |
923 |
|
|
cgp->cg_initediblk = initediblk; |
924 |
|
|
} |
925 |
|
|
|
926 |
|
|
|
927 |
|
|
ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, |
928 |
|
|
fsopts); |
929 |
|
|
|
930 |
|
|
/* now write inode */ |
931 |
|
|
d = fsbtodb(fs, ino_to_fsba(fs, ino)); |
932 |
|
|
ffs_rdfs(d, fs->fs_bsize, buf, fsopts); |
933 |
|
|
if (ffs_opts->version == 1) |
934 |
|
|
dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din; |
935 |
|
|
else |
936 |
|
|
dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din; |
937 |
|
|
ffs_wtfs(d, fs->fs_bsize, buf, fsopts); |
938 |
|
|
free(buf); |
939 |
|
|
} |