git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] git-archive: recursive prefix directory creation

From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Date
May 19, 2007, 11:37 UTC
Message-ID
<464EE169.30306@lsrfire.ath.cx>

Currently git-archive only adds a single directory entry for prefixes, e.g. for --prefix=a/b/c/ only the directory a/b/c/ would be added to the archive, not a/ nor a/b/. While tar and unzip don't seem to have a problem handling these missing entries, their omission was not intended.

This patch replaces the prefix path creation code in git-archive with calls to a new path walker similar to read_tree_recursive, named descend_leading_dirs. It calls a read_tree_fn_t function for each leading directory while descending deeper into the path (e.g. first a/, then a/b/ etc.).

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
 archive-tar.c |   11 ++---------
 archive-zip.c |   11 ++---------
 tree.c        |   45 +++++++++++++++++++++++++++++++++++++++++++++
 tree.h        |    5 +++++
 4 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/archive-tar.c b/archive-tar.c
index 33e7657..7ea396d 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -308,15 +308,8 @@ int write_tar_archive(struct archiver_args *args)
 	if (args->commit_sha1)
 		write_global_extended_header(args->commit_sha1);
 
-	if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-		char *base = xstrdup(args->base);
-		int baselen = strlen(base);
-
-		while (baselen > 0 && base[baselen - 1] == '/')
-			base[--baselen] = '\0';
-		write_tar_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-		free(base);
-	}
+	descend_leading_dirs(args->tree->object.sha1, args->base, plen,
+	                     040777, 0, write_tar_entry);
 	read_tree_recursive(args->tree, args->base, plen, 0,
 			    args->pathspec, write_tar_entry);
 	write_trailer();
diff --git a/archive-zip.c b/archive-zip.c
index 3cbf6bb..2fc22ff 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -317,15 +317,8 @@ int write_zip_archive(struct archiver_args *args)
 	zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
 	verbose = args->verbose;
 
-	if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-		char *base = xstrdup(args->base);
-		int baselen = strlen(base);
-
-		while (baselen > 0 && base[baselen - 1] == '/')
-			base[--baselen] = '\0';
-		write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-		free(base);
-	}
+	descend_leading_dirs(args->tree->object.sha1, args->base, plen,
+	                     040777, 0, write_zip_entry);
 	read_tree_recursive(args->tree, args->base, plen, 0,
 			    args->pathspec, write_zip_entry);
 	write_zip_trailer(args->commit_sha1);
diff --git a/tree.c b/tree.c
index e4a39aa..5cd1f90 100644
--- a/tree.c
+++ b/tree.c
@@ -231,3 +231,48 @@ struct tree *parse_tree_indirect(const unsigned char *sha1)
 			parse_object(obj->sha1);
 	} while (1);
 }
+
+int descend_leading_dirs(const unsigned char *sha1,
+                         const char *path, size_t pathlen,
+                         unsigned int mode, int stage, read_tree_fn_t fn)
+{
+	int err;
+	size_t baselen;
+
+	if (!path)
+		return 0;
+
+	/* Discard file name part. */
+	while (pathlen > 0 && path[pathlen - 1] != '/')
+		pathlen--;
+	while (pathlen > 0 && path[pathlen - 1] == '/')
+		pathlen--;
+	if (pathlen == 0)
+		return 0;
+
+	/* Now separate base and current directory name. */
+	baselen = pathlen;
+	while (baselen > 0 && path[baselen - 1] != '/')
+		baselen--;
+
+	err = descend_leading_dirs(null_sha1, path, baselen, mode, stage, fn);
+
+	if (!err) {
+		/* We need a NUL-terminated version of the directory name. */
+		char *dirname = xstrndup(path + baselen, pathlen - baselen);
+		switch (fn(sha1, path, baselen, dirname, mode, stage)) {
+		case 0:
+			err = 1;
+			break;
+		case READ_TREE_RECURSIVE:
+			err = 0;
+			break;
+		default:
+			err = -1;
+			break;
+		}
+		free(dirname);
+	}
+
+	return err;
+}
diff --git a/tree.h b/tree.h
index dd25c53..6b0f5d9 100644
--- a/tree.h
+++ b/tree.h
@@ -30,4 +30,9 @@ extern int read_tree_recursive(struct tree *tree,
 
 extern int read_tree(struct tree *tree, int stage, const char **paths);
 
+extern int descend_leading_dirs(const unsigned char *sha1,
+                                const char *path, size_t pathlen,
+                                unsigned int mode, int stage,
+                                read_tree_fn_t fn);
+
 #endif /* TREE_H */
Next: Junio C Hamano
Message 1 of 5 in “git-archive: recursive prefix directory creation”
  1. git-archive: recursive prefix directory creationRené Scharfe, May 19, 2007
  2. Junio C HamanoMay 19, 2007
  3. René ScharfeMay 19, 2007
  4. Junio C HamanoMay 19, 2007
  5. René ScharfeMay 20, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.