ffs.c revision 214921
1/*	$NetBSD: ffs.c,v 1.44 2009/04/28 22:49:26 joerg Exp $	*/
2
3/*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Luke Mewburn for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed for the NetBSD Project by
20 *      Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 *    or promote products derived from this software without specific prior
23 *    written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37/*
38 * Copyright (c) 1982, 1986, 1989, 1993
39 *	The Regents of the University of California.  All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 *	@(#)ffs_alloc.c	8.19 (Berkeley) 7/13/95
66 */
67
68#include <sys/cdefs.h>
69__FBSDID("$FreeBSD: head/usr.sbin/makefs/ffs.c 214921 2010-11-07 16:05:04Z cognet $");
70
71#include <sys/param.h>
72
73#include <sys/mount.h>
74
75#include <assert.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <stdarg.h>
79#include <stdint.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <unistd.h>
84
85#include "makefs.h"
86#include "ffs.h"
87
88#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
89#include <sys/statvfs.h>
90#endif
91
92#include <ufs/ufs/dinode.h>
93#include <ufs/ufs/dir.h>
94#include <ufs/ffs/fs.h>
95
96
97#include "ffs/ufs_bswap.h"
98#include "ffs/ufs_inode.h"
99#include "ffs/newfs_extern.h"
100#include "ffs/ffs_extern.h"
101
102#undef DIP
103#define DIP(dp, field) \
104	((ffs_opts->version == 1) ? \
105	(dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
106
107/*
108 * Various file system defaults (cribbed from newfs(8)).
109 */
110#define	DFL_FRAGSIZE		1024		/* fragment size */
111#define	DFL_BLKSIZE		8192		/* block size */
112#define	DFL_SECSIZE		512		/* sector size */
113#define	DFL_CYLSPERGROUP	65536		/* cylinders per group */
114#define	DFL_FRAGSPERINODE	4		/* fragments per inode */
115#define	DFL_ROTDELAY		0		/* rotational delay */
116#define	DFL_NRPOS		1		/* rotational positions */
117#define	DFL_RPM			3600		/* rpm of disk */
118#define	DFL_NSECTORS		64		/* # of sectors */
119#define	DFL_NTRACKS		16		/* # of tracks */
120
121
122typedef struct {
123	u_char		*buf;		/* buf for directory */
124	doff_t		size;		/* full size of buf */
125	doff_t		cur;		/* offset of current entry */
126} dirbuf_t;
127
128
129static	int	ffs_create_image(const char *, fsinfo_t *);
130static	void	ffs_dump_fsinfo(fsinfo_t *);
131static	void	ffs_dump_dirbuf(dirbuf_t *, const char *, int);
132static	void	ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int);
133static	int	ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
134static	void	ffs_size_dir(fsnode *, fsinfo_t *);
135static	void	ffs_validate(const char *, fsnode *, fsinfo_t *);
136static	void	ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *);
137static	void	ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *);
138static  void	*ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *,
139				 fsnode *, fsinfo_t *);
140static  void	*ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
141				 fsnode *, fsinfo_t *);
142
143
144
145int	sectorsize;		/* XXX: for buf.c::getblk() */
146
147	/* publically visible functions */
148
149void
150ffs_prep_opts(fsinfo_t *fsopts)
151{
152	ffs_opt_t *ffs_opts;
153
154	if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL)
155		err(1, "Allocating memory for ffs_options");
156
157	fsopts->fs_specific = ffs_opts;
158
159	ffs_opts->bsize= -1;
160	ffs_opts->fsize= -1;
161	ffs_opts->cpg= -1;
162	ffs_opts->density= -1;
163	ffs_opts->minfree= -1;
164	ffs_opts->optimization= -1;
165	ffs_opts->maxcontig= -1;
166	ffs_opts->maxbpg= -1;
167	ffs_opts->avgfilesize= -1;
168	ffs_opts->avgfpdir= -1;
169	ffs_opts->version = 1;
170}
171
172void
173ffs_cleanup_opts(fsinfo_t *fsopts)
174{
175	if (fsopts->fs_specific)
176		free(fsopts->fs_specific);
177}
178
179int
180ffs_parse_opts(const char *option, fsinfo_t *fsopts)
181{
182	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
183
184	option_t ffs_options[] = {
185		{ "bsize",	&ffs_opts->bsize,	1,	INT_MAX,
186					"block size" },
187		{ "fsize",	&ffs_opts->fsize,	1,	INT_MAX,
188					"fragment size" },
189		{ "density",	&ffs_opts->density,	1,	INT_MAX,
190					"bytes per inode" },
191		{ "minfree",	&ffs_opts->minfree,	0,	99,
192					"minfree" },
193		{ "maxbpf",	&ffs_opts->maxbpg,	1,	INT_MAX,
194					"max blocks per file in a cg" },
195		{ "avgfilesize", &ffs_opts->avgfilesize,1,	INT_MAX,
196					"expected average file size" },
197		{ "avgfpdir",	&ffs_opts->avgfpdir,	1,	INT_MAX,
198					"expected # of files per directory" },
199		{ "extent",	&ffs_opts->maxbsize,	1,	INT_MAX,
200					"maximum # extent size" },
201		{ "maxbpcg",	&ffs_opts->maxblkspercg,1,	INT_MAX,
202					"max # of blocks per group" },
203		{ "version",	&ffs_opts->version,	1,	2,
204					"UFS version" },
205		{ .name = NULL }
206	};
207
208	char	*var, *val;
209	int	rv;
210
211	assert(option != NULL);
212	assert(fsopts != NULL);
213	assert(ffs_opts != NULL);
214
215	if (debug & DEBUG_FS_PARSE_OPTS)
216		printf("ffs_parse_opts: got `%s'\n", option);
217
218	if ((var = strdup(option)) == NULL)
219		err(1, "Allocating memory for copy of option string");
220	rv = 0;
221
222	if ((val = strchr(var, '=')) == NULL) {
223		warnx("Option `%s' doesn't contain a value", var);
224		goto leave_ffs_parse_opts;
225	}
226	*val++ = '\0';
227
228	if (strcmp(var, "optimization") == 0) {
229		if (strcmp(val, "time") == 0) {
230			ffs_opts->optimization = FS_OPTTIME;
231		} else if (strcmp(val, "space") == 0) {
232			ffs_opts->optimization = FS_OPTSPACE;
233		} else {
234			warnx("Invalid optimization `%s'", val);
235			goto leave_ffs_parse_opts;
236		}
237		rv = 1;
238	} else
239		rv = set_option(ffs_options, var, val);
240
241 leave_ffs_parse_opts:
242	if (var)
243		free(var);
244	return (rv);
245}
246
247
248void
249ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
250{
251	struct fs	*superblock;
252	struct timeval	start;
253
254	assert(image != NULL);
255	assert(dir != NULL);
256	assert(root != NULL);
257	assert(fsopts != NULL);
258
259	if (debug & DEBUG_FS_MAKEFS)
260		printf("ffs_makefs: image %s directory %s root %p\n",
261		    image, dir, root);
262
263		/* validate tree and options */
264	TIMER_START(start);
265	ffs_validate(dir, root, fsopts);
266	TIMER_RESULTS(start, "ffs_validate");
267
268	printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
269	    image, (long long)fsopts->size, (long long)fsopts->inodes);
270
271		/* create image */
272	TIMER_START(start);
273	if (ffs_create_image(image, fsopts) == -1)
274		errx(1, "Image file `%s' not created.", image);
275	TIMER_RESULTS(start, "ffs_create_image");
276
277	fsopts->curinode = ROOTINO;
278
279	if (debug & DEBUG_FS_MAKEFS)
280		putchar('\n');
281
282		/* populate image */
283	printf("Populating `%s'\n", image);
284	TIMER_START(start);
285	if (! ffs_populate_dir(dir, root, fsopts))
286		errx(1, "Image file `%s' not populated.", image);
287	TIMER_RESULTS(start, "ffs_populate_dir");
288
289		/* ensure no outstanding buffers remain */
290	if (debug & DEBUG_FS_MAKEFS)
291		bcleanup();
292
293		/* update various superblock parameters */
294	superblock = fsopts->superblock;
295	superblock->fs_fmod = 0;
296	superblock->fs_old_cstotal.cs_ndir   = superblock->fs_cstotal.cs_ndir;
297	superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree;
298	superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree;
299	superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree;
300
301		/* write out superblock; image is now complete */
302	ffs_write_superblock(fsopts->superblock, fsopts);
303	if (close(fsopts->fd) == -1)
304		err(1, "Closing `%s'", image);
305	fsopts->fd = -1;
306	printf("Image `%s' complete\n", image);
307}
308
309	/* end of public functions */
310
311
312static void
313ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
314{
315	int32_t	ncg = 1;
316#if notyet
317	int32_t	spc, nspf, ncyl, fssize;
318#endif
319	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
320
321	assert(dir != NULL);
322	assert(root != NULL);
323	assert(fsopts != NULL);
324	assert(ffs_opts != NULL);
325
326	if (debug & DEBUG_FS_VALIDATE) {
327		printf("ffs_validate: before defaults set:\n");
328		ffs_dump_fsinfo(fsopts);
329	}
330
331		/* set FFS defaults */
332	if (fsopts->sectorsize == -1)
333		fsopts->sectorsize = DFL_SECSIZE;
334	if (ffs_opts->fsize == -1)
335		ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
336	if (ffs_opts->bsize == -1)
337		ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
338	if (ffs_opts->cpg == -1)
339		ffs_opts->cpg = DFL_CYLSPERGROUP;
340	else
341		ffs_opts->cpgflg = 1;
342				/* fsopts->density is set below */
343	if (ffs_opts->nsectors == -1)
344		ffs_opts->nsectors = DFL_NSECTORS;
345	if (ffs_opts->minfree == -1)
346		ffs_opts->minfree = MINFREE;
347	if (ffs_opts->optimization == -1)
348		ffs_opts->optimization = DEFAULTOPT;
349	if (ffs_opts->maxcontig == -1)
350		ffs_opts->maxcontig =
351		    MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
352	/* XXX ondisk32 */
353	if (ffs_opts->maxbpg == -1)
354		ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
355	if (ffs_opts->avgfilesize == -1)
356		ffs_opts->avgfilesize = AVFILESIZ;
357	if (ffs_opts->avgfpdir == -1)
358		ffs_opts->avgfpdir = AFPDIR;
359
360		/* calculate size of tree */
361	ffs_size_dir(root, fsopts);
362	fsopts->inodes += ROOTINO;		/* include first two inodes */
363
364	if (debug & DEBUG_FS_VALIDATE)
365		printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n",
366		    (long long)fsopts->size, (long long)fsopts->inodes);
367
368		/* add requested slop */
369	fsopts->size += fsopts->freeblocks;
370	fsopts->inodes += fsopts->freefiles;
371	if (fsopts->freefilepc > 0)
372		fsopts->inodes =
373		    fsopts->inodes * (100 + fsopts->freefilepc) / 100;
374	if (fsopts->freeblockpc > 0)
375		fsopts->size =
376		    fsopts->size * (100 + fsopts->freeblockpc) / 100;
377
378		/* add space needed for superblocks */
379	/*
380	 * The old SBOFF (SBLOCK_UFS1) is used here because makefs is
381	 * typically used for small filesystems where space matters.
382	 * XXX make this an option.
383	 */
384	fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
385		/* add space needed to store inodes, x3 for blockmaps, etc */
386	if (ffs_opts->version == 1)
387		fsopts->size += ncg * DINODE1_SIZE *
388		    roundup(fsopts->inodes / ncg,
389			ffs_opts->bsize / DINODE1_SIZE);
390	else
391		fsopts->size += ncg * DINODE2_SIZE *
392		    roundup(fsopts->inodes / ncg,
393			ffs_opts->bsize / DINODE2_SIZE);
394
395		/* add minfree */
396	if (ffs_opts->minfree > 0)
397		fsopts->size =
398		    fsopts->size * (100 + ffs_opts->minfree) / 100;
399	/*
400	 * XXX	any other fs slop to add, such as csum's, bitmaps, etc ??
401	 */
402
403	if (fsopts->size < fsopts->minsize)	/* ensure meets minimum size */
404		fsopts->size = fsopts->minsize;
405
406		/* round up to the next block */
407	fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
408
409		/* calculate density if necessary */
410	if (ffs_opts->density == -1)
411		ffs_opts->density = fsopts->size / fsopts->inodes + 1;
412
413	if (debug & DEBUG_FS_VALIDATE) {
414		printf("ffs_validate: after defaults set:\n");
415		ffs_dump_fsinfo(fsopts);
416		printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n",
417		    dir, (long long)fsopts->size, (long long)fsopts->inodes);
418	}
419	sectorsize = fsopts->sectorsize;	/* XXX - see earlier */
420
421		/* now check calculated sizes vs requested sizes */
422	if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
423		errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
424		    dir, (long long)fsopts->size, (long long)fsopts->maxsize);
425	}
426}
427
428
429static void
430ffs_dump_fsinfo(fsinfo_t *f)
431{
432
433	ffs_opt_t	*fs = f->fs_specific;
434
435	printf("fsopts at %p\n", f);
436
437	printf("\tsize %lld, inodes %lld, curinode %u\n",
438	    (long long)f->size, (long long)f->inodes, f->curinode);
439
440	printf("\tminsize %lld, maxsize %lld\n",
441	    (long long)f->minsize, (long long)f->maxsize);
442	printf("\tfree files %lld, freefile %% %d\n",
443	    (long long)f->freefiles, f->freefilepc);
444	printf("\tfree blocks %lld, freeblock %% %d\n",
445	    (long long)f->freeblocks, f->freeblockpc);
446	printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
447
448	printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
449	    fs->bsize, fs->fsize, fs->cpg, fs->density);
450	printf("\tnsectors %d, rpm %d, minfree %d\n",
451	    fs->nsectors, fs->rpm, fs->minfree);
452	printf("\tmaxcontig %d, maxbpg %d\n",
453	    fs->maxcontig, fs->maxbpg);
454	printf("\toptimization %s\n",
455	    fs->optimization == FS_OPTSPACE ? "space" : "time");
456}
457
458
459static int
460ffs_create_image(const char *image, fsinfo_t *fsopts)
461{
462#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
463	struct statvfs	sfs;
464#endif
465	struct fs	*fs;
466	char	*buf;
467	int	i, bufsize;
468	off_t	bufrem;
469
470	assert (image != NULL);
471	assert (fsopts != NULL);
472
473		/* create image */
474	if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666))
475	    == -1) {
476		warn("Can't open `%s' for writing", image);
477		return (-1);
478	}
479
480		/* zero image */
481#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
482	if (fstatvfs(fsopts->fd, &sfs) == -1) {
483#endif
484		bufsize = 8192;
485#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
486		warn("can't fstatvfs `%s', using default %d byte chunk",
487		    image, bufsize);
488	} else
489		bufsize = sfs.f_iosize;
490#endif
491	bufrem = fsopts->size;
492	if (debug & DEBUG_FS_CREATE_IMAGE)
493		printf(
494		    "zero-ing image `%s', %lld sectors, using %d byte chunks\n",
495		    image, (long long)bufrem, bufsize);
496	if ((buf = calloc(1, bufsize)) == NULL) {
497		warn("Can't create buffer for sector");
498		return (-1);
499	}
500	while (bufrem > 0) {
501		i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
502		if (i == -1) {
503			warn("zeroing image, %lld bytes to go",
504			    (long long)bufrem);
505			free(buf);
506			return (-1);
507		}
508		bufrem -= i;
509	}
510	free(buf);
511
512		/* make the file system */
513	if (debug & DEBUG_FS_CREATE_IMAGE)
514		printf("calling mkfs(\"%s\", ...)\n", image);
515	fs = ffs_mkfs(image, fsopts);
516	fsopts->superblock = (void *)fs;
517	if (debug & DEBUG_FS_CREATE_IMAGE) {
518		time_t t;
519
520		t = (time_t)((struct fs *)fsopts->superblock)->fs_time;
521		printf("mkfs returned %p; fs_time %s",
522		    fsopts->superblock, ctime(&t));
523		printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n",
524		    (long long)fs->fs_cstotal.cs_nbfree,
525		    (long long)fs->fs_cstotal.cs_nffree,
526		    (long long)fs->fs_cstotal.cs_nifree,
527		    (long long)fs->fs_cstotal.cs_ndir);
528	}
529
530	if (fs->fs_cstotal.cs_nifree + ROOTINO < fsopts->inodes) {
531		warnx(
532		"Image file `%s' has %lld free inodes; %lld are required.",
533		    image,
534		    (long long)(fs->fs_cstotal.cs_nifree + ROOTINO),
535		    (long long)fsopts->inodes);
536		return (-1);
537	}
538	return (fsopts->fd);
539}
540
541
542static void
543ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
544{
545	struct direct	tmpdir;
546	fsnode *	node;
547	int		curdirsize, this;
548	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
549
550	/* node may be NULL (empty directory) */
551	assert(fsopts != NULL);
552	assert(ffs_opts != NULL);
553
554	if (debug & DEBUG_FS_SIZE_DIR)
555		printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
556		    (long long)fsopts->size, (long long)fsopts->inodes);
557
558#define	ADDDIRENT(e) do {						\
559	tmpdir.d_namlen = strlen((e));					\
560	this = DIRSIZ_SWAP(0, &tmpdir, 0);					\
561	if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)			\
562		printf("ADDDIRENT: was: %s (%d) this %d cur %d\n",	\
563		    e, tmpdir.d_namlen, this, curdirsize);		\
564	if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ))		\
565		curdirsize = roundup(curdirsize, DIRBLKSIZ);		\
566	curdirsize += this;						\
567	if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)			\
568		printf("ADDDIRENT: now: %s (%d) this %d cur %d\n",	\
569		    e, tmpdir.d_namlen, this, curdirsize);		\
570} while (0);
571
572	/*
573	 * XXX	this needs to take into account extra space consumed
574	 *	by indirect blocks, etc.
575	 */
576#define	ADDSIZE(x) do {							\
577	fsopts->size += roundup((x), ffs_opts->fsize);			\
578} while (0);
579
580	curdirsize = 0;
581	for (node = root; node != NULL; node = node->next) {
582		ADDDIRENT(node->name);
583		if (node == root) {			/* we're at "." */
584			assert(strcmp(node->name, ".") == 0);
585			ADDDIRENT("..");
586		} else if ((node->inode->flags & FI_SIZED) == 0) {
587				/* don't count duplicate names */
588			node->inode->flags |= FI_SIZED;
589			if (debug & DEBUG_FS_SIZE_DIR_NODE)
590				printf("ffs_size_dir: `%s' size %lld\n",
591				    node->name,
592				    (long long)node->inode->st.st_size);
593			fsopts->inodes++;
594			if (node->type == S_IFREG)
595				ADDSIZE(node->inode->st.st_size);
596			if (node->type == S_IFLNK) {
597				int	slen;
598
599				slen = strlen(node->symlink) + 1;
600				if (slen >= (ffs_opts->version == 1 ?
601						MAXSYMLINKLEN_UFS1 :
602						MAXSYMLINKLEN_UFS2))
603					ADDSIZE(slen);
604			}
605		}
606		if (node->type == S_IFDIR)
607			ffs_size_dir(node->child, fsopts);
608	}
609	ADDSIZE(curdirsize);
610
611	if (debug & DEBUG_FS_SIZE_DIR)
612		printf("ffs_size_dir: exit: size %lld inodes %lld\n",
613		    (long long)fsopts->size, (long long)fsopts->inodes);
614}
615
616static void *
617ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
618		 fsnode *root, fsinfo_t *fsopts)
619{
620	int slen;
621	void *membuf;
622
623	memset(dinp, 0, sizeof(*dinp));
624	dinp->di_mode = cur->inode->st.st_mode;
625	dinp->di_nlink = cur->inode->nlink;
626	dinp->di_size = cur->inode->st.st_size;
627	dinp->di_atime = cur->inode->st.st_atime;
628	dinp->di_mtime = cur->inode->st.st_mtime;
629	dinp->di_ctime = cur->inode->st.st_ctime;
630#if HAVE_STRUCT_STAT_ST_MTIMENSEC
631	dinp->di_atimensec = cur->inode->st.st_atimensec;
632	dinp->di_mtimensec = cur->inode->st.st_mtimensec;
633	dinp->di_ctimensec = cur->inode->st.st_ctimensec;
634#endif
635#if HAVE_STRUCT_STAT_ST_FLAGS
636	dinp->di_flags = cur->inode->st.st_flags;
637#endif
638#if HAVE_STRUCT_STAT_ST_GEN
639	dinp->di_gen = cur->inode->st.st_gen;
640#endif
641	dinp->di_uid = cur->inode->st.st_uid;
642	dinp->di_gid = cur->inode->st.st_gid;
643		/* not set: di_db, di_ib, di_blocks, di_spare */
644
645	membuf = NULL;
646	if (cur == root) {			/* "."; write dirbuf */
647		membuf = dbufp->buf;
648		dinp->di_size = dbufp->size;
649	} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
650		dinp->di_size = 0;	/* a device */
651		dinp->di_rdev =
652		    ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap);
653	} else if (S_ISLNK(cur->type)) {	/* symlink */
654		slen = strlen(cur->symlink);
655		if (slen < MAXSYMLINKLEN_UFS1) {	/* short link */
656			memcpy(dinp->di_db, cur->symlink, slen);
657		} else
658			membuf = cur->symlink;
659		dinp->di_size = slen;
660	}
661	return membuf;
662}
663
664static void *
665ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
666		 fsnode *root, fsinfo_t *fsopts)
667{
668	int slen;
669	void *membuf;
670
671	memset(dinp, 0, sizeof(*dinp));
672	dinp->di_mode = cur->inode->st.st_mode;
673	dinp->di_nlink = cur->inode->nlink;
674	dinp->di_size = cur->inode->st.st_size;
675	dinp->di_atime = cur->inode->st.st_atime;
676	dinp->di_mtime = cur->inode->st.st_mtime;
677	dinp->di_ctime = cur->inode->st.st_ctime;
678#if HAVE_STRUCT_STAT_ST_MTIMENSEC
679	dinp->di_atimensec = cur->inode->st.st_atimensec;
680	dinp->di_mtimensec = cur->inode->st.st_mtimensec;
681	dinp->di_ctimensec = cur->inode->st.st_ctimensec;
682#endif
683#if HAVE_STRUCT_STAT_ST_FLAGS
684	dinp->di_flags = cur->inode->st.st_flags;
685#endif
686#if HAVE_STRUCT_STAT_ST_GEN
687	dinp->di_gen = cur->inode->st.st_gen;
688#endif
689#if HAVE_STRUCT_STAT_BIRTHTIME
690	dinp->di_birthtime = cur->inode->st.st_birthtime;
691	dinp->di_birthnsec = cur->inode->st.st_birthtimensec;
692#endif
693	dinp->di_uid = cur->inode->st.st_uid;
694	dinp->di_gid = cur->inode->st.st_gid;
695		/* not set: di_db, di_ib, di_blocks, di_spare */
696
697	membuf = NULL;
698	if (cur == root) {			/* "."; write dirbuf */
699		membuf = dbufp->buf;
700		dinp->di_size = dbufp->size;
701	} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
702		dinp->di_size = 0;	/* a device */
703		dinp->di_rdev =
704		    ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap);
705	} else if (S_ISLNK(cur->type)) {	/* symlink */
706		slen = strlen(cur->symlink);
707		if (slen < MAXSYMLINKLEN_UFS2) {	/* short link */
708			memcpy(dinp->di_db, cur->symlink, slen);
709		} else
710			membuf = cur->symlink;
711		dinp->di_size = slen;
712	}
713	return membuf;
714}
715
716static int
717ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
718{
719	fsnode		*cur;
720	dirbuf_t	dirbuf;
721	union dinode	din;
722	void		*membuf;
723	char		path[MAXPATHLEN + 1];
724	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
725
726	assert(dir != NULL);
727	assert(root != NULL);
728	assert(fsopts != NULL);
729	assert(ffs_opts != NULL);
730
731	(void)memset(&dirbuf, 0, sizeof(dirbuf));
732
733	if (debug & DEBUG_FS_POPULATE)
734		printf("ffs_populate_dir: PASS 1  dir %s node %p\n", dir, root);
735
736		/*
737		 * pass 1: allocate inode numbers, build directory `file'
738		 */
739	for (cur = root; cur != NULL; cur = cur->next) {
740		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
741			cur->inode->flags |= FI_ALLOCATED;
742			if (cur == root && cur->parent != NULL)
743				cur->inode->ino = cur->parent->inode->ino;
744			else {
745				cur->inode->ino = fsopts->curinode;
746				fsopts->curinode++;
747			}
748		}
749		ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap);
750		if (cur == root) {		/* we're at "."; add ".." */
751			ffs_make_dirbuf(&dirbuf, "..",
752			    cur->parent == NULL ? cur : cur->parent->first,
753			    fsopts->needswap);
754			root->inode->nlink++;	/* count my parent's link */
755		} else if (cur->child != NULL)
756			root->inode->nlink++;	/* count my child's link */
757
758		/*
759		 * XXX	possibly write file and long symlinks here,
760		 *	ensuring that blocks get written before inodes?
761		 *	otoh, this isn't a real filesystem, so who
762		 *	cares about ordering? :-)
763		 */
764	}
765	if (debug & DEBUG_FS_POPULATE_DIRBUF)
766		ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap);
767
768		/*
769		 * pass 2: write out dirbuf, then non-directories at this level
770		 */
771	if (debug & DEBUG_FS_POPULATE)
772		printf("ffs_populate_dir: PASS 2  dir %s\n", dir);
773	for (cur = root; cur != NULL; cur = cur->next) {
774		if (cur->inode->flags & FI_WRITTEN)
775			continue;		/* skip hard-linked entries */
776		cur->inode->flags |= FI_WRITTEN;
777
778		if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
779		    >= sizeof(path))
780			errx(1, "Pathname too long.");
781
782		if (cur->child != NULL)
783			continue;		/* child creates own inode */
784
785				/* build on-disk inode */
786		if (ffs_opts->version == 1)
787			membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
788			    root, fsopts);
789		else
790			membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur,
791			    root, fsopts);
792
793		if (debug & DEBUG_FS_POPULATE_NODE) {
794			printf("ffs_populate_dir: writing ino %d, %s",
795			    cur->inode->ino, inode_type(cur->type));
796			if (cur->inode->nlink > 1)
797				printf(", nlink %d", cur->inode->nlink);
798			putchar('\n');
799		}
800
801		if (membuf != NULL) {
802			ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
803		} else if (S_ISREG(cur->type)) {
804			ffs_write_file(&din, cur->inode->ino, path, fsopts);
805		} else {
806			assert (! S_ISDIR(cur->type));
807			ffs_write_inode(&din, cur->inode->ino, fsopts);
808		}
809	}
810
811		/*
812		 * pass 3: write out sub-directories
813		 */
814	if (debug & DEBUG_FS_POPULATE)
815		printf("ffs_populate_dir: PASS 3  dir %s\n", dir);
816	for (cur = root; cur != NULL; cur = cur->next) {
817		if (cur->child == NULL)
818			continue;
819		if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
820		    >= sizeof(path))
821			errx(1, "Pathname too long.");
822		if (! ffs_populate_dir(path, cur->child, fsopts))
823			return (0);
824	}
825
826	if (debug & DEBUG_FS_POPULATE)
827		printf("ffs_populate_dir: DONE dir %s\n", dir);
828
829		/* cleanup */
830	if (dirbuf.buf != NULL)
831		free(dirbuf.buf);
832	return (1);
833}
834
835
836static void
837ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
838{
839	int 	isfile, ffd;
840	char	*fbuf, *p;
841	off_t	bufleft, chunk, offset;
842	ssize_t nread;
843	struct inode	in;
844	struct buf *	bp;
845	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
846
847	assert (din != NULL);
848	assert (buf != NULL);
849	assert (fsopts != NULL);
850	assert (ffs_opts != NULL);
851
852	isfile = S_ISREG(DIP(din, mode));
853	fbuf = NULL;
854	ffd = -1;
855	p = NULL;
856
857	in.i_fs = (struct fs *)fsopts->superblock;
858
859	if (debug & DEBUG_FS_WRITE_FILE) {
860		printf(
861		    "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld",
862		    ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT),
863		    (long long)DIP(din, size));
864		if (isfile)
865			printf(", file '%s'\n", (char *)buf);
866		else
867			printf(", buffer %p\n", buf);
868	}
869
870	in.i_number = ino;
871	in.i_size = DIP(din, size);
872	if (ffs_opts->version == 1)
873		memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
874		    sizeof(in.i_din.ffs1_din));
875	else
876		memcpy(&in.i_din.ffs2_din, &din->ffs2_din,
877		    sizeof(in.i_din.ffs2_din));
878	in.i_fd = fsopts->fd;
879
880	if (DIP(din, size) == 0)
881		goto write_inode_and_leave;		/* mmm, cheating */
882
883	if (isfile) {
884		if ((fbuf = malloc(ffs_opts->bsize)) == NULL)
885			err(1, "Allocating memory for write buffer");
886		if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
887			warn("Can't open `%s' for reading", (char *)buf);
888			goto leave_ffs_write_file;
889		}
890	} else {
891		p = buf;
892	}
893
894	chunk = 0;
895	for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
896		chunk = MIN(bufleft, ffs_opts->bsize);
897		if (!isfile)
898			;
899		else if ((nread = read(ffd, fbuf, chunk)) == -1)
900			err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
901			    (char *)buf, (long long)bufleft);
902		else if (nread != chunk)
903			errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
904			    "read %zd bytes, expected %ju bytes, does "
905			    "metalog size= attribute mismatch source size?",
906			    (char *)buf, (long long)bufleft, nread,
907			    (uintmax_t)chunk);
908		else
909			p = fbuf;
910		offset = DIP(din, size) - bufleft;
911		if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
912			printf(
913		"ffs_write_file: write %p offset %lld size %lld left %lld\n",
914			    p, (long long)offset,
915			    (long long)chunk, (long long)bufleft);
916	/*
917	 * XXX	if holey support is desired, do the check here
918	 *
919	 * XXX	might need to write out last bit in fragroundup
920	 *	sized chunk. however, ffs_balloc() handles this for us
921	 */
922		errno = ffs_balloc(&in, offset, chunk, &bp);
923 bad_ffs_write_file:
924		if (errno != 0)
925			err(1,
926			    "Writing inode %d (%s), bytes %lld + %lld",
927			    ino,
928			    isfile ? (char *)buf :
929			      inode_type(DIP(din, mode) & S_IFMT),
930			    (long long)offset, (long long)chunk);
931		memcpy(bp->b_data, p, chunk);
932		errno = bwrite(bp);
933		if (errno != 0)
934			goto bad_ffs_write_file;
935		brelse(bp);
936		if (!isfile)
937			p += chunk;
938	}
939
940 write_inode_and_leave:
941	ffs_write_inode(&in.i_din, in.i_number, fsopts);
942
943 leave_ffs_write_file:
944	if (fbuf)
945		free(fbuf);
946	if (ffd != -1)
947		close(ffd);
948}
949
950
951static void
952ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap)
953{
954	doff_t		i;
955	struct direct	*de;
956	uint16_t	reclen;
957
958	assert (dbuf != NULL);
959	assert (dir != NULL);
960	printf("ffs_dump_dirbuf: dir %s size %d cur %d\n",
961	    dir, dbuf->size, dbuf->cur);
962
963	for (i = 0; i < dbuf->size; ) {
964		de = (struct direct *)(dbuf->buf + i);
965		reclen = ufs_rw16(de->d_reclen, needswap);
966		printf(
967	    " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n",
968		    ufs_rw32(de->d_ino, needswap),
969		    inode_type(DTTOIF(de->d_type)), i, reclen,
970		    de->d_namlen, de->d_name);
971		i += reclen;
972		assert(reclen > 0);
973	}
974}
975
976static void
977ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
978{
979	struct direct	de, *dp;
980	uint16_t	llen, reclen;
981	u_char		*newbuf;
982
983	assert (dbuf != NULL);
984	assert (name != NULL);
985	assert (node != NULL);
986					/* create direct entry */
987	(void)memset(&de, 0, sizeof(de));
988	de.d_ino = ufs_rw32(node->inode->ino, needswap);
989	de.d_type = IFTODT(node->type);
990	de.d_namlen = (uint8_t)strlen(name);
991	strcpy(de.d_name, name);
992	reclen = DIRSIZ_SWAP(0, &de, needswap);
993	de.d_reclen = ufs_rw16(reclen, needswap);
994
995	dp = (struct direct *)(dbuf->buf + dbuf->cur);
996	llen = 0;
997	if (dp != NULL)
998		llen = DIRSIZ_SWAP(0, dp, needswap);
999
1000	if (debug & DEBUG_FS_MAKE_DIRBUF)
1001		printf(
1002		    "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n"
1003		    "  ino %d type %d reclen %d namlen %d name %.30s\n",
1004		    dbuf->size, dbuf->cur, llen,
1005		    ufs_rw32(de.d_ino, needswap), de.d_type, reclen,
1006		    de.d_namlen, de.d_name);
1007
1008	if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
1009		if (debug & DEBUG_FS_MAKE_DIRBUF)
1010			printf("ffs_make_dirbuf: growing buf to %d\n",
1011			    dbuf->size + DIRBLKSIZ);
1012		if ((newbuf = realloc(dbuf->buf, dbuf->size + DIRBLKSIZ)) == NULL)
1013			err(1, "Allocating memory for directory buffer");
1014		dbuf->buf = newbuf;
1015		dbuf->size += DIRBLKSIZ;
1016		memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
1017		dbuf->cur = dbuf->size - DIRBLKSIZ;
1018	} else if (dp) {			/* shrink end of previous */
1019		dp->d_reclen = ufs_rw16(llen,needswap);
1020		dbuf->cur += llen;
1021	}
1022	dp = (struct direct *)(dbuf->buf + dbuf->cur);
1023	memcpy(dp, &de, reclen);
1024	dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap);
1025}
1026
1027/*
1028 * cribbed from sys/ufs/ffs/ffs_alloc.c
1029 */
1030static void
1031ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
1032{
1033	char 		*buf;
1034	struct ufs1_dinode *dp1;
1035	struct ufs2_dinode *dp2, *dip;
1036	struct cg	*cgp;
1037	struct fs	*fs;
1038	int		cg, cgino, i;
1039	daddr_t		d;
1040	char		sbbuf[FFS_MAXBSIZE];
1041	int32_t		initediblk;
1042	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
1043
1044	assert (dp != NULL);
1045	assert (ino > 0);
1046	assert (fsopts != NULL);
1047	assert (ffs_opts != NULL);
1048
1049	fs = (struct fs *)fsopts->superblock;
1050	cg = ino_to_cg(fs, ino);
1051	cgino = ino % fs->fs_ipg;
1052	if (debug & DEBUG_FS_WRITE_INODE)
1053		printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n",
1054		    dp, ino, cg, cgino);
1055
1056	ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
1057	    fsopts);
1058	cgp = (struct cg *)sbbuf;
1059	if (!cg_chkmagic_swap(cgp, fsopts->needswap))
1060		errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
1061
1062	assert (isclr(cg_inosused_swap(cgp, fsopts->needswap), cgino));
1063
1064	buf = malloc(fs->fs_bsize);
1065	if (buf == NULL)
1066		errx(1, "ffs_write_inode: cg %d: can't alloc inode block", cg);
1067
1068	dp1 = (struct ufs1_dinode *)buf;
1069	dp2 = (struct ufs2_dinode *)buf;
1070
1071	if (fs->fs_cstotal.cs_nifree == 0)
1072		errx(1, "ffs_write_inode: fs out of inodes for ino %u",
1073		    ino);
1074	if (fs->fs_cs(fs, cg).cs_nifree == 0)
1075		errx(1,
1076		    "ffs_write_inode: cg %d out of inodes for ino %u",
1077		    cg, ino);
1078	setbit(cg_inosused_swap(cgp, fsopts->needswap), cgino);
1079	ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap);
1080	fs->fs_cstotal.cs_nifree--;
1081	fs->fs_cs(fs, cg).cs_nifree--;
1082	if (S_ISDIR(DIP(dp, mode))) {
1083		ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap);
1084		fs->fs_cstotal.cs_ndir++;
1085		fs->fs_cs(fs, cg).cs_ndir++;
1086	}
1087
1088	/*
1089	 * Initialize inode blocks on the fly for UFS2.
1090	 */
1091	initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
1092	if (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
1093	    initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
1094		memset(buf, 0, fs->fs_bsize);
1095		dip = (struct ufs2_dinode *)buf;
1096		srandom(time(NULL));
1097		for (i = 0; i < INOPB(fs); i++) {
1098			dip->di_gen = random() / 2 + 1;
1099			dip++;
1100		}
1101		ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,
1102				  cg * fs->fs_ipg + initediblk)),
1103		    fs->fs_bsize, buf, fsopts);
1104		initediblk += INOPB(fs);
1105		cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap);
1106	}
1107
1108
1109	ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
1110	    fsopts);
1111
1112					/* now write inode */
1113	d = fsbtodb(fs, ino_to_fsba(fs, ino));
1114	ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
1115	if (fsopts->needswap) {
1116		if (ffs_opts->version == 1)
1117			ffs_dinode1_swap(&dp->ffs1_din,
1118			    &dp1[ino_to_fsbo(fs, ino)]);
1119		else
1120			ffs_dinode2_swap(&dp->ffs2_din,
1121			    &dp2[ino_to_fsbo(fs, ino)]);
1122	} else {
1123		if (ffs_opts->version == 1)
1124			dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
1125		else
1126			dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
1127	}
1128	ffs_wtfs(d, fs->fs_bsize, buf, fsopts);
1129	free(buf);
1130}
1131
1132void
1133panic(const char *fmt, ...)
1134{
1135	va_list ap;
1136
1137	va_start(ap, fmt);
1138	vwarnx(fmt, ap);
1139	va_end(ap);
1140	exit(1);
1141}
1142