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