Allow contents of multiple directories to be merged to the current image.

Note this patch was submitted to NetBSD and they already adopted it.

http://mail-index.netbsd.org/source-changes/2012/01/28/msg031078.html

MFC after:	1 week
This commit is contained in:
Jung-uk Kim 2012-01-31 00:32:37 +00:00
parent 62f8a13a75
commit 688aaa098d
8 changed files with 139 additions and 63 deletions

View file

@ -472,8 +472,6 @@ cd9660_makefs(const char *image, const char *dir, fsnode *root,
return;
}
diskStructure.rootFilesystemPath = dir;
if (diskStructure.verbose_level > 0)
printf("cd9660_makefs: image %s directory %s root %p\n",
image, dir, root);
@ -1568,24 +1566,15 @@ cd9660_generate_path_table(void)
}
void
cd9660_compute_full_filename(cd9660node *node, char *buf, int level)
cd9660_compute_full_filename(cd9660node *node, char *buf)
{
cd9660node *parent;
int len;
parent = (node->rr_real_parent == NULL ?
node->parent : node->rr_real_parent);
if (parent != NULL) {
cd9660_compute_full_filename(parent, buf, level + 1);
strcat(buf, node->node->name);
} else {
/* We are at the root */
strcat(buf, diskStructure.rootFilesystemPath);
if (buf[strlen(buf) - 1] == '/')
buf[strlen(buf) - 1] = '\0';
}
if (level != 0)
strcat(buf, "/");
len = CD9660MAXPATH + 1;
len = snprintf(buf, len, "%s/%s/%s", node->node->root,
node->node->path, node->node->name);
if (len > CD9660MAXPATH)
errx(1, "Pathname too long.");
}
/* NEW filename conversion method */

View file

@ -244,8 +244,6 @@ typedef struct _iso9660_disk {
cd9660node *rootNode;
const char *rootFilesystemPath;
/* Important sector numbers here */
/* primaryDescriptor.type_l_path_table*/
int64_t primaryBigEndianTableSector;
@ -345,7 +343,7 @@ int cd9660_setup_boot_volume_descriptor(volume_descriptor *);
int cd9660_write_image(const char *image);
int cd9660_copy_file(FILE *, off_t, const char *);
void cd9660_compute_full_filename(cd9660node *, char *, int);
void cd9660_compute_full_filename(cd9660node *, char *);
int cd9660_compute_record_size(cd9660node *);
/* Debugging functions */

View file

@ -296,7 +296,7 @@ cd9660_write_file(FILE *fd, cd9660node *writenode)
inode->flags |= FI_WRITTEN;
if (writenode->node->contents == NULL)
cd9660_compute_full_filename(writenode,
temp_file_name, 0);
temp_file_name);
ret = cd9660_copy_file(fd, writenode->fileDataSector,
(writenode->node->contents != NULL) ?
writenode->node->contents : temp_file_name);

View file

@ -780,8 +780,8 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
cur->inode->flags |= FI_WRITTEN;
if (cur->contents == NULL) {
if (snprintf(path, sizeof(path), "%s/%s", dir,
cur->name) >= sizeof(path))
if (snprintf(path, sizeof(path), "%s/%s/%s", cur->root,
cur->path, cur->name) >= (int)sizeof(path))
errx(1, "Pathname too long.");
}

View file

@ -35,7 +35,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 10, 2009
.Dd January 30, 2012
.Dt MAKEFS 8
.Os
.Sh NAME
@ -58,6 +58,7 @@
.Op Fl t Ar fs-type
.Ar image-file
.Ar directory | manifest
.Op Ar extra-directory ...
.Sh DESCRIPTION
The utility
.Nm
@ -67,6 +68,15 @@ from the directory tree
.Ar directory
or from the mtree manifest
.Ar manifest .
If optional directory tree
.Ar extra-directory
is passed, then the directory tree of each argument will be merged
into the
.Ar directory
or
.Ar manifest
first before creating
.Ar image-file .
No special devices or privileges are required to perform this task.
.Pp
The options are as follows:

View file

@ -87,7 +87,7 @@ main(int argc, char *argv[])
fstype_t *fstype;
fsinfo_t fsoptions;
fsnode *root;
int ch, len;
int ch, i, len;
char *subtree;
char *specfile;
@ -241,7 +241,7 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
if (argc != 2)
if (argc < 2)
usage();
/* -x must be accompanied by -F */
@ -260,7 +260,7 @@ main(int argc, char *argv[])
case S_IFDIR: /* walk the tree */
subtree = argv[1];
TIMER_START(start);
root = walk_dir(subtree, NULL);
root = walk_dir(subtree, ".", NULL, NULL);
TIMER_RESULTS(start, "walk_dir");
break;
case S_IFREG: /* read the manifest file */
@ -274,6 +274,17 @@ main(int argc, char *argv[])
/* NOTREACHED */
}
/* append extra directory */
for (i = 2; i < argc; i++) {
if (stat(argv[i], &sb) == -1)
err(1, "Can't stat `%s'", argv[i]);
if (!S_ISDIR(sb.st_mode))
errx(1, "%s: not a directory", argv[i]);
TIMER_START(start);
root = walk_dir(argv[i], ".", NULL, root);
TIMER_RESULTS(start, "walk_dir2");
}
if (specfile) { /* apply a specfile */
TIMER_START(start);
apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
@ -282,7 +293,7 @@ main(int argc, char *argv[])
if (debug & DEBUG_DUMP_FSNODES) {
printf("\nparent: %s\n", subtree);
dump_fsnodes(".", root);
dump_fsnodes(root);
putchar('\n');
}
@ -336,7 +347,7 @@ usage(void)
"usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n"
"\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n"
"\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-x]\n"
"\t[-N userdb-dir] image-file directory | manifest\n",
"\t[-N userdb-dir] image-file directory | manifest [extra-directory ...]\n",
prog);
exit(1);
}

View file

@ -94,6 +94,8 @@ typedef struct _fsnode {
fsinode *inode; /* actual inode data */
char *symlink; /* symlink target */
char *contents; /* file to provide contents */
const char *root; /* root path */
char *path; /* directory name */
char *name; /* file name */
int flags; /* misc flags */
} fsnode;
@ -147,11 +149,11 @@ typedef struct {
void apply_specfile(const char *, const char *, fsnode *, int);
void dump_fsnodes(const char *, fsnode *);
void dump_fsnodes(fsnode *);
const char * inode_type(mode_t);
fsnode * read_mtree(const char *, fsnode *);
int set_option(option_t *, const char *, const char *);
fsnode * walk_dir(const char *, fsnode *);
fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *);
void free_fsnodes(fsnode *);
void ffs_prep_opts(fsinfo_t *);

View file

@ -57,40 +57,70 @@ __FBSDID("$FreeBSD$");
static void apply_specdir(const char *, NODE *, fsnode *, int);
static void apply_specentry(const char *, NODE *, fsnode *);
static fsnode *create_fsnode(const char *, struct stat *);
static fsnode *create_fsnode(const char *, const char *, const char *,
struct stat *);
static fsinode *link_check(fsinode *);
/*
* walk_dir --
* build a tree of fsnodes from `dir', with a parent fsnode of `parent'
* (which may be NULL for the root of the tree).
* build a tree of fsnodes from `root' and `dir', with a parent
* fsnode of `parent' (which may be NULL for the root of the tree).
* append the tree to a fsnode of `join' if it is not NULL.
* each "level" is a directory, with the "." entry guaranteed to be
* at the start of the list, and without ".." entries.
*/
fsnode *
walk_dir(const char *dir, fsnode *parent)
walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join)
{
fsnode *first, *cur, *prev;
fsnode *first, *cur, *prev, *last;
DIR *dirp;
struct dirent *dent;
char path[MAXPATHLEN + 1];
struct stat stbuf;
char *name, *rp;
int dot, len;
assert(root != NULL);
assert(dir != NULL);
len = snprintf(path, sizeof(path), "%s/%s", root, dir);
if (len >= (int)sizeof(path))
errx(1, "Pathname too long.");
if (debug & DEBUG_WALK_DIR)
printf("walk_dir: %s %p\n", dir, parent);
if ((dirp = opendir(dir)) == NULL)
err(1, "Can't opendir `%s'", dir);
first = prev = NULL;
printf("walk_dir: %s %p\n", path, parent);
if ((dirp = opendir(path)) == NULL)
err(1, "Can't opendir `%s'", path);
rp = path + strlen(root) + 1;
if (join != NULL) {
first = cur = join;
while (cur->next != NULL)
cur = cur->next;
prev = cur;
} else
first = prev = NULL;
last = prev;
while ((dent = readdir(dirp)) != NULL) {
if (strcmp(dent->d_name, "..") == 0)
continue;
name = dent->d_name;
dot = 0;
if (name[0] == '.')
switch (name[1]) {
case '\0': /* "." */
if (join != NULL)
continue;
dot = 1;
break;
case '.': /* ".." */
if (name[2] == '\0')
continue;
/* FALLTHROUGH */
default:
dot = 0;
}
if (debug & DEBUG_WALK_DIR_NODE)
printf("scanning %s/%s\n", dir, dent->d_name);
if (snprintf(path, sizeof(path), "%s/%s", dir, dent->d_name)
>= sizeof(path))
printf("scanning %s/%s/%s\n", root, dir, name);
if (snprintf(path + len, sizeof(path) - len, "/%s", name) >=
(int)sizeof(path) - len)
errx(1, "Pathname too long.");
if (lstat(path, &stbuf) == -1)
err(1, "Can't lstat `%s'", path);
@ -102,22 +132,51 @@ walk_dir(const char *dir, fsnode *parent)
}
#endif
cur = create_fsnode(dent->d_name, &stbuf);
if (join != NULL) {
cur = join->next;
for (;;) {
if (cur == NULL || strcmp(cur->name, name) == 0)
break;
if (cur == last) {
cur = NULL;
break;
}
cur = cur->next;
}
if (cur != NULL) {
if (S_ISDIR(cur->type) &&
S_ISDIR(stbuf.st_mode)) {
if (debug & DEBUG_WALK_DIR_NODE)
printf("merging %s with %p\n",
path, cur->child);
cur->child = walk_dir(root, rp, cur,
cur->child);
continue;
}
errx(1, "Can't merge %s `%s' with existing %s",
inode_type(stbuf.st_mode), path,
inode_type(cur->type));
}
}
cur = create_fsnode(root, dir, name, &stbuf);
cur->parent = parent;
if (strcmp(dent->d_name, ".") == 0) {
if (dot) {
/* ensure "." is at the start of the list */
cur->next = first;
first = cur;
if (! prev)
prev = cur;
cur->first = first;
} else { /* not "." */
if (prev)
prev->next = cur;
prev = cur;
if (!first)
first = cur;
cur->first = first;
if (S_ISDIR(cur->type)) {
cur->child = walk_dir(path, cur);
cur->child = walk_dir(root, rp, cur, NULL);
continue;
}
}
@ -147,22 +206,27 @@ walk_dir(const char *dir, fsnode *parent)
err(1, "Memory allocation error");
}
}
for (cur = first; cur != NULL; cur = cur->next)
cur->first = first;
assert(first != NULL);
if (join == NULL)
for (cur = first->next; cur != NULL; cur = cur->next)
cur->first = first;
if (closedir(dirp) == -1)
err(1, "Can't closedir `%s'", dir);
err(1, "Can't closedir `%s/%s'", root, dir);
return (first);
}
static fsnode *
create_fsnode(const char *name, struct stat *stbuf)
create_fsnode(const char *root, const char *path, const char *name,
struct stat *stbuf)
{
fsnode *cur;
if ((cur = calloc(1, sizeof(fsnode))) == NULL ||
(cur->path = strdup(path)) == NULL ||
(cur->name = strdup(name)) == NULL ||
(cur->inode = calloc(1, sizeof(fsinode))) == NULL)
err(1, "Memory allocation error");
cur->root = root;
cur->type = stbuf->st_mode & S_IFMT;
cur->inode->nlink = 1;
cur->inode->st = *stbuf;
@ -211,6 +275,7 @@ free_fsnodes(fsnode *node)
free(cur->inode);
if (cur->symlink)
free(cur->symlink);
free(cur->path);
free(cur->name);
free(cur);
}
@ -388,14 +453,16 @@ apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
stbuf.st_mtimensec = stbuf.st_atimensec =
stbuf.st_ctimensec = start_time.tv_nsec;
#endif
curfsnode = create_fsnode(curnode->name, &stbuf);
curfsnode = create_fsnode(".", ".", curnode->name,
&stbuf);
curfsnode->parent = dirnode->parent;
curfsnode->first = dirnode;
curfsnode->next = dirnode->next;
dirnode->next = curfsnode;
if (curfsnode->type == S_IFDIR) {
/* for dirs, make "." entry as well */
curfsnode->child = create_fsnode(".", &stbuf);
curfsnode->child = create_fsnode(".", ".", ".",
&stbuf);
curfsnode->child->parent = curfsnode;
curfsnode->child->first = curfsnode->child;
}
@ -503,19 +570,18 @@ apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
/*
* dump_fsnodes --
* dump the fsnodes from `cur', based in the directory `dir'
* dump the fsnodes from `cur'
*/
void
dump_fsnodes(const char *dir, fsnode *root)
dump_fsnodes(fsnode *root)
{
fsnode *cur;
char path[MAXPATHLEN + 1];
assert (dir != NULL);
printf("dump_fsnodes: %s %p\n", dir, root);
printf("dump_fsnodes: %s %p\n", root->path, root);
for (cur = root; cur != NULL; cur = cur->next) {
if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
>= sizeof(path))
if (snprintf(path, sizeof(path), "%s/%s", cur->path,
cur->name) >= (int)sizeof(path))
errx(1, "Pathname too long.");
if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
@ -534,10 +600,10 @@ dump_fsnodes(const char *dir, fsnode *root)
if (cur->child) {
assert (cur->type == S_IFDIR);
dump_fsnodes(path, cur->child);
dump_fsnodes(cur->child);
}
}
printf("dump_fsnodes: finished %s\n", dir);
printf("dump_fsnodes: finished %s/%s\n", root->path, root->name);
}