xref: /minix3/usr.sbin/makefs/msdos.c (revision 9f988b79349f9b89ecc822458c30ec8897558560)
1*9f988b79SJean-Baptiste Boric /*	$NetBSD: msdos.c,v 1.14 2013/02/03 03:21:21 christos Exp $	*/
2*9f988b79SJean-Baptiste Boric 
3*9f988b79SJean-Baptiste Boric /*-
4*9f988b79SJean-Baptiste Boric  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5*9f988b79SJean-Baptiste Boric  * All rights reserved.
6*9f988b79SJean-Baptiste Boric  *
7*9f988b79SJean-Baptiste Boric  * This code is derived from software contributed to The NetBSD Foundation
8*9f988b79SJean-Baptiste Boric  * by Christos Zoulas.
9*9f988b79SJean-Baptiste Boric  *
10*9f988b79SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
11*9f988b79SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
12*9f988b79SJean-Baptiste Boric  * are met:
13*9f988b79SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
14*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
15*9f988b79SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
16*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in the
17*9f988b79SJean-Baptiste Boric  *    documentation and/or other materials provided with the distribution.
18*9f988b79SJean-Baptiste Boric  * 3. Neither the name of The NetBSD Foundation nor the names of its
19*9f988b79SJean-Baptiste Boric  *    contributors may be used to endorse or promote products derived
20*9f988b79SJean-Baptiste Boric  *    from this software without specific prior written permission.
21*9f988b79SJean-Baptiste Boric  *
22*9f988b79SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23*9f988b79SJean-Baptiste Boric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24*9f988b79SJean-Baptiste Boric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25*9f988b79SJean-Baptiste Boric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26*9f988b79SJean-Baptiste Boric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27*9f988b79SJean-Baptiste Boric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28*9f988b79SJean-Baptiste Boric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29*9f988b79SJean-Baptiste Boric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30*9f988b79SJean-Baptiste Boric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31*9f988b79SJean-Baptiste Boric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32*9f988b79SJean-Baptiste Boric  * POSSIBILITY OF SUCH DAMAGE.
33*9f988b79SJean-Baptiste Boric  */
34*9f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
35*9f988b79SJean-Baptiste Boric #include "nbtool_config.h"
36*9f988b79SJean-Baptiste Boric #endif
37*9f988b79SJean-Baptiste Boric 
38*9f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
39*9f988b79SJean-Baptiste Boric #if defined(__RCSID) && !defined(__lint)
40*9f988b79SJean-Baptiste Boric __RCSID("$NetBSD: msdos.c,v 1.14 2013/02/03 03:21:21 christos Exp $");
41*9f988b79SJean-Baptiste Boric #endif	/* !__lint */
42*9f988b79SJean-Baptiste Boric 
43*9f988b79SJean-Baptiste Boric #include <sys/param.h>
44*9f988b79SJean-Baptiste Boric 
45*9f988b79SJean-Baptiste Boric #if !HAVE_NBTOOL_CONFIG_H
46*9f988b79SJean-Baptiste Boric #include <sys/mount.h>
47*9f988b79SJean-Baptiste Boric #endif
48*9f988b79SJean-Baptiste Boric 
49*9f988b79SJean-Baptiste Boric #include <assert.h>
50*9f988b79SJean-Baptiste Boric #include <errno.h>
51*9f988b79SJean-Baptiste Boric #include <fcntl.h>
52*9f988b79SJean-Baptiste Boric #include <stdarg.h>
53*9f988b79SJean-Baptiste Boric #include <stdio.h>
54*9f988b79SJean-Baptiste Boric #include <stdlib.h>
55*9f988b79SJean-Baptiste Boric #include <string.h>
56*9f988b79SJean-Baptiste Boric #include <unistd.h>
57*9f988b79SJean-Baptiste Boric #include <dirent.h>
58*9f988b79SJean-Baptiste Boric #include <util.h>
59*9f988b79SJean-Baptiste Boric 
60*9f988b79SJean-Baptiste Boric #include <ffs/buf.h>
61*9f988b79SJean-Baptiste Boric #include <fs/msdosfs/denode.h>
62*9f988b79SJean-Baptiste Boric #include "makefs.h"
63*9f988b79SJean-Baptiste Boric #include "msdos.h"
64*9f988b79SJean-Baptiste Boric #include "mkfs_msdos.h"
65*9f988b79SJean-Baptiste Boric 
66*9f988b79SJean-Baptiste Boric static int msdos_populate_dir(const char *, struct denode *, fsnode *,
67*9f988b79SJean-Baptiste Boric     fsnode *, fsinfo_t *);
68*9f988b79SJean-Baptiste Boric 
69*9f988b79SJean-Baptiste Boric void
msdos_prep_opts(fsinfo_t * fsopts)70*9f988b79SJean-Baptiste Boric msdos_prep_opts(fsinfo_t *fsopts)
71*9f988b79SJean-Baptiste Boric {
72*9f988b79SJean-Baptiste Boric 	struct msdos_options *msdos_opt = ecalloc(1, sizeof(*msdos_opt));
73*9f988b79SJean-Baptiste Boric 	const option_t msdos_options[] = {
74*9f988b79SJean-Baptiste Boric #define AOPT(_opt, _type, _name, _min, _desc) { 			\
75*9f988b79SJean-Baptiste Boric 	.letter = _opt,							\
76*9f988b79SJean-Baptiste Boric 	.name = # _name,						\
77*9f988b79SJean-Baptiste Boric 	.type = _min == -1 ? OPT_STRPTR :				\
78*9f988b79SJean-Baptiste Boric 	    (_min == -2 ? OPT_BOOL :					\
79*9f988b79SJean-Baptiste Boric 	    (sizeof(_type) == 1 ? OPT_INT8 :				\
80*9f988b79SJean-Baptiste Boric 	    (sizeof(_type) == 2 ? OPT_INT16 :				\
81*9f988b79SJean-Baptiste Boric 	    (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))),		\
82*9f988b79SJean-Baptiste Boric 	.value = &msdos_opt->_name,					\
83*9f988b79SJean-Baptiste Boric 	.minimum = _min,						\
84*9f988b79SJean-Baptiste Boric 	.maximum = sizeof(_type) == 1 ? 0xff :				\
85*9f988b79SJean-Baptiste Boric 	    (sizeof(_type) == 2 ? 0xffff :				\
86*9f988b79SJean-Baptiste Boric 	    (sizeof(_type) == 4 ? 0xffffffff : 0xffffffffffffffffLL)),	\
87*9f988b79SJean-Baptiste Boric 	.desc = _desc,						\
88*9f988b79SJean-Baptiste Boric },
89*9f988b79SJean-Baptiste Boric ALLOPTS
90*9f988b79SJean-Baptiste Boric #undef AOPT
91*9f988b79SJean-Baptiste Boric 		{ .name = NULL }
92*9f988b79SJean-Baptiste Boric 	};
93*9f988b79SJean-Baptiste Boric 
94*9f988b79SJean-Baptiste Boric 	fsopts->fs_specific = msdos_opt;
95*9f988b79SJean-Baptiste Boric 	fsopts->fs_options = copy_opts(msdos_options);
96*9f988b79SJean-Baptiste Boric }
97*9f988b79SJean-Baptiste Boric 
98*9f988b79SJean-Baptiste Boric void
msdos_cleanup_opts(fsinfo_t * fsopts)99*9f988b79SJean-Baptiste Boric msdos_cleanup_opts(fsinfo_t *fsopts)
100*9f988b79SJean-Baptiste Boric {
101*9f988b79SJean-Baptiste Boric 	free(fsopts->fs_specific);
102*9f988b79SJean-Baptiste Boric 	free(fsopts->fs_options);
103*9f988b79SJean-Baptiste Boric }
104*9f988b79SJean-Baptiste Boric 
105*9f988b79SJean-Baptiste Boric int
msdos_parse_opts(const char * option,fsinfo_t * fsopts)106*9f988b79SJean-Baptiste Boric msdos_parse_opts(const char *option, fsinfo_t *fsopts)
107*9f988b79SJean-Baptiste Boric {
108*9f988b79SJean-Baptiste Boric 	struct msdos_options *msdos_opt = fsopts->fs_specific;
109*9f988b79SJean-Baptiste Boric 	option_t *msdos_options = fsopts->fs_options;
110*9f988b79SJean-Baptiste Boric 
111*9f988b79SJean-Baptiste Boric 	int rv;
112*9f988b79SJean-Baptiste Boric 
113*9f988b79SJean-Baptiste Boric 	assert(option != NULL);
114*9f988b79SJean-Baptiste Boric 	assert(fsopts != NULL);
115*9f988b79SJean-Baptiste Boric 	assert(msdos_opt != NULL);
116*9f988b79SJean-Baptiste Boric 
117*9f988b79SJean-Baptiste Boric 	if (debug & DEBUG_FS_PARSE_OPTS)
118*9f988b79SJean-Baptiste Boric 		printf("msdos_parse_opts: got `%s'\n", option);
119*9f988b79SJean-Baptiste Boric 
120*9f988b79SJean-Baptiste Boric 	rv = set_option(msdos_options, option, NULL, 0);
121*9f988b79SJean-Baptiste Boric 	if (rv == -1)
122*9f988b79SJean-Baptiste Boric 		return rv;
123*9f988b79SJean-Baptiste Boric 
124*9f988b79SJean-Baptiste Boric 	if (strcmp(msdos_options[rv].name, "volume_id") == 0)
125*9f988b79SJean-Baptiste Boric 		msdos_opt->volume_id_set = 1;
126*9f988b79SJean-Baptiste Boric 	else if (strcmp(msdos_options[rv].name, "media_descriptor") == 0)
127*9f988b79SJean-Baptiste Boric 		msdos_opt->media_descriptor_set = 1;
128*9f988b79SJean-Baptiste Boric 	else if (strcmp(msdos_options[rv].name, "hidden_sectors") == 0)
129*9f988b79SJean-Baptiste Boric 		msdos_opt->hidden_sectors_set = 1;
130*9f988b79SJean-Baptiste Boric 	return 1;
131*9f988b79SJean-Baptiste Boric }
132*9f988b79SJean-Baptiste Boric 
133*9f988b79SJean-Baptiste Boric 
134*9f988b79SJean-Baptiste Boric void
msdos_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)135*9f988b79SJean-Baptiste Boric msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
136*9f988b79SJean-Baptiste Boric {
137*9f988b79SJean-Baptiste Boric 	struct msdos_options *msdos_opt = fsopts->fs_specific;
138*9f988b79SJean-Baptiste Boric 	struct vnode vp, rootvp;
139*9f988b79SJean-Baptiste Boric 	struct timeval	start;
140*9f988b79SJean-Baptiste Boric 	struct msdosfsmount *pmp;
141*9f988b79SJean-Baptiste Boric 
142*9f988b79SJean-Baptiste Boric 	assert(image != NULL);
143*9f988b79SJean-Baptiste Boric 	assert(dir != NULL);
144*9f988b79SJean-Baptiste Boric 	assert(root != NULL);
145*9f988b79SJean-Baptiste Boric 	assert(fsopts != NULL);
146*9f988b79SJean-Baptiste Boric 
147*9f988b79SJean-Baptiste Boric 	/*
148*9f988b79SJean-Baptiste Boric 	 * XXX: pick up other options from the msdos specific ones?
149*9f988b79SJean-Baptiste Boric 	 * Is minsize right here?
150*9f988b79SJean-Baptiste Boric 	 */
151*9f988b79SJean-Baptiste Boric 	msdos_opt->create_size = MAX(msdos_opt->create_size, fsopts->minsize);
152*9f988b79SJean-Baptiste Boric 	msdos_opt->offset = fsopts->offset;
153*9f988b79SJean-Baptiste Boric 	if (msdos_opt->bytes_per_sector == 0) {
154*9f988b79SJean-Baptiste Boric 		if (fsopts->sectorsize == -1)
155*9f988b79SJean-Baptiste Boric 			fsopts->sectorsize = 512;
156*9f988b79SJean-Baptiste Boric 		msdos_opt->bytes_per_sector = fsopts->sectorsize;
157*9f988b79SJean-Baptiste Boric 	} else if (fsopts->sectorsize == -1) {
158*9f988b79SJean-Baptiste Boric 		fsopts->sectorsize = msdos_opt->bytes_per_sector;
159*9f988b79SJean-Baptiste Boric 	} else if (fsopts->sectorsize != msdos_opt->bytes_per_sector) {
160*9f988b79SJean-Baptiste Boric 		err(1, "inconsistent sectorsize -S %u"
161*9f988b79SJean-Baptiste Boric 		    "!= -o bytes_per_sector %u",
162*9f988b79SJean-Baptiste Boric 		    fsopts->sectorsize, msdos_opt->bytes_per_sector);
163*9f988b79SJean-Baptiste Boric 	}
164*9f988b79SJean-Baptiste Boric 
165*9f988b79SJean-Baptiste Boric 		/* create image */
166*9f988b79SJean-Baptiste Boric 	printf("Creating `%s'\n", image);
167*9f988b79SJean-Baptiste Boric 	TIMER_START(start);
168*9f988b79SJean-Baptiste Boric 	if (mkfs_msdos(image, NULL, msdos_opt) == -1)
169*9f988b79SJean-Baptiste Boric 		return;
170*9f988b79SJean-Baptiste Boric 	TIMER_RESULTS(start, "mkfs_msdos");
171*9f988b79SJean-Baptiste Boric 
172*9f988b79SJean-Baptiste Boric 	fsopts->fd = open(image, O_RDWR);
173*9f988b79SJean-Baptiste Boric 	vp.fs = fsopts;
174*9f988b79SJean-Baptiste Boric 
175*9f988b79SJean-Baptiste Boric 	if ((pmp = msdosfs_mount(&vp, 0)) == NULL)
176*9f988b79SJean-Baptiste Boric 		err(1, "msdosfs_mount");
177*9f988b79SJean-Baptiste Boric 
178*9f988b79SJean-Baptiste Boric 	if (msdosfs_root(pmp, &rootvp) != 0)
179*9f988b79SJean-Baptiste Boric 		err(1, "msdosfs_root");
180*9f988b79SJean-Baptiste Boric 
181*9f988b79SJean-Baptiste Boric 	if (debug & DEBUG_FS_MAKEFS)
182*9f988b79SJean-Baptiste Boric 		printf("msdos_makefs: image %s directory %s root %p\n",
183*9f988b79SJean-Baptiste Boric 		    image, dir, root);
184*9f988b79SJean-Baptiste Boric 
185*9f988b79SJean-Baptiste Boric 		/* populate image */
186*9f988b79SJean-Baptiste Boric 	printf("Populating `%s'\n", image);
187*9f988b79SJean-Baptiste Boric 	TIMER_START(start);
188*9f988b79SJean-Baptiste Boric 	if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1)
189*9f988b79SJean-Baptiste Boric 		errx(1, "Image file `%s' not created.", image);
190*9f988b79SJean-Baptiste Boric 	TIMER_RESULTS(start, "msdos_populate_dir");
191*9f988b79SJean-Baptiste Boric 
192*9f988b79SJean-Baptiste Boric 	if (debug & DEBUG_FS_MAKEFS)
193*9f988b79SJean-Baptiste Boric 		putchar('\n');
194*9f988b79SJean-Baptiste Boric 
195*9f988b79SJean-Baptiste Boric 		/* ensure no outstanding buffers remain */
196*9f988b79SJean-Baptiste Boric 	if (debug & DEBUG_FS_MAKEFS)
197*9f988b79SJean-Baptiste Boric 		bcleanup();
198*9f988b79SJean-Baptiste Boric 
199*9f988b79SJean-Baptiste Boric 	printf("Image `%s' complete\n", image);
200*9f988b79SJean-Baptiste Boric }
201*9f988b79SJean-Baptiste Boric 
202*9f988b79SJean-Baptiste Boric static int
msdos_populate_dir(const char * path,struct denode * dir,fsnode * root,fsnode * parent,fsinfo_t * fsopts)203*9f988b79SJean-Baptiste Boric msdos_populate_dir(const char *path, struct denode *dir, fsnode *root,
204*9f988b79SJean-Baptiste Boric     fsnode *parent, fsinfo_t *fsopts)
205*9f988b79SJean-Baptiste Boric {
206*9f988b79SJean-Baptiste Boric 	fsnode *cur;
207*9f988b79SJean-Baptiste Boric 	char pbuf[MAXPATHLEN];
208*9f988b79SJean-Baptiste Boric 
209*9f988b79SJean-Baptiste Boric 	assert(dir != NULL);
210*9f988b79SJean-Baptiste Boric 	assert(root != NULL);
211*9f988b79SJean-Baptiste Boric 	assert(fsopts != NULL);
212*9f988b79SJean-Baptiste Boric 
213*9f988b79SJean-Baptiste Boric 	for (cur = root->next; cur != NULL; cur = cur->next) {
214*9f988b79SJean-Baptiste Boric 		if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path,
215*9f988b79SJean-Baptiste Boric 		    cur->name) >= sizeof(pbuf)) {
216*9f988b79SJean-Baptiste Boric 			warnx("path %s too long", pbuf);
217*9f988b79SJean-Baptiste Boric 			return -1;
218*9f988b79SJean-Baptiste Boric 		}
219*9f988b79SJean-Baptiste Boric 
220*9f988b79SJean-Baptiste Boric 		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
221*9f988b79SJean-Baptiste Boric 			cur->inode->flags |= FI_ALLOCATED;
222*9f988b79SJean-Baptiste Boric 			if (cur != root) {
223*9f988b79SJean-Baptiste Boric 				fsopts->curinode++;
224*9f988b79SJean-Baptiste Boric 				cur->inode->ino = fsopts->curinode;
225*9f988b79SJean-Baptiste Boric 				cur->parent = parent;
226*9f988b79SJean-Baptiste Boric 			}
227*9f988b79SJean-Baptiste Boric 		}
228*9f988b79SJean-Baptiste Boric 
229*9f988b79SJean-Baptiste Boric 		if (cur->inode->flags & FI_WRITTEN) {
230*9f988b79SJean-Baptiste Boric 			continue;	// hard link
231*9f988b79SJean-Baptiste Boric 		}
232*9f988b79SJean-Baptiste Boric 		cur->inode->flags |= FI_WRITTEN;
233*9f988b79SJean-Baptiste Boric 
234*9f988b79SJean-Baptiste Boric 		if (cur->child) {
235*9f988b79SJean-Baptiste Boric 			struct denode *de;
236*9f988b79SJean-Baptiste Boric 			if ((de = msdosfs_mkdire(pbuf, dir, cur)) == NULL) {
237*9f988b79SJean-Baptiste Boric 				warn("msdosfs_mkdire %s", pbuf);
238*9f988b79SJean-Baptiste Boric 				return -1;
239*9f988b79SJean-Baptiste Boric 			}
240*9f988b79SJean-Baptiste Boric 			if (msdos_populate_dir(pbuf, de, cur->child, cur,
241*9f988b79SJean-Baptiste Boric 			    fsopts) == -1) {
242*9f988b79SJean-Baptiste Boric 				warn("msdos_populate_dir %s", pbuf);
243*9f988b79SJean-Baptiste Boric 				return -1;
244*9f988b79SJean-Baptiste Boric 			}
245*9f988b79SJean-Baptiste Boric 			continue;
246*9f988b79SJean-Baptiste Boric 		} else if (!S_ISREG(cur->type)) {
247*9f988b79SJean-Baptiste Boric 			warnx("skipping non-regular file %s/%s", cur->path,
248*9f988b79SJean-Baptiste Boric 			    cur->name);
249*9f988b79SJean-Baptiste Boric 			continue;
250*9f988b79SJean-Baptiste Boric 		}
251*9f988b79SJean-Baptiste Boric 		if (msdosfs_mkfile(pbuf, dir, cur) == NULL) {
252*9f988b79SJean-Baptiste Boric 			warn("msdosfs_mkfile %s", pbuf);
253*9f988b79SJean-Baptiste Boric 			return -1;
254*9f988b79SJean-Baptiste Boric 		}
255*9f988b79SJean-Baptiste Boric 	}
256*9f988b79SJean-Baptiste Boric 	return 0;
257*9f988b79SJean-Baptiste Boric }
258