[PATCH 0/4] Pulling refs files

DORMANTno replies

20 messages, 4 authors, 2016-06-15 · open the first message on its own page

[PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

This series makes the following changes:

 1: Adds support for having the C code know about the general existance of
    .git/refs, and functions for writing these files.
 2: Adds support in the generic pull code for fetching refs (and dummy
    implementations).
 3: Adds support in the HTTP pull code for fetching refs
 4: Adds support in the rsh pull code for fetching refs; this requires
    changes to the protocol. These changes should be sufficient to support
    any future extension, however.

	-Daniel
*This .sig left intentionally blank*

[PATCH 1/4] Support for refs directory

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

Add support for reading and writing files in the refs directory.

Signed-off-by: Daniel Barkalow <redacted>
Index: Makefile
===================================================================
--- 2a5e43fa9318a648bfb4dbf64208f4c26905a5f8/Makefile  (mode:100644 sha1:6afcb3e867a6857f9128dba877e433c12366c1f4)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/Makefile  (mode:100644 sha1:653912b7290d1a28860db41f602fbf15ca2d9aa5)
@@ -36,9 +36,10 @@
 	$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
-	 tag.o date.o
+	 tag.o date.o refs.o
+
 LIB_FILE=libgit.a
-LIB_H=cache.h object.h blob.h tree.h commit.h tag.h
+LIB_H=cache.h object.h blob.h tree.h commit.h tag.h refs.h
 
 LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
Index: cache.h
===================================================================
--- 2a5e43fa9318a648bfb4dbf64208f4c26905a5f8/cache.h  (mode:100644 sha1:c06b94107e0e1149be0ad642812e8d4a42f2193c)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/cache.h  (mode:100644 sha1:ca9d13a972e05d8d0aa15babd5a963688fdd5968)
@@ -110,8 +110,10 @@
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
+#define REFS_ENVIRONMENT "GIT_REFS_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 
+extern char *get_refs_directory(void);
 extern char *get_object_directory(void);
 extern char *get_index_file(void);
 
Index: init-db.c
===================================================================
--- 2a5e43fa9318a648bfb4dbf64208f4c26905a5f8/init-db.c  (mode:100644 sha1:b6bb78356762bd28261949da54638f46776e6d4b)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/init-db.c  (mode:100644 sha1:3441a35d7c2eb88e76db4886e8c068ca898ea8fd)
@@ -40,6 +40,7 @@
 	memcpy(path, sha1_dir, len);
 
 	safe_create_dir(sha1_dir);
+	safe_create_dir(get_refs_directory());
 	for (i = 0; i < 256; i++) {
 		sprintf(path+len, "/%02x", i);
 		safe_create_dir(path);
Index: refs.c
===================================================================
--- /dev/null  (tree:2a5e43fa9318a648bfb4dbf64208f4c26905a5f8)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/refs.c  (mode:100644 sha1:9ba5696c15d8597236e1f5b7a4dbd609045efc81)
@@ -0,0 +1,139 @@
+#include "refs.h"
+#include "cache.h"
+
+#include <errno.h>
+
+static char *split_ref_file_name(const char *dir, const char *name)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int dirlen = strlen(dir);
+	int namelen = strlen(name);
+	char *ret;
+	if (dir[0] == '.')
+		return NULL;
+	if (strchr(dir, '/'))
+		return NULL;
+	if (strchr(name, '/'))
+		return NULL;
+	ret = xmalloc(baselen + 3 + dirlen + namelen);
+	strcpy(ret, base);
+	ret[baselen] = '/';
+	strcpy(ret + baselen + 1, dir);
+	ret[baselen + 1 + dirlen] = '/';
+	strcpy(ret + baselen + 2 + dirlen, name);
+	ret[baselen + 2 + dirlen + namelen] = '\0';
+	return ret;
+}
+
+static char *ref_file_name(const char *ref)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int reflen = strlen(ref);
+	char *ret;
+	char *check;
+	if (ref[0] == '.')
+		return NULL;
+	check = strchr(ref, '/');
+	if (!check)
+		return NULL;
+	if (strchr(check + 1, '/'))
+		return NULL;
+	ret = xmalloc(baselen + 2 + reflen);
+	strcpy(ret, base);
+	ret[baselen] = '/';
+	strcpy(ret + baselen + 1, ref);
+	ret[baselen + 1 + reflen] = '\0';
+	return ret;
+}
+
+static int read_ref_file(char *filename, unsigned char *sha1) {
+	int fd = open(filename, O_RDONLY);
+	char hex[41];
+	if (fd < 0) {
+		return error("Couldn't open %s\n", filename);
+	}
+	if ((read(fd, hex, 41) < 41) ||
+	    (hex[40] != '\n') ||
+	    get_sha1_hex(hex, sha1)) {
+		error("Couldn't read a hash from %s\n", filename);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+int get_split_ref_sha1(const char *dir, const char *name, unsigned char *sha1)
+{
+	char *filename = split_ref_file_name(dir, name);
+	int retval;
+	if (!filename)
+		return -1;
+	retval = read_ref_file(filename, sha1);
+	free(filename);
+	return retval;
+}
+
+int get_ref_sha1(const char *ref, unsigned char *sha1)
+{
+	char *filename = ref_file_name(ref);
+	int retval;
+	if (!filename)
+		return -1;
+	retval = read_ref_file(filename, sha1);
+	free(filename);
+	return retval;
+}
+
+int write_split_ref_sha1(const char *dir, const char *name,
+			 unsigned char *sha1)
+{
+	char *filename = split_ref_file_name(dir, name);
+	char *hex = sha1_to_hex(sha1);
+	char term = '\n';
+	int fd;
+	if (!filename)
+		return -1;
+	unlink(filename);
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0 && errno == ENOENT) {
+		char *dirname = split_ref_file_name(dir, "");
+		mkdir(dirname, 0755);
+		free(dirname);
+		fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	}
+	if (fd < 0) {
+		error("Couldn't open for writing %s: %s\n", filename,
+		      strerror(errno));
+		free(filename);
+		return -1;
+	}
+	if (write(fd, hex, 40) < 40 ||
+	    write(fd, &term, 1) < 1) {
+		error("Couldn't write %s\n", filename);
+		free(filename);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+	
+}
+
+int split_ref(char **dir, char **name, const char *ref)
+{
+	char *middle = strchr(ref, '/');
+	if (ref[0] == '.')
+		return -1;
+	if (!middle)
+		return -1;
+	if (strchr(middle + 1, '/'))
+		return -1;
+	*dir = xmalloc(middle - ref + 1);
+	*name = strdup(middle + 1);
+	(*dir)[middle - ref] = '\0';
+	memcpy(*dir, ref, middle - ref);
+	return 0;
+}
Index: refs.h
===================================================================
--- /dev/null  (tree:2a5e43fa9318a648bfb4dbf64208f4c26905a5f8)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/refs.h  (mode:100644 sha1:9ef6ed7563f70273aef6574a01d5626fee28345a)
@@ -0,0 +1,20 @@
+#ifndef REFS_H
+#define REFS_H
+
+/** Reads the refs file specified into sha1 **/
+extern int get_split_ref_sha1(const char *dir, const char *name,
+			      unsigned char *sha1);
+
+/** Reads the refs file specified into sha1 **/
+extern int get_ref_sha1(const char *ref, unsigned char *sha1);
+
+/** Writes sha1 into the refs file specified **/
+extern int write_split_ref_sha1(const char *dir, const char *name, 
+				unsigned char *sha1);
+
+/** Sets dir and name to the directory and name parts of ref, in new
+ * storage. 
+ **/
+extern int split_ref(char **dir, char **name, const char *ref);
+
+#endif /* REFS_H */
Index: sha1_file.c
===================================================================
--- 2a5e43fa9318a648bfb4dbf64208f4c26905a5f8/sha1_file.c  (mode:100644 sha1:942b673dc3c7fa9f057c5c452e3a1b73eaeb8707)
+++ adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/sha1_file.c  (mode:100644 sha1:a3ab45fbb39f37622ae191fe5c3cbaf30389ec74)
@@ -59,7 +59,7 @@
 	return get_sha1_hex(buffer, result);
 }
 
-static char *git_dir, *git_object_dir, *git_index_file;
+static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir;
 static void setup_git_env(void)
 {
 	git_dir = gitenv(GIT_DIR_ENVIRONMENT);
@@ -70,6 +70,11 @@
 		git_object_dir = xmalloc(strlen(git_dir) + 9);
 		sprintf(git_object_dir, "%s/objects", git_dir);
 	}
+	git_refs_dir = gitenv(REFS_ENVIRONMENT);
+	if (!git_refs_dir) {
+		git_refs_dir = xmalloc(strlen(git_dir) + 6);
+		sprintf(git_refs_dir, "%s/refs", git_dir);
+	}
 	git_index_file = gitenv(INDEX_ENVIRONMENT);
 	if (!git_index_file) {
 		git_index_file = xmalloc(strlen(git_dir) + 7);
@@ -91,6 +96,13 @@
 	return git_index_file;
 }
 
+char *get_refs_directory(void)
+{
+	if (!git_refs_dir)
+		setup_git_env();
+	return git_refs_dir;
+}
+
 int get_sha1(const char *str, unsigned char *sha1)
 {
 	static char pathname[PATH_MAX];

[PATCH 2/4] Generic support for pulling refs

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

This adds a pull method to pull refs, provides dummy implementations for
the existing programs, and uses that method to try to get refs if
requested. It also adds generic support for writing the target to a refs
file.

Signed-off-by: Daniel Barkalow <redacted>
Index: http-pull.c
===================================================================
--- adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/http-pull.c  (mode:100644 sha1:024457a9895ab10c4ef18aa6e232d12fdaab4da9)
+++ 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/http-pull.c  (mode:100644 sha1:af4e82fdf9c58a15564d40bef85d57e9f6626727)
@@ -98,6 +98,11 @@
 	return 0;
 }
 
+int fetch_ref(char *dir, char *name, unsigned char *sha1)
+{
+	return -1;
+}
+
 int main(int argc, char **argv)
 {
 	char *commit_id;
Index: local-pull.c
===================================================================
--- adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/local-pull.c  (mode:100644 sha1:3a342ab18390d7ce0df1f970a4961b31548a9417)
+++ 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/local-pull.c  (mode:100644 sha1:73aad965d0b190627aa95726e4feaa2623d31d26)
@@ -18,6 +18,11 @@
 
 static char *path;
 
+int fetch_ref(char *dir, char *name, unsigned char *sha1)
+{
+	return -1;
+}
+
 int fetch(unsigned char *sha1)
 {
 	static int object_name_start = -1;
Index: pull.c
===================================================================
--- adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/pull.c  (mode:100644 sha1:0bed44f4cbf6716cfc3152f35626123992766408)
+++ 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/pull.c  (mode:100644 sha1:d4d858cd638e915096a408ba3c37090a1b460c21)
@@ -3,6 +3,12 @@
 #include "cache.h"
 #include "commit.h"
 #include "tree.h"
+#include "tag.h"
+
+#include "refs.h"
+
+char *write_ref_dir = NULL;
+char *write_ref_name = NULL;
 
 int get_tree = 0;
 int get_history = 0;
@@ -98,16 +104,52 @@
 	return 0;
 }
 
+static int process_tag(unsigned char *sha1)
+{
+	return 0;
+}
+
+static int process_unknown(unsigned char *sha1)
+{
+	struct object *obj;
+	if (make_sure_we_have_it(NULL, sha1))
+		return -1;
+	obj = parse_object(sha1);
+	if (obj->type == commit_type) {
+		memcpy(current_commit_sha1, sha1, 20);
+		return process_commit(sha1);
+	} else if (obj->type == tag_type)
+		return process_tag(sha1);
+	return error("Cannot pull a %s object", obj->type);
+}
+
+static int interpret_target(char *target, unsigned char *sha1)
+{
+	char *dir, *name;
+	if (!get_sha1_hex(target, sha1))
+		return 0;
+	if (!split_ref(&dir, &name, target)) {
+		if (!fetch_ref(dir, name, sha1)) {
+			return 0;
+		}
+	}
+	return -1;
+}
+
 int pull(char *target)
 {
 	int retval;
 	unsigned char sha1[20];
-	retval = get_sha1_hex(target, sha1);
-	if (retval)
-		return retval;
-	retval = make_sure_we_have_it(commitS, sha1);
+	retval = interpret_target(target, sha1);
+	if (retval) {
+		return error("Could not interpret %s as something to pull",
+			     target);
+	}
+	retval = process_unknown(sha1);
 	if (retval)
 		return retval;
-	memcpy(current_commit_sha1, sha1, 20);
-	return process_commit(sha1);
+
+	if (write_ref_dir && write_ref_name)
+		write_split_ref_sha1(write_ref_dir, write_ref_name, sha1);
+	return 0;
 }
Index: pull.h
===================================================================
--- adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/pull.h  (mode:100644 sha1:d2dca02de7c23426e84e9f63762df9428933e8d8)
+++ 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/pull.h  (mode:100644 sha1:de0e9245b68856bcf84c033650b6b3eb151641e2)
@@ -4,6 +4,12 @@
 /** To be provided by the particular implementation. **/
 extern int fetch(unsigned char *sha1);
 
+extern int fetch_ref(char *dir, char *name, unsigned char *sha1);
+
+/** Ref filename to write target to. **/
+extern char *write_ref_dir;
+extern char *write_ref_name;
+
 /** Set to fetch the target tree. */
 extern int get_tree;
 
Index: rpull.c
===================================================================
--- adc28203a55e7e9d3c0b4f6546ea0c2b99106f24/rpull.c  (mode:100644 sha1:b48e63157c66c160b9751603a92831f77106044c)
+++ 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/rpull.c  (mode:100644 sha1:493fcdae670ebb1d93b8c75d3e28798e060d7537)
@@ -22,6 +22,11 @@
 	return ret;
 }
 
+int fetch_ref(char *dir, char *name, unsigned char *sha1)
+{
+	return -1;
+}
+
 int main(int argc, char **argv)
 {
 	char *commit_id;

[PATCH 3/4] Pull refs by HTTP

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

Adds support for pulling refs by HTTP, and an option for writing the
pulled ref to a file.

Signed-off-by: Daniel Barkalow <redacted>
Index: http-pull.c
===================================================================
--- 90e05f81df7b7fd2c39d252b6f9a2374d4dd0cf5/http-pull.c  (mode:100644 sha1:af4e82fdf9c58a15564d40bef85d57e9f6626727)
+++ 4931f2d8b9c2ab83718f6446d5ef3af5fa320b3f/http-pull.c  (mode:100644 sha1:6e8dc48ddd0ea1ae89074f6ae0d89c54303895b7)
@@ -7,6 +7,8 @@
 #include <errno.h>
 #include <stdio.h>
 
+#include "refs.h"
+
 #include "pull.h"
 
 #include <curl/curl.h>
@@ -45,6 +47,23 @@
 	return size;
 }
 
+struct buffer
+{
+	size_t posn;
+	size_t size;
+	void *buffer;
+};
+
+static size_t fwrite_buffer(void *ptr, size_t eltsize, size_t nmemb,
+			    struct buffer *buffer) {
+	size_t size = eltsize * nmemb;
+	if (size > buffer->size - buffer->posn)
+		size = buffer->size - buffer->posn;
+	memcpy(buffer->buffer + buffer->posn, ptr, size);
+	buffer->posn += size;
+	return size;
+}
+
 int fetch(unsigned char *sha1)
 {
 	char *hex = sha1_to_hex(sha1);
@@ -93,14 +112,42 @@
 		unlink(filename);
 		return error("File %s has bad hash\n", hex);
 	}
-	
 	pull_say("got %s\n", hex);
 	return 0;
 }
 
 int fetch_ref(char *dir, char *name, unsigned char *sha1)
 {
-	return -1;
+	char *url, *posn;
+	char hex[42];
+	struct buffer buffer;
+	buffer.size = 41;
+	buffer.posn = 0;
+	buffer.buffer = hex;
+	hex[41] = '\0';
+	
+	curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+
+	url = xmalloc(strlen(base) + 7 + strlen(dir) + strlen(name));
+	strcpy(url, base);
+	posn = url + strlen(base);
+	strcpy(posn, "refs/");
+	posn += 5;
+	strcpy(posn, dir);
+	posn += strlen(dir);
+	*(posn++) = '/';
+	strcpy(posn, name);
+
+	curl_easy_setopt(curl, CURLOPT_URL, url);
+
+	if (curl_easy_perform(curl))
+		return error("Couldn't get %s for %s/%s\n", url,
+			     dir, name);
+
+	hex[40] = '\0';
+	get_sha1_hex(hex, sha1);
+	return 0;
 }
 
 int main(int argc, char **argv)
@@ -120,6 +167,10 @@
 			get_history = 1;
 		} else if (argv[arg][1] == 'v') {
 			get_verbosely = 1;
+		} else if (argv[arg][1] == 'w') {
+			char *write_ref = argv[arg + 1];
+			split_ref(&write_ref_dir, &write_ref_name, write_ref);
+			arg++;
 		}
 		arg++;
 	}

[PATCH 4/4] Pulling refs by ssh

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

Adds support for pulling refs by rsh.

This changes the rsh protocol to allow requests for different things, and
to allow the server to report that it doesn't have something without
breaking the connection.

Signed-off-by: Daniel Barkalow <redacted>
Index: rpull.c
===================================================================
--- 4931f2d8b9c2ab83718f6446d5ef3af5fa320b3f/rpull.c  (mode:100644 sha1:493fcdae670ebb1d93b8c75d3e28798e060d7537)
+++ a219d8e31f3882aaa32e7dbac7a1f92b35a9dbff/rpull.c  (mode:100644 sha1:cce9e71becc95f728d320ef49e11a647a420b75d)
@@ -8,6 +8,7 @@
 #include <stdio.h>
 #include "rsh.h"
 #include "pull.h"
+#include "refs.h"
 
 static int fd_in;
 static int fd_out;
@@ -15,16 +16,34 @@
 int fetch(unsigned char *sha1)
 {
 	int ret;
+	signed char remote;
+	char type = 'o';
+	if (has_sha1_file(sha1))
+		return 0;
+	write(fd_out, &type, 1);
 	write(fd_out, sha1, 20);
+	if (read(fd_in, &remote, 1) < 1)
+		return -1;
+	if (remote < 0)
+		return remote;
 	ret = write_sha1_from_fd(sha1, fd_in);
 	if (!ret)
 		pull_say("got %s\n", sha1_to_hex(sha1));
 	return ret;
 }
 
-int fetch_ref(char *dir, char *name, unsigned char *sha1)
+int fetch_ref(char *name, char *dir, unsigned char *sha1)
 {
-	return -1;
+	signed char remote;
+	char type = 'r';
+	write(fd_out, &type, 1);
+	write(fd_out, name, strlen(name) + 1);
+	write(fd_out, dir, strlen(dir) + 1);
+	read(fd_in, &remote, 1);
+	if (remote < 0)
+		return remote;
+	read(fd_in, sha1, 20);
+	return 0;
 }
 
 int main(int argc, char **argv)
@@ -44,6 +63,10 @@
 			get_history = 1;
 		} else if (argv[arg][1] == 'v') {
 			get_verbosely = 1;
+		} else if (argv[arg][1] == 'w') {
+			char *write_ref = argv[arg + 1];
+			split_ref(&write_ref_dir, &write_ref_name, write_ref);
+			arg++;
 		}
 		arg++;
 	}
Index: rpush.c
===================================================================
--- 4931f2d8b9c2ab83718f6446d5ef3af5fa320b3f/rpush.c  (mode:100644 sha1:26518846704ecf63ad00390599b251aa1b32713e)
+++ a219d8e31f3882aaa32e7dbac7a1f92b35a9dbff/rpush.c  (mode:100644 sha1:c3cad4eac186307e743eacb913a0b382a455d1f4)
@@ -2,47 +2,98 @@
 #include "rsh.h"
 #include <sys/socket.h>
 #include <errno.h>
+#include "refs.h"
 
-void service(int fd_in, int fd_out) {
+int serve_object(int fd_in, int fd_out) {
 	ssize_t size;
-	int posn;
+	int posn = 0;
 	char sha1[20];
 	unsigned long objsize;
 	void *buf;
+	signed char remote;
 	do {
-		posn = 0;
-		do {
-			size = read(fd_in, sha1 + posn, 20 - posn);
-			if (size < 0) {
-				perror("rpush: read ");
-				return;
+		size = read(fd_in, sha1 + posn, 20 - posn);
+		if (size < 0) {
+			perror("rpush: read ");
+			return -1;
+		}
+		if (!size)
+			return -1;
+		posn += size;
+	} while (posn < 20);
+	
+	/* fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1)); */
+	remote = 0;
+	
+	buf = map_sha1_file(sha1, &objsize);
+	
+	if (!buf) {
+		fprintf(stderr, "rpush: could not find %s\n", 
+			sha1_to_hex(sha1));
+		remote = -1;
+	}
+	
+	write(fd_out, &remote, 1);
+	
+	if (remote < 0)
+		return 0;
+	
+	posn = 0;
+	do {
+		size = write(fd_out, buf + posn, objsize - posn);
+		if (size <= 0) {
+			if (!size) {
+				fprintf(stderr, "rpush: write closed");
+			} else {
+				perror("rpush: write ");
 			}
-			if (!size)
-				return;
-			posn += size;
-		} while (posn < 20);
+			return -1;
+		}
+		posn += size;
+	} while (posn < objsize);
+	return 0;
+}
 
-		/* fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1)); */
+int serve_ref(int fd_in, int fd_out)
+{
+	char dir[PATH_MAX], name[PATH_MAX];
+	unsigned char sha1[20];
+	int posn = 0;
+	signed char remote = 0;
+	do {
+		if (read(fd_in, dir + posn, 1) < 1)
+			return -1;
+		posn++;
+	} while (dir[posn - 1]);
+	posn = 0;
+	do {
+		if (read(fd_in, name + posn, 1) < 1)
+			return -1;
+		posn++;
+	} while (name[posn - 1]);
+	if (get_split_ref_sha1(dir, name, sha1))
+		remote = -1;
+	write(fd_out, &remote, 1);
+	if (remote)
+		return 0;
+	write(fd_out, sha1, 20);
+	return 0;
+}
 
-		buf = map_sha1_file(sha1, &objsize);
-		if (!buf) {
-			fprintf(stderr, "rpush: could not find %s\n", 
-				sha1_to_hex(sha1));
+void service(int fd_in, int fd_out) {
+	char type;
+	int retval;
+	do {
+		retval = read(fd_in, &type, 1);
+		if (retval < 1) {
+			if (retval < 0)
+				perror("rpush: read ");
 			return;
 		}
-		posn = 0;
-		do {
-			size = write(fd_out, buf + posn, objsize - posn);
-			if (size <= 0) {
-				if (!size) {
-					fprintf(stderr, "rpush: write closed");
-				} else {
-					perror("rpush: write ");
-				}
-				return;
-			}
-			posn += size;
-		} while (posn < objsize);
+		if (type == 'o' && serve_object(fd_in, fd_out))
+			return;
+		if (type == 'r' && serve_ref(fd_in, fd_out))
+			return;
 	} while (1);
 }
 
@@ -53,6 +104,8 @@
         char *url;
 	int fd_in, fd_out;
 	while (arg < argc && argv[arg][0] == '-') {
+		if (argv[arg][1] == 'w')
+			arg++;
                 arg++;
         }
         if (argc < arg + 2) {
Index: rsh.c
===================================================================
--- 4931f2d8b9c2ab83718f6446d5ef3af5fa320b3f/rsh.c  (mode:100644 sha1:5d1cb9d578a8e679fc190a9d7d2c842ad811223f)
+++ a219d8e31f3882aaa32e7dbac7a1f92b35a9dbff/rsh.c  (mode:100644 sha1:192d8f67e9a5e2bf7bb9e14c8c037dff49e74d57)
@@ -36,8 +36,8 @@
 	*(path++) = '\0';
 	/* ssh <host> 'cd /<path>; stdio-pull <arg...> <commit-id>' */
 	snprintf(command, COMMAND_SIZE, 
-		 "cd /%s; %s=objects %s",
-		 path, DB_ENVIRONMENT, remote_prog);
+		 "cd /%s; GIT_DIR=. %s",
+		 path, remote_prog);
 	posn = command + strlen(command);
 	for (i = 0; i < rmt_argc; i++) {
 		*(posn++) = ' ';

Re: [PATCH 3/4] Pull refs by HTTP

From: Edgar Toernig <hidden>
Date: 2016-06-15 22:41:57

Daniel Barkalow wrote:
+	url = xmalloc(strlen(base) + 7 + strlen(dir) + strlen(name));
+	strcpy(url, base);
+	posn = url + strlen(base);
+	strcpy(posn, "refs/");
+	posn += 5;
+	strcpy(posn, dir);
+	posn += strlen(dir);
+	*(posn++) = '/';
+	strcpy(posn, name);
Have you ever heard of sprintf & co?

	sprintf(url, "%srefs/%s/%s", base, dir, name);

Ciao, ET.

Re: [PATCH 4/4] Pulling refs by ssh

From: "H. Peter Anvin" <hpa@zytor.com>
Date: 2016-06-15 22:41:57

Daniel Barkalow wrote:
Adds support for pulling refs by rsh.

This changes the rsh protocol to allow requests for different things, and
to allow the server to report that it doesn't have something without
breaking the connection.
Use && rather than semicolon, and make sure you quote things that need 
to be quoted.

	-hpa

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Fri, May 13, 2005 at 08:49:25AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
This series makes the following changes:

 1: Adds support for having the C code know about the general existance of
    .git/refs, and functions for writing these files.
 2: Adds support in the generic pull code for fetching refs (and dummy
    implementations).
 3: Adds support in the HTTP pull code for fetching refs
 4: Adds support in the rsh pull code for fetching refs; this requires
    changes to the protocol. These changes should be sufficient to support
    any future extension, however.
Hmm, I've honestly expected something different - a generic way to
specify any file in the repository to be pulled along, instead of a
introducing refs awareness at this level of git. What would be the
advantages of that approach against just specifying list of other files
to pull along?

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Sat, 14 May 2005, Petr Baudis wrote:
Hmm, I've honestly expected something different - a generic way to
specify any file in the repository to be pulled along, instead of a
introducing refs awareness at this level of git. What would be the
advantages of that approach against just specifying list of other files
to pull along?
The point is to specify the commit to pull by fetching a file from the
other side, not just to move a file. So you need to be specifying that the
file is a hex encoding of the sha1 hash of the starting point of the pull,
and the refs/ area is where these are expected to be. (Note that it still
doesn't have any knowledge about the meanings of files in refs/; you tell
it which one you want to use, and optionally which one you want to write
to, and it will use the names you provide).

It wouldn't help much to download the head file if you had to know the
contents of that file already in order to do everything as a single
transfer.

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Sat, May 14, 2005 at 01:14:22AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
On Sat, 14 May 2005, Petr Baudis wrote:
quoted
Hmm, I've honestly expected something different - a generic way to
specify any file in the repository to be pulled along, instead of a
introducing refs awareness at this level of git. What would be the
advantages of that approach against just specifying list of other files
to pull along?
The point is to specify the commit to pull by fetching a file from the
other side, not just to move a file. So you need to be specifying that the
file is a hex encoding of the sha1 hash of the starting point of the pull,
and the refs/ area is where these are expected to be. (Note that it still
doesn't have any knowledge about the meanings of files in refs/; you tell
it which one you want to use, and optionally which one you want to write
to, and it will use the names you provide).

It wouldn't help much to download the head file if you had to know the
contents of that file already in order to do everything as a single
transfer.
So what about just something like

	git-wormhole-pull remote:refs/head/master wormhole://localhost/

That is, you could just specify remote:path_relative_to_url instead of
SHA1 id as the commit.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Sat, 14 May 2005, Petr Baudis wrote:
So what about just something like

	git-wormhole-pull remote:refs/head/master wormhole://localhost/

That is, you could just specify remote:path_relative_to_url instead of
SHA1 id as the commit.
Do you have any sensible alternatives to "remote:refs/<something>" in
mind? I suppose that "remote:HEAD" would also work. How are you thinking
of having the value get written locally?

Do you also have some idea for user-invoked rpush? It has to call
something that writes the value on the other side (and I'd ideally like it
to do the update atomically and locked against other clients). This series
uses the same mechanism to write it that it uses to write hashes fetched
from remote machines.

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 4/4] Pulling refs by ssh

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Fri, 13 May 2005, H. Peter Anvin wrote:
Use && rather than semicolon, and make sure you quote things that need 
to be quoted.
This is a separate issue from the change for refs; could you send a patch
that quotes things properly? The "cd" should be unnecessary now that we
have the GIT_DIR environment variable.

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Sun, May 15, 2005 at 05:23:18AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
On Sat, 14 May 2005, Petr Baudis wrote:
quoted
So what about just something like

	git-wormhole-pull remote:refs/head/master wormhole://localhost/

That is, you could just specify remote:path_relative_to_url instead of
SHA1 id as the commit.
Do you have any sensible alternatives to "remote:refs/<something>" in
mind? I suppose that "remote:HEAD" would also work. How are you thinking
of having the value get written locally?
Anything that gets eventually wound up in the info/ directory. (The name
of the ignore file saved in info/ignore is the current hit.)
Do you also have some idea for user-invoked rpush? It has to call
something that writes the value on the other side (and I'd ideally like it
to do the update atomically and locked against other clients). This series
uses the same mechanism to write it that it uses to write hashes fetched
from remote machines.
Well, it'd be again nice to have some generic mechanism for this so that
the user could theoretically push over rsync too or something (although
that'll be even more racy, it is fine for single-user repository).

I think the remote file to write the value inside should be porcelain
business. What you should always check though is that before the pull
(and after the locking) the value in that file is the same as the "push
base". This way you make sure that you are still following a single
branch and in case of multiuser repositories that you were fully merged
before pushing.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Tue, 17 May 2005, Petr Baudis wrote:
Dear diary, on Sun, May 15, 2005 at 05:23:18AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
quoted
On Sat, 14 May 2005, Petr Baudis wrote:
quoted
So what about just something like

	git-wormhole-pull remote:refs/head/master wormhole://localhost/

That is, you could just specify remote:path_relative_to_url instead of
SHA1 id as the commit.
Do you have any sensible alternatives to "remote:refs/<something>" in
mind? I suppose that "remote:HEAD" would also work. How are you thinking
of having the value get written locally?
Anything that gets eventually wound up in the info/ directory. (The name
of the ignore file saved in info/ignore is the current hit.)
Hmm... maybe the right thing is to make the implementation-provided
transfer code handle arbitrary things in GIT_DIR, but have code for
updating reference files atomically and using a reference file to start
from use "refs/"? Certainly, there's nothing special about reference files
in transit.

Certainly the things in the info/ directory shouldn't be treated a head
that you're going to pull, so that has to be different above the protocol
level anyway.
Well, it'd be again nice to have some generic mechanism for this so that
the user could theoretically push over rsync too or something (although
that'll be even more racy, it is fine for single-user repository).
Hmm; I'm not sure what would be good for interfacing with rsync.
I think the remote file to write the value inside should be porcelain
business.
Certainly it's porcelain business what remote file to write; but I think
it has to be core business doing the lock, test, and update. I think it
would be inconvenient to go back to the porcelain layer in the middle of
the operation, particularly since it would have to go back to the core,
which is what has the connection to the remote host.
What you should always check though is that before the pull
(and after the locking) the value in that file is the same as the "push
base". This way you make sure that you are still following a single
branch and in case of multiuser repositories that you were fully merged
before pushing.
So the remote receiver should get an instruction: change X from OLD to NEW
and pull NEW. It should:

 - lock the file against further updates
 - check that the current value is the provided OLD
 - pull the necessary objects
 - write NEW to the file
 - report success

On failure of any step, it should unlock the file without changing it.

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Tue, May 17, 2005 at 11:20:54PM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
On Tue, 17 May 2005, Petr Baudis wrote:
quoted
Anything that gets eventually wound up in the info/ directory. (The name
of the ignore file saved in info/ignore is the current hit.)
Hmm... maybe the right thing is to make the implementation-provided
transfer code handle arbitrary things in GIT_DIR, but have code for
updating reference files atomically and using a reference file to start
from use "refs/"? Certainly, there's nothing special about reference files
in transit.

Certainly the things in the info/ directory shouldn't be treated a head
that you're going to pull, so that has to be different above the protocol
level anyway.
*confused* :) I'm sorry, I have trouble understanding this. Could you
rephrase, please?
quoted
Well, it'd be again nice to have some generic mechanism for this so that
the user could theoretically push over rsync too or something (although
that'll be even more racy, it is fine for single-user repository).
Hmm; I'm not sure what would be good for interfacing with rsync.
I've been thinking about writing some FTP-like client for rsync, where
you could "interactively" tell it what files to download etc.
quoted
I think the remote file to write the value inside should be porcelain
business.
Certainly it's porcelain business what remote file to write; but I think
it has to be core business doing the lock, test, and update. I think it
would be inconvenient to go back to the porcelain layer in the middle of
the operation, particularly since it would have to go back to the core,
which is what has the connection to the remote host.
Of course. The porcelain file would just provide the filename.
quoted
What you should always check though is that before the pull
(and after the locking) the value in that file is the same as the "push
base". This way you make sure that you are still following a single
branch and in case of multiuser repositories that you were fully merged
before pushing.
So the remote receiver should get an instruction: change X from OLD to NEW
and pull NEW. It should:

 - lock the file against further updates
 - check that the current value is the provided OLD
 - pull the necessary objects
 - write NEW to the file
- unlock the file ;-))
 - report success

On failure of any step, it should unlock the file without changing it.
Sounds right.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Tue, 17 May 2005, Petr Baudis wrote:
Dear diary, on Tue, May 17, 2005 at 11:20:54PM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
quoted
Hmm... maybe the right thing is to make the implementation-provided
transfer code handle arbitrary things in GIT_DIR, but have code for
updating reference files atomically and using a reference file to start
from use "refs/"? Certainly, there's nothing special about reference files
in transit.

Certainly the things in the info/ directory shouldn't be treated a head
that you're going to pull, so that has to be different above the protocol
level anyway.
*confused* :) I'm sorry, I have trouble understanding this. Could you
rephrase, please?
If you want to get info/ignore, you want to get it and save it, not
download a set of objects it refers to. So it's different from specifying
that you want to use refs/heads/master as the starting point for a pull.

There would be a separation between transfering whatever file you specify
and treating the specified (remote) file from refs/ as the starting point
for pulling objects.

Also, you don't need to do the same kind of careful update, since the
desired value of info/ignore isn't going to depend on the previous
value.
quoted
So the remote receiver should get an instruction: change X from OLD to NEW
and pull NEW. It should:

 - lock the file against further updates
 - check that the current value is the provided OLD
 - pull the necessary objects
 - write NEW to the file
- unlock the file ;-))
The way I'm actually doing things is to write NEW into the lock file at
some arbitrary point, and "writing to the file" is actually renaming the
lock file to the normal filename. So writing unlocks the file
automatically.
quoted
 - report success

On failure of any step, it should unlock the file without changing it.
Sounds right.
I think I'll get to implementing it Wednesday night. I might be able to
get the first step done tonight (my previous patch, except with the
transfer applying to arbitrary files).

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Wed, May 18, 2005 at 12:20:40AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
On Tue, 17 May 2005, Petr Baudis wrote:
quoted
Dear diary, on Tue, May 17, 2005 at 11:20:54PM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
quoted
Hmm... maybe the right thing is to make the implementation-provided
transfer code handle arbitrary things in GIT_DIR, but have code for
updating reference files atomically and using a reference file to start
from use "refs/"? Certainly, there's nothing special about reference files
in transit.

Certainly the things in the info/ directory shouldn't be treated a head
that you're going to pull, so that has to be different above the protocol
level anyway.
*confused* :) I'm sorry, I have trouble understanding this. Could you
rephrase, please?
If you want to get info/ignore, you want to get it and save it, not
download a set of objects it refers to. So it's different from specifying
that you want to use refs/heads/master as the starting point for a pull.
Obviously. I think you should need to "explicitly" tell pull to actually
save any files locally, since you (I mean Cogito) certainly does not
want the pull stuff to touch the local refs/heads/master - it wants it
in some other file.
quoted
quoted
So the remote receiver should get an instruction: change X from OLD to NEW
and pull NEW. It should:

 - lock the file against further updates
 - check that the current value is the provided OLD
 - pull the necessary objects
 - write NEW to the file
- unlock the file ;-))
The way I'm actually doing things is to write NEW into the lock file at
some arbitrary point, and "writing to the file" is actually renaming the
lock file to the normal filename. So writing unlocks the file
automatically.
Ah. Obviously. That makes sense. :-)

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Tue, 17 May 2005, Daniel Barkalow wrote:
I think I'll get to implementing it Wednesday night. I might be able to
get the first step done tonight (my previous patch, except with the
transfer applying to arbitrary files).
Upon further consideration, I think there are three things that pull
implementation needs to handle:

 1) fetching object files by hash, validating them, and writing them to
    the local objects directory
 2) fetching reference files by name, and making them available to the
    local program without writing them to disk at all.
 3) fetching other files by name and writing them to either the
    corresponding filename or a provided replacement.

I had thought that (2) could be done as a special case of (3), but I think
that it has to be separate, because (2) just returns the value, while
(3) can't just return the contents, but has to write it somewhere, since
it isn't constrained to be exactly 20 bytes.

So I think I'd like to do essentially the original series, slightly
rearranged and with a few edits, and then add (3) afterwards; this should
be easy once the rpush/rpull changes to make the protocol extensible are
in place.

I'll also do additional (independant) patches to provide an expected
starting point and lock things appropriately.

	-Daniel
*This .sig left intentionally blank*

Re: [PATCH 0/4] Pulling refs files

From: Petr Baudis <hidden>
Date: 2016-06-15 22:41:57

Dear diary, on Thu, May 19, 2005 at 05:19:01AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
 2) fetching reference files by name, and making them available to the
    local program without writing them to disk at all.
 3) fetching other files by name and writing them to either the
    corresponding filename or a provided replacement.

I had thought that (2) could be done as a special case of (3), but I think
that it has to be separate, because (2) just returns the value, while
(3) can't just return the contents, but has to write it somewhere, since
it isn't constrained to be exactly 20 bytes.
Huh. How would (2) be useful and why can't you just still write it e.g.
to some user-supplied temporary file? I think that'd be still actually
much less trouble for the scripts to handle.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor

Re: [PATCH 0/4] Pulling refs files

From: Daniel Barkalow <hidden>
Date: 2016-06-15 22:41:57

On Thu, 19 May 2005, Petr Baudis wrote:
Dear diary, on Thu, May 19, 2005 at 05:19:01AM CEST, I got a letter
where Daniel Barkalow [off-list ref] told me that...
quoted
 2) fetching reference files by name, and making them available to the
    local program without writing them to disk at all.
 3) fetching other files by name and writing them to either the
    corresponding filename or a provided replacement.

I had thought that (2) could be done as a special case of (3), but I think
that it has to be separate, because (2) just returns the value, while
(3) can't just return the contents, but has to write it somewhere, since
it isn't constrained to be exactly 20 bytes.
Huh. How would (2) be useful and why can't you just still write it e.g.
to some user-supplied temporary file? I think that'd be still actually
much less trouble for the scripts to handle.
(2) is what is needed if the user just requests downloading objects
starting with a reference stored remotely, and doesn't request that the
reference be written anywhere. It is also useful because the system wants
to verify that it has actually downloaded the objects successfully before
writing the reference.

Note that the scripts see a higher-level interface; these are the
operations that (e.g.) http-pull.c has to provide for pull.c, which builds
a larger operation (determine the target hash, download the objects, write
the specified ref file) out of them. It would be inconvenient for pull.c 
to download to a temporary file and then read the temporary file, which
shouldn't normally be visible yet, to figure out what it's doing. It wants
to have a function that takes a string and returns a hash, getting the
value from the remote host, and it's inconvenient to deal with the disk in
the middle.

	-Daniel
*This .sig left intentionally blank*
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help