All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 0/3]
@ 2015-05-14 20:17 David Turner
  2015-05-14 20:17 ` [PATCH 1/3] tree-walk: learn get_tree_entry_follow_symlinks David Turner
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: David Turner @ 2015-05-14 20:17 UTC (permalink / raw)
  To: git

Change text explaining that --follow-symlinks only works with
--batch{-check,}; now it is presented as a missing feature rather than
a necessary evil.

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH v12 0/3] git cat-file --follow-symlinks
@ 2015-05-14 21:58 David Turner
  2015-05-14 21:58 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
  0 siblings, 1 reply; 10+ messages in thread
From: David Turner @ 2015-05-14 21:58 UTC (permalink / raw)
  To: git

Adjust asciidoc to use +-continuation with non-indented sections
instead of [normal].

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH v11 0/3] cat-file --follow-symlinks
@ 2015-05-14 20:38 David Turner
  2015-05-14 20:38 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
  0 siblings, 1 reply; 10+ messages in thread
From: David Turner @ 2015-05-14 20:38 UTC (permalink / raw)
  To: git

Squashes Junio's formatting and text to cat-file.c on top of my doco
fixes from v10.

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH v9 0/3]
@ 2015-05-13 18:23 David Turner
  2015-05-13 18:23 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
  0 siblings, 1 reply; 10+ messages in thread
From: David Turner @ 2015-05-13 18:23 UTC (permalink / raw)
  To: git

Oops, forgot to ammend commit before patch v8.  This patch *really*
includes the switch and type casting fixes.

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH v8 0/3] git cat-file --follow-symlinks
@ 2015-05-13 18:21 David Turner
  2015-05-13 18:21 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
  0 siblings, 1 reply; 10+ messages in thread
From: David Turner @ 2015-05-13 18:21 UTC (permalink / raw)
  To: git

This version includes the following:
(a) fix leak in tree-walk.c, thanks to Jeff King
(b) asciidoc now correctly indented when rendered as HTML and when
rendered as a man page.
(c) type casting is now correct
(d) Added a default to switch statement to shut up stupid compilers.

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH 1/3] tree-walk: learn get_tree_enty_follow_symlinks
@ 2015-05-08 18:13 dturner
  2015-05-08 18:13 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch dturner
  0 siblings, 1 reply; 10+ messages in thread
From: dturner @ 2015-05-08 18:13 UTC (permalink / raw)
  To: git; +Cc: David Turner

From: David Turner <dturner@twitter.com>

Add a new function, get_tree_entry_follow_symlinks, to tree-walk.[ch].
The function is not yet used.  It will be used to implement git
cat-file --batch --follow-symlinks.

The function locates an object by path, following symlinks in the
repository.  If the symlinks lead outside the repository, the function
reports this to the caller.

Signed-off-by: David Turner <dturner@twitter.com>
---
 tree-walk.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tree-walk.h |   2 +
 2 files changed, 224 insertions(+)

diff --git a/tree-walk.c b/tree-walk.c
index 5dd9a71..6fb4b7d 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -415,6 +415,228 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
 	return error;
 }
 
+static int find_tree_entry_nonrecursive(struct tree_desc *t, char *name, unsigned char *result, unsigned *mode) {
+	int namelen = strlen(name);
+
+	while (t->size) {
+		const char *entry;
+		const unsigned char *sha1;
+		int entrylen, cmp;
+
+		sha1 = tree_entry_extract(t, &entry, mode);
+		entrylen = tree_entry_len(&t->entry);
+		update_tree_entry(t);
+		if (entrylen > namelen)
+			continue;
+		cmp = memcmp(name, entry, entrylen);
+		if (cmp > 0)
+			continue;
+		if (cmp < 0)
+			break;
+		if (entrylen == namelen) {
+			hashcpy(result, sha1);
+			return 0;
+		}
+		if (name[entrylen] != '/')
+			continue;
+		if (!S_ISDIR(*mode))
+			break;
+		hashcpy(result, sha1);
+		return 0;
+	}
+	return -1;
+}
+
+struct dir_state {
+	void *tree;
+	unsigned long size;
+	unsigned char sha1[20];
+};
+
+#define GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS 40
+
+/**
+ * Find a tree entry by following symlinks in tree_sha (which is
+ * assumed to be the root of the repository).  In the event that a
+ * symlink points outside the repository (e.g. a link to /foo or a
+ * root-level link to ../foo), the portion of the link which is
+ * outside the repository will be copied into result_path (which is
+ * assumed to hold at least PATH_MAX bytes), and *mode will be set to
+ * 0.  Otherwise, result will be filled in with the sha1 of the found
+ * object, and *mode will hold the mode of the object.
+ */
+int get_tree_enty_follow_symlinks(unsigned char *tree_sha1, const char *name, unsigned char *result, unsigned char *result_path, unsigned *mode)
+{
+	int retval = -1;
+	void *tree;
+	struct dir_state *parents = NULL;
+	size_t parents_cap = 0;
+	ssize_t parents_len = 0;
+	unsigned long size;
+	unsigned char root[20];
+	unsigned char current_tree_sha1[20];
+	struct strbuf namebuf = STRBUF_INIT;
+	enum object_type type;
+	int already_have_tree = 0;
+	struct tree_desc t = {0};
+	int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS;
+	int i;
+
+	strbuf_addstr(&namebuf, name);
+	hashcpy(current_tree_sha1, tree_sha1);
+
+	while (1) {
+		char *first_slash;
+		char *remainder = NULL;
+		int find_result;
+
+		if (!t.buffer) {
+			tree = read_object_with_reference(current_tree_sha1,
+							  tree_type, &size,
+							  root);
+			if (!tree)
+				goto done;
+
+			ALLOC_GROW(parents, parents_len + 1, parents_cap);
+			parents[parents_len].tree = tree;
+			parents[parents_len].size = size;
+			hashcpy(parents[parents_len].sha1, root);
+
+			parents_len++;
+
+			if (namebuf.buf[0] == '\0') {
+				hashcpy(result, root);
+				retval = 0;
+				goto done;
+			}
+
+			if (!size)
+				goto done;
+
+			/* descend */
+			init_tree_desc(&t, tree, size);
+		}
+
+		/* Handle symlinks to e.g. a//b by removing leading slashes */
+		while (namebuf.buf[0] == '/') {
+			strbuf_remove(&namebuf, 0, 1);
+		}
+
+		/* Split namebuf into a first component and a
+		 * remainder */
+		if ((first_slash = strchr(namebuf.buf, '/'))) {
+			*first_slash = 0;
+			remainder = first_slash + 1;
+		}
+
+		if (!strcmp(namebuf.buf, "..")) {
+			struct dir_state *parent;
+			/* We could end up with .. in the namebuf if
+			 * it appears in a symlink. */
+
+			if (parents_len == 1) {
+				if (remainder)
+					*first_slash = '/';
+				if (strlcpy(result_path, namebuf.buf,
+					    PATH_MAX) < PATH_MAX) {
+					*mode = 0;
+					retval = 0;
+				}
+				goto done;
+			}
+			parent = &parents[parents_len - 1];
+			free(parent->tree);
+			parents_len--;
+			parent = &parents[parents_len - 1];
+			init_tree_desc(&t, parent->tree, parent->size);
+			strbuf_remove(&namebuf, 0, remainder ? 3 : 2);
+			continue;
+		}
+
+		/* We could end up here via a symlink to dir/.. */
+		if (namebuf.buf[0] == '\0') {
+			hashcpy(result, parents[parents_len - 1].sha1);
+			retval = 0;
+			goto done;
+		}
+
+		/* Look up the first (or only) path component
+		 * in the tree. */
+		find_result = find_tree_entry_nonrecursive(&t, namebuf.buf,
+							   current_tree_sha1,
+							   mode);
+		if (find_result) {
+			retval = find_result;
+			goto done;
+		}
+
+		if (S_ISDIR(*mode)) {
+			if (!remainder) {
+				hashcpy(result, current_tree_sha1);
+				retval = 0;
+				goto done;
+			}
+			/* Descend the tree */
+			t.buffer = NULL;
+			strbuf_remove(&namebuf, 0,
+				      1 + first_slash - namebuf.buf);
+		} else if (S_ISREG(*mode)) {
+			if (!remainder) {
+				hashcpy(result, current_tree_sha1);
+				retval = 0;
+			}
+			goto done;
+		} else if (S_ISLNK(*mode)) {
+			/* Follow a symlink */
+			size_t link_len, len;
+			char *contents, *contents_start;
+			struct dir_state *parent;
+
+			if (follows_remaining-- == 0)
+				/* Too many symlinks followed */
+				goto done;
+
+			contents = read_sha1_file(current_tree_sha1, &type,
+						  &link_len);
+
+			if (!contents)
+				goto done;
+
+			if (contents[0] == '/') {
+				if (strlcpy(result_path,
+					    contents, PATH_MAX) < PATH_MAX) {
+					*mode = 0;
+					retval = 0;
+				}
+				goto done;
+			}
+
+			if (remainder)
+				len = first_slash - namebuf.buf;
+			else
+				len = namebuf.len;
+
+			contents_start = contents;
+
+			parent = &parents[parents_len - 1];
+			init_tree_desc(&t, parent->tree, parent->size);
+			strbuf_splice(&namebuf, 0, len,
+				      contents_start, link_len);
+			if (remainder)
+				namebuf.buf[link_len] = '/';
+			free(contents);
+		}
+	}
+done:
+	for (i = 0; i < parents_len; ++i) {
+		free(parents[i].tree);
+	}
+	free(parents);
+
+	strbuf_release(&namebuf);
+	return retval;
+}
+
 static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)
 {
 	int namelen = strlen(name);
diff --git a/tree-walk.h b/tree-walk.h
index ae7fb3a..002e5a9 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -40,6 +40,8 @@ struct traverse_info;
 typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
 int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info);
 
+int get_tree_enty_follow_symlinks(unsigned char *tree_sha1, const char *name, unsigned char *result, unsigned char *result_path, unsigned *mode);
+
 struct traverse_info {
 	struct traverse_info *prev;
 	struct name_entry name;
-- 
2.0.4.315.gad8727a-twtrsrc

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-05-14 21:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-14 20:17 [PATCH v10 0/3] David Turner
2015-05-14 20:17 ` [PATCH 1/3] tree-walk: learn get_tree_entry_follow_symlinks David Turner
2015-05-14 20:17 ` [PATCH 2/3] sha1_name: get_sha1_with_context learns to follow symlinks David Turner
2015-05-14 20:17 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
  -- strict thread matches above, loose matches on Subject: below --
2015-05-14 21:58 [PATCH v12 0/3] git cat-file --follow-symlinks David Turner
2015-05-14 21:58 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
2015-05-14 20:38 [PATCH v11 0/3] cat-file --follow-symlinks David Turner
2015-05-14 20:38 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
2015-05-13 18:23 [PATCH v9 0/3] David Turner
2015-05-13 18:23 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
2015-05-13 18:21 [PATCH v8 0/3] git cat-file --follow-symlinks David Turner
2015-05-13 18:21 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch David Turner
2015-05-08 18:13 [PATCH 1/3] tree-walk: learn get_tree_enty_follow_symlinks dturner
2015-05-08 18:13 ` [PATCH 3/3] cat-file: add --follow-symlinks to --batch dturner
2015-05-08 19:51   ` Eric Sunshine

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.