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