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