svn commit: r192730 - projects/jbuild/usr.bin/tar

John Birrell jb at FreeBSD.org
Mon May 25 06:36:03 UTC 2009


Author: jb
Date: Mon May 25 06:36:02 2009
New Revision: 192730
URL: http://svn.freebsd.org/changeset/base/192730

Log:
  Rough merge of the manifest file support from p4.
  
  The merged code needs to be updated to handle the change which removed
  write_entry(). Not a big deal.

Modified:
  projects/jbuild/usr.bin/tar/bsdtar.c
  projects/jbuild/usr.bin/tar/bsdtar.h
  projects/jbuild/usr.bin/tar/cmdline.c
  projects/jbuild/usr.bin/tar/write.c

Modified: projects/jbuild/usr.bin/tar/bsdtar.c
==============================================================================
--- projects/jbuild/usr.bin/tar/bsdtar.c	Mon May 25 06:33:11 2009	(r192729)
+++ projects/jbuild/usr.bin/tar/bsdtar.c	Mon May 25 06:36:02 2009	(r192730)
@@ -309,6 +309,13 @@ main(int argc, char **argv)
 		case 'm': /* SUSv2 */
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME;
 			break;
+		case OPTION_MANIFEST:
+			/* The argument is the manifest file name. */
+			bsdtar->manifest = optarg;
+
+			/* Specifying a manifest implies creating an archive. */
+			set_mode(bsdtar, 'c');
+			break;
 		case 'n': /* GNU tar */
 			bsdtar->option_no_subdirs = 1;
 			break;

Modified: projects/jbuild/usr.bin/tar/bsdtar.h
==============================================================================
--- projects/jbuild/usr.bin/tar/bsdtar.h	Mon May 25 06:33:11 2009	(r192729)
+++ projects/jbuild/usr.bin/tar/bsdtar.h	Mon May 25 06:36:02 2009	(r192730)
@@ -63,6 +63,7 @@ struct bsdtar {
 	const char	 *option_options; /* --options */
 	char		  option_honor_nodump; /* --nodump */
 	char		  option_interactive; /* -w */
+	const char	 *manifest; /* --manifest */
 	char		  option_no_owner; /* -o */
 	char		  option_no_subdirs; /* -n */
 	char		  option_null; /* --null */
@@ -116,6 +117,7 @@ enum {
 	OPTION_INCLUDE,
 	OPTION_KEEP_NEWER_FILES,
 	OPTION_LZMA,
+	OPTION_MANIFEST,
 	OPTION_NEWER_CTIME,
 	OPTION_NEWER_CTIME_THAN,
 	OPTION_NEWER_MTIME,

Modified: projects/jbuild/usr.bin/tar/cmdline.c
==============================================================================
--- projects/jbuild/usr.bin/tar/cmdline.c	Mon May 25 06:33:11 2009	(r192729)
+++ projects/jbuild/usr.bin/tar/cmdline.c	Mon May 25 06:36:02 2009	(r192730)
@@ -94,6 +94,7 @@ static struct option {
 	{ "keep-old-files",       0, 'k' },
 	{ "list",                 0, 't' },
 	{ "lzma",                 0, OPTION_LZMA },
+	{ "manifest",             1, OPTION_MANIFEST },
 	{ "modification-time",    0, 'm' },
 	{ "newer",		  1, OPTION_NEWER_CTIME },
 	{ "newer-ctime",	  1, OPTION_NEWER_CTIME },

Modified: projects/jbuild/usr.bin/tar/write.c
==============================================================================
--- projects/jbuild/usr.bin/tar/write.c	Mon May 25 06:33:11 2009	(r192729)
+++ projects/jbuild/usr.bin/tar/write.c	Mon May 25 06:36:02 2009	(r192730)
@@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 #endif
 
+#include <ctype.h>
 #include "bsdtar.h"
 #include "tree.h"
 
@@ -126,6 +127,8 @@ static void		 archive_names_from_file(st
 			     struct archive *a);
 static int		 archive_names_from_file_helper(struct bsdtar *bsdtar,
 			     const char *line);
+static void		 archive_names_from_manifest(struct bsdtar *bsdtar,
+			     struct archive *a);
 static int		 copy_file_data(struct bsdtar *bsdtar,
 			     struct archive *a, struct archive *ina);
 static int		 new_enough(struct bsdtar *, const char *path,
@@ -145,7 +148,8 @@ tar_mode_c(struct bsdtar *bsdtar)
 	struct archive *a;
 	int r;
 
-	if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
+	if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL &&
+	    bsdtar->manifest == NULL)
 		bsdtar_errc(bsdtar, 1, 0, "no files or directories specified");
 
 	a = archive_write_new();
@@ -431,6 +435,9 @@ write_archive(struct archive *a, struct 
 	if (bsdtar->names_from_file != NULL)
 		archive_names_from_file(bsdtar, a);
 
+	if (bsdtar->manifest != NULL)
+		archive_names_from_manifest(bsdtar, a);
+
 	while (*bsdtar->argv) {
 		arg = *bsdtar->argv;
 		if (arg[0] == '-' && arg[1] == 'C') {
@@ -518,6 +525,214 @@ archive_names_from_file(struct bsdtar *b
 		    "directory expected after -C");
 }
 
+/*
+ * Expand a file name from a manifest file.
+ */
+static void
+manifest_expand_name(struct bsdtar *bsdtar, const char *src, char *dst,
+    size_t s_dst)
+{
+	char *pdst = dst;
+	char *p;
+	char env[64];
+	const char *psrc = src;
+	size_t len;
+
+	while (*psrc != '\0' && s_dst > 1) {
+		/* %% expands to % */
+		if (*psrc == '%' && *(psrc + 1) == '%') {
+			*pdst++ = *psrc++;
+			s_dst--;
+			psrc++;
+
+		/* %FOO% is an environment variable called FOO */
+		} else if (*psrc == '%') {
+			psrc++;
+
+			/* Expect a trailing % */
+			if ((p = strchr(psrc, '%')) == NULL)
+				bsdtar_errc(bsdtar, 1, 0,
+				    "Unterminated environment variable "
+				    "name in '%s'", src);
+
+			/* Check for overlength environment variable names. */
+			if ((len = (size_t)(p - psrc)) > sizeof(env))
+				bsdtar_errc(bsdtar, 1, 0,
+				    "Environment variable name is too"
+				    "long in '%s'", src);
+
+			/* Copy the environment variable name and zero terminate it. */
+			strncpy(env, psrc, len);
+			env[len] = '\0';
+			psrc = p + 1;
+
+			/* Get the environment variable string. */
+			if ((p = getenv(env)) == NULL)
+				bsdtar_errc(bsdtar, 1, 0,
+				    "Environment variable '%s' is undefined",
+				    env);
+
+			/* Copy the environment variable string into the buffer. */
+			while (*p != '\0' && s_dst > 1) {
+				*pdst++ = *p++;
+				s_dst--;
+			}
+		} else {
+			/* Copy all other characters as-is. */
+			*pdst++ = *psrc++;
+			s_dst--;
+		}
+	}
+	*pdst = '\0';
+
+	/* Expect all the source characters to have been consumed. */
+	if (*psrc != '\0')
+		bsdtar_errc(bsdtar, 1, 0,
+		    "Destination string not large enough to expand '%s'", src);
+}
+
+/*
+ * Read and parse a manifest file.
+ */
+static void
+manifest_read(struct bsdtar *bsdtar, const char *manifest_name)
+{
+	FILE *f;
+	char *bp;
+	char *bufr;
+	char *p;
+	long offset;
+	size_t s_bufr = 1024;
+
+	if ((f = fopen(manifest_name, "r")) == NULL)
+		bsdtar_errc(bsdtar, 1, errno, "Couldn't open manifest %s", manifest_name);
+
+	if ((bufr = malloc(s_bufr)) == NULL)
+		bsdtar_errc(bsdtar, 1, errno, "Couldn't allocate memory for manifest buffer");
+
+	while (1) {
+		int f_eval = 0;
+		int f_include = 0;
+		char *p_arg = NULL;
+		char *p_gid = NULL;
+		char *p_mode = NULL;
+		char *p_store = NULL;
+		char *p_symlink = NULL;
+		char *p_uid = NULL;
+		struct stat fs;
+
+		/* Save the file offset in case we need to reallocate the buffer. */
+		if ((offset = ftell(f)) < 0)
+			bsdtar_errc(bsdtar, 1, errno, "Couldn't get manifest file offset");
+
+		if (fgets(bufr, s_bufr, f) == NULL)
+			break;
+
+		/* If there isn't a new line in the buffer, we need to reallocate it. */
+		if ((p = strchr(bufr, '\n')) == NULL) {
+			s_bufr *= 2;
+			if ((bufr = realloc(bufr, s_bufr)) == NULL)
+				bsdtar_errc(bsdtar, 1, errno,
+				    "Couldn't allocate memory for manifest buffer");
+
+			if (fseek(f, offset, SEEK_SET) == -1)
+				bsdtar_errc(bsdtar, 1, errno,
+				    "Couldn't seek to offset in manifest file");
+			continue;
+		}
+
+		/* Ignore comments. */
+		if (*bufr == '#')
+			continue;
+
+		/* Remove the trailing new line character. */
+		*p = '\0';
+		bp = bufr;
+
+		while (*bp != '\0' && isspace(*bp))
+			bp++;
+
+		/* Ignore empty lines. */
+		if (*bufr == '\0')
+			continue;
+
+		/* Parse the buffer into white-space separated fields. */
+		while ((p = strsep(&bp, " \t")) != NULL) {
+			if (strcmp(p, "%EVAL%") == 0) {
+				/* XXX */
+				f_eval = 1;
+				break;
+			} else if (strcmp(p, "%INCLUDE%") == 0)
+				f_include = 1;
+			else if (strncmp(p, "gid=", 4) == 0)
+				p_gid = p + 4;
+			else if (strncmp(p, "mode=", 5) == 0)
+				p_mode = p + 5;
+			else if (strncmp(p, "store=", 6) == 0)
+				p_store = p + 6;
+			else if (strncmp(p, "symlink=", 8) == 0)
+				p_symlink = p + 8;
+			else if (strncmp(p, "uid=", 4) == 0)
+				p_uid = p + 4;
+			else if (strncmp(p, "no_", 3) == 0)
+				printf("No code for: %s\n", p);
+			else
+				p_arg = p;
+		}
+
+		if (f_eval)
+			; /* XXX EVAL is not supported */
+		else if (f_include)
+			manifest_read(bsdtar, p_arg);
+		else if (p_store != NULL) {
+			char fname[MAXNAMLEN];
+
+			manifest_expand_name(bsdtar, p_arg, fname, sizeof(fname));
+
+			if (stat(fname, &fs) != 0)
+				bsdtar_errc(bsdtar, 1, errno,
+				    "Couldn't get file status of '%s'", fname);
+
+			/* Reset the user/group by default. */
+			fs.st_uid = 0;
+			fs.st_gid = 0;
+
+			if (p_gid != NULL)
+				fs.st_gid = atoi(p_gid);
+
+			if (p_uid != NULL)
+				fs.st_uid = atoi(p_uid);
+
+			if (p_mode != NULL) {
+				fs.st_mode &= ~0777;
+				fs.st_mode |= strtol(p_mode, NULL, 8);
+			}
+
+			/* write_entry_backend(bsdtar, bsdtar->archive, &fs, p_store, fname); */
+		} else if (p_symlink != NULL)
+			printf("Symlink: %s\n", p_symlink);
+		else {
+			printf("Dunno: %s\n", p_arg);
+		}
+	}
+
+	free(bufr);
+
+	fclose(f);
+}
+
+/*
+ * Archive names specified in a manifest file.
+ */
+static void
+archive_names_from_manifest(struct bsdtar *bsdtar, struct archive *a)
+{
+	bsdtar->archive = a;
+
+	/* Read and parse the top-level manifest file. */
+	manifest_read(bsdtar, bsdtar->manifest);
+}
+
 static int
 archive_names_from_file_helper(struct bsdtar *bsdtar, const char *line)
 {


More information about the svn-src-projects mailing list