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