[PATCH] Stop using the "git descriptor file" model

Linus Torvalds torvalds at linux-foundation.org
Wed Mar 12 14:53:37 PDT 2014


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Wed, 12 Mar 2014 14:12:58 -0700
Subject: [PATCH] Stop using the "git descriptor file" model

Instead, just encode the git repository information in the filename.

We want to make it much harder to make it match a real filename, but to
still allow easy browsing with the file manager interface.  So the git
repository "filename" format is the path to the git repository
directory, with the branch name encoded as "[branch]" at the end rather
than the "path:branch" format that we used in the descriptor file.

[ For example, on Windows, a filename like "c:\my.xml" could be
  interpreted as the branchame "\my.xml" in the repository in the
  directory "c" ]

In particular, with this model, no filename that ends with ".xml" could
possibly ever be considered a git repository name, since the last
character of a git pathname is always ']'.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

This is a more convenient form to use. I can just set my default filename 
to

   /home/torvalds/scuba[linus]

and it does the right thing. And there is no way to mix this up with an 
XML file if you do the normal *.xml style file format.

 dive.h     |  7 +++--
 file.c     | 10 ++++---
 load-git.c | 35 ++++++++----------------
 save-git.c | 90 ++++++++++++++++++++++++++++++++------------------------------
 save-xml.c | 21 +++++----------
 5 files changed, 76 insertions(+), 87 deletions(-)

diff --git a/dive.h b/dive.h
index febc6080c858..5ac43f16dfb5 100644
--- a/dive.h
+++ b/dive.h
@@ -685,8 +685,11 @@ extern void save_dives(const char *filename);
 extern void save_dives_logic(const char *filename, bool select_only);
 extern void save_dive(FILE *f, struct dive *dive);
 extern void export_dives_uddf(const char *filename, const bool selected);
-extern int git_save_dives(int fd, bool select_only);
-extern int git_load_dives(char *where);
+
+struct git_repository;
+extern struct git_repository *is_git_repository(const char *filename, const char **branchp);
+extern int git_save_dives(struct git_repository *, const char *, bool select_only);
+extern int git_load_dives(struct git_repository *, const char *);
 
 extern int subsurface_rename(const char *path, const char *newpath);
 extern int subsurface_open(const char *path, int oflags, mode_t mode);
diff --git a/file.c b/file.c
index 826f3eb51a25..8facdf8d5aab 100644
--- a/file.c
+++ b/file.c
@@ -356,19 +356,21 @@ static void parse_file_buffer(const char *filename, struct memblock *mem, char *
 
 	if (!mem->size || !mem->buffer)
 		return;
-	if (mem->size > 3 && !memcmp(mem->buffer, "git", 3)) {
-		git_load_dives(mem->buffer);
-		return;
-	}
 
 	parse_xml_buffer(filename, mem->buffer, mem->size, &dive_table, NULL, error);
 }
 
 void parse_file(const char *filename, char **error)
 {
+	struct git_repository *git;
+	const char *branch;
 	struct memblock mem;
 	char *fmt;
 
+	git = is_git_repository(filename, &branch);
+	if (git && !git_load_dives(git, branch))
+		return;
+
 	if (readfile(filename, &mem) < 0) {
 		/* we don't want to display an error if this was the default file */
 		if (prefs.default_filename && !strcmp(filename, prefs.default_filename))
diff --git a/load-git.c b/load-git.c
index 15c48027bde2..5d55245dbed5 100644
--- a/load-git.c
+++ b/load-git.c
@@ -1214,32 +1214,19 @@ static int do_git_load(git_repository *repo, const char *branch)
 	return ret;
 }
 
-int git_load_dives(char *where)
+/*
+ * Like git_save_dives(), this silently returns a negative
+ * value if it's not a git repository at all (so that you
+ * can try to load it some other way.
+ *
+ * If it is a git repository, we return zero for success,
+ * or report an error and return 1 if the load failed.
+ */
+int git_load_dives(struct git_repository *repo, const char *branch)
 {
-	int ret, len;
-	git_repository *repo;
-	char *loc, *branch;
-
-	/* Jump over the "git" marker */
-	loc = where + 3;
-	while (isspace(*loc))
-		loc++;
-
-	/* Trim whitespace from the end */
-	len = strlen(loc);
-	while (len && isspace(loc[len-1]))
-		loc[--len] = 0;
-
-	/* Find a branch name if there is any */
-	branch = strrchr(loc, ':');
-	if (branch)
-		*branch++ = 0;
-
-	if (git_repository_open(&repo, loc))
-		return report_error("Unable to open git repository at '%s' (branch '%s')", loc, branch);
-
-	ret = do_git_load(repo, branch);
+	int ret = do_git_load(repo, branch);
 	git_repository_free(repo);
+	free((void *)branch);
 	finish_active_dive();
 	finish_active_trip();
 	return ret;
diff --git a/save-git.c b/save-git.c
index 04ff87467bd1..4760fe32a6e0 100644
--- a/save-git.c
+++ b/save-git.c
@@ -854,57 +854,61 @@ static int do_git_save(git_repository *repo, const char *branch, bool select_onl
 	return 0;
 }
 
-int git_save_dives(int fd, bool select_only)
+/*
+ * If it's not a git repo, return NULL. Be very conservative.
+ */
+struct git_repository *is_git_repository(const char *filename, const char **branchp)
 {
-	int len, ret;
+	int flen, blen, ret;
 	struct stat st;
-	static char buffer[2048];
 	git_repository *repo;
 	char *loc, *branch;
 
-	if (fstat(fd, &st) < 0)
-		return 0;
-	if (st.st_size >= sizeof(buffer))
-		return 0;
-	len = st.st_size;
-	if (read(fd, buffer, len) != len)
-		return 0;
-	buffer[len] = 0;
-	if (len < 4)
-		return 0;
-	if (memcmp(buffer, "git ", 4))
-		return 0;
-
-	/* Ok, it's a git pointer, we're going to follow it */
-	close(fd);
-
-	/* Trim any whitespace at the end */
-	while (isspace(buffer[len-1]))
-		buffer[--len] = 0;
-
-	/* skip the "git" part and any whitespace from the beginning */
-	loc = buffer+3;
-	len -= 3;
-	while (isspace(*loc)) {
-		loc++;
-		len--;
-	}
+	flen = strlen(filename);
+	if (!flen || filename[--flen] != ']')
+		return NULL;
 
-	if (!len)
-		return report_error("Invalid git pointer");
+	/* Find the matching '[' */
+	blen = 0;
+	while (flen && filename[--flen] != '[')
+		blen++;
 
-	/*
-	 * The result should be a git directory and branch name, like
-	 *  "/home/torvalds/scuba:linus"
-	 */
-	branch = strrchr(loc, ':');
-	if (branch)
-		*branch++ = 0;
+	if (!flen)
+		return NULL;
+
+	loc = malloc(flen+1);
+	if (!loc)
+		return NULL;
+	memcpy(loc, filename, flen);
+	loc[flen] = 0;
+
+	branch = malloc(blen+1);
+	if (!branch) {
+		free(loc);
+		return NULL;
+	}
+	memcpy(branch, filename+flen+1, blen);
+	branch[blen] = 0;
 
-	if (git_repository_open(&repo, loc))
-		return report_error("Unable to open git repository at '%s' (branch '%s')", loc, branch);
+	if (stat(loc, &st) < 0 || !S_ISDIR(st.st_mode)) {
+		free(loc);
+		return NULL;
+	}
 
-	ret = do_git_save(repo, branch, select_only);
+	ret = git_repository_open(&repo, loc);
+	free(loc);
+	if (ret < 0) {
+		free(branch);
+		return NULL;
+	}
+	*branchp = branch;
+	return repo;
+}
+
+int git_save_dives(struct git_repository *repo, const char *branch, bool select_only)
+{
+	int ret = do_git_save(repo, branch, select_only);
 	git_repository_free(repo);
-	return ret < 0 ? ret : 1;
+	free((void *)branch);
+	return ret;
 }
diff --git a/save-xml.c b/save-xml.c
index f5d17c49cb6a..a27dcfa76357 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -597,21 +597,14 @@ void save_dives_logic(const char *filename, const bool select_only)
 {
 	struct membuffer buf = { 0 };
 	FILE *f;
-	int fd;
+	void *git;
+	const char *branch;
 
-	/*
-	 * See if the file already exists, and if so,
-	 * perhaps it's a git save-file pointer?
-	 *
-	 * Otherwise, try to back it up.
-	 */
-	fd = subsurface_open(filename, O_RDONLY, 0);
-	if (fd >= 0) {
-		if (git_save_dives(fd, select_only))
-			return;
-		close(fd);
-		try_to_backup(filename);
-	}
+	git = is_git_repository(filename, &branch);
+	if (git && !git_save_dives(git, branch, select_only))
+		return;
+
+	try_to_backup(filename);
 
 	save_dives_buffer(&buf, select_only);
 
-- 
1.9.0



More information about the subsurface mailing list