* [PATCH 1/5] Add some functions for commit lists
2005-04-24 0:03 [PATCH 0/5] Better merge-base, alternative transport programs Daniel Barkalow
@ 2005-04-24 0:07 ` Daniel Barkalow
2005-04-24 2:12 ` Linus Torvalds
2005-04-24 0:10 ` [PATCH 2/5] Parse tree objects completely Daniel Barkalow
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Daniel Barkalow @ 2005-04-24 0:07 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
This adds a function for inserting an item in a commit list, a function
for sorting a commit list by date, and a function for progressively
scanning a commit history from most recent to least recent.
Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: commit.c
===================================================================
--- 329aca984ad6d06eb6d2dffae3933f00ccb8df5a/commit.c (mode:100644 sha1:9f0668eb68cec56a738a58fe930ae0ae2960e2b2)
+++ e09a6d73a7c6c7a8bfb7e7003a34a507ed97a3b6/commit.c (mode:100644 sha1:911f6435a74b93f6d25c6852d1814fa8dbaf626e)
@@ -63,12 +63,9 @@
bufptr += 46; /* "tree " + "hex sha1" + "\n" */
while (!memcmp(bufptr, "parent ", 7) &&
!get_sha1_hex(bufptr + 7, parent)) {
- struct commit_list *new_parent =
- malloc(sizeof(struct commit_list));
- new_parent->next = item->parents;
- new_parent->item = lookup_commit(parent);
- add_ref(&item->object, &new_parent->item->object);
- item->parents = new_parent;
+ struct commit *new_parent = lookup_commit(parent);
+ commit_list_insert(new_parent, &item->parents);
+ add_ref(&item->object, &new_parent->object);
bufptr += 48;
}
item->date = parse_commit_date(bufptr);
@@ -76,6 +73,14 @@
return 0;
}
+void commit_list_insert(struct commit *item, struct commit_list **list_p)
+{
+ struct commit_list *new_list = malloc(sizeof(struct commit_list));
+ new_list->item = item;
+ new_list->next = *list_p;
+ *list_p = new_list;
+}
+
void free_commit_list(struct commit_list *list)
{
while (list) {
@@ -84,3 +89,44 @@
free(temp);
}
}
+
+static void insert_by_date(struct commit_list **list, struct commit *item)
+{
+ struct commit_list **pp = list;
+ struct commit_list *p;
+ while ((p = *pp) != NULL) {
+ if (p->item->date < item->date) {
+ break;
+ }
+ pp = &p->next;
+ }
+ commit_list_insert(item, pp);
+}
+
+
+void sort_by_date(struct commit_list **list)
+{
+ struct commit_list *ret = NULL;
+ while (*list) {
+ insert_by_date(&ret, (*list)->item);
+ *list = (*list)->next;
+ }
+ *list = ret;
+}
+
+struct commit *pop_most_recent_commit(struct commit_list **list)
+{
+ struct commit *ret = (*list)->item;
+ struct commit_list *parents = ret->parents;
+ struct commit_list *old = *list;
+
+ *list = (*list)->next;
+ free(old);
+
+ while (parents) {
+ parse_commit(parents->item);
+ insert_by_date(list, parents->item);
+ parents = parents->next;
+ }
+ return ret;
+}
Index: commit.h
===================================================================
--- 329aca984ad6d06eb6d2dffae3933f00ccb8df5a/commit.h (mode:100644 sha1:4afd27b1095cf9f9203c96db2b9f2b0bba5063d8)
+++ e09a6d73a7c6c7a8bfb7e7003a34a507ed97a3b6/commit.h (mode:100644 sha1:c8684d1cd07d7c9ed0af06a3f3d9e7b49fbed0a2)
@@ -22,6 +22,15 @@
int parse_commit(struct commit *item);
+void commit_list_insert(struct commit *item, struct commit_list **list_p);
+
void free_commit_list(struct commit_list *list);
+void sort_by_date(struct commit_list **list);
+
+/** Removes the first commit from a list sorted by date, and adds all
+ * of its parents.
+ **/
+struct commit *pop_most_recent_commit(struct commit_list **list);
+
#endif /* COMMIT_H */
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 3/5] Additional functions for the objects database
2005-04-24 0:03 [PATCH 0/5] Better merge-base, alternative transport programs Daniel Barkalow
2005-04-24 0:07 ` [PATCH 1/5] Add some functions for commit lists Daniel Barkalow
2005-04-24 0:10 ` [PATCH 2/5] Parse tree objects completely Daniel Barkalow
@ 2005-04-24 0:15 ` Daniel Barkalow
2005-04-24 0:18 ` [PATCH 4/5] Replace merge-base implementation Daniel Barkalow
2005-04-24 0:24 ` [PATCH 5/5] Various transport programs Daniel Barkalow
4 siblings, 0 replies; 12+ messages in thread
From: Daniel Barkalow @ 2005-04-24 0:15 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
This adds two functions: one to check if an object is present in the local
database, and one to add an object to the local database by reading it
from a file descriptor and checking its hash.
Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: cache.h
===================================================================
--- 144a13fb75a39538ec4578792d2c374c6ef50f46/cache.h (mode:100644 sha1:bf30ac4741d2eeeb483079f566182505898082f3)
+++ cae140a16189361d8c9f1f7e68ef519956fd26d9/cache.h (mode:100644 sha1:794d676a5cf5c9a03309c4b368840f8707cfcf46)
@@ -122,11 +122,16 @@
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(char *buf, unsigned len, unsigned char *return_sha1);
+
extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
/* Read a tree into the cache */
extern int read_tree(void *buffer, unsigned long size, int stage);
+extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
+
+extern int has_sha1_file(const unsigned char *sha1);
+
/* Convert to/from hex/sha1 representation */
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
Index: sha1_file.c
===================================================================
--- 144a13fb75a39538ec4578792d2c374c6ef50f46/sha1_file.c (mode:100644 sha1:66308ede85c2dad6b184fb74a7215b06a173d8f7)
+++ cae140a16189361d8c9f1f7e68ef519956fd26d9/sha1_file.c (mode:100644 sha1:97a515a073fec5870dfaaa279868ce9330853d3d)
@@ -328,3 +328,75 @@
close(fd);
return 0;
}
+
+int write_sha1_from_fd(const unsigned char *sha1, int fd)
+{
+ char *filename = sha1_file_name(sha1);
+
+ int local;
+ z_stream stream;
+ unsigned char real_sha1[20];
+ char buf[4096];
+ char discard[4096];
+ int ret;
+ SHA_CTX c;
+
+ local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+
+ if (local < 0)
+ return error("Couldn't open %s\n", filename);
+
+ memset(&stream, 0, sizeof(stream));
+
+ inflateInit(&stream);
+
+ SHA1_Init(&c);
+
+ do {
+ ssize_t size;
+ size = read(fd, buf, 4096);
+ if (size <= 0) {
+ close(local);
+ unlink(filename);
+ if (!size)
+ return error("Connection closed?");
+ perror("Reading from connection");
+ return -1;
+ }
+ write(local, buf, size);
+ stream.avail_in = size;
+ stream.next_in = buf;
+ do {
+ stream.next_out = discard;
+ stream.avail_out = sizeof(discard);
+ ret = inflate(&stream, Z_SYNC_FLUSH);
+ SHA1_Update(&c, discard, sizeof(discard) -
+ stream.avail_out);
+ } while (stream.avail_in && ret == Z_OK);
+
+ } while (ret == Z_OK);
+ inflateEnd(&stream);
+
+ close(local);
+ SHA1_Final(real_sha1, &c);
+ if (ret != Z_STREAM_END) {
+ unlink(filename);
+ return error("File %s corrupted", sha1_to_hex(sha1));
+ }
+ if (memcmp(sha1, real_sha1, 20)) {
+ unlink(filename);
+ return error("File %s has bad hash\n", sha1_to_hex(sha1));
+ }
+
+ return 0;
+}
+
+int has_sha1_file(const unsigned char *sha1)
+{
+ char *filename = sha1_file_name(sha1);
+ struct stat st;
+
+ if (!stat(filename, &st))
+ return 1;
+ return 0;
+}
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 4/5] Replace merge-base implementation
2005-04-24 0:03 [PATCH 0/5] Better merge-base, alternative transport programs Daniel Barkalow
` (2 preceding siblings ...)
2005-04-24 0:15 ` [PATCH 3/5] Additional functions for the objects database Daniel Barkalow
@ 2005-04-24 0:18 ` Daniel Barkalow
2005-04-24 0:24 ` [PATCH 5/5] Various transport programs Daniel Barkalow
4 siblings, 0 replies; 12+ messages in thread
From: Daniel Barkalow @ 2005-04-24 0:18 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
The old implementation was a nice algorithm, but, unfortunately, it could
be confused in some cases and would not necessarily do the obvious thing
if one argument was decended from the other. This version fixes that by
changing the criterion to the most recent common ancestor.
Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: merge-base.c
===================================================================
--- cae140a16189361d8c9f1f7e68ef519956fd26d9/merge-base.c (mode:100644 sha1:ac1153bc5646cb2d515ff206b759f4a79e90273a)
+++ 9b75904eab1300d83264a1840d396160482fee88/merge-base.c (mode:100644 sha1:0e4c58ede915aca5719bbd12ecd1945f2f300590)
@@ -5,67 +5,63 @@
static struct commit *process_list(struct commit_list **list_p, int this_mark,
int other_mark)
{
- struct commit_list *parent, *temp;
- struct commit_list *posn = *list_p;
- *list_p = NULL;
- while (posn) {
- parse_commit(posn->item);
- if (posn->item->object.flags & this_mark) {
- /*
- printf("%d already seen %s %x\n",
- this_mark
- sha1_to_hex(posn->parent->sha1),
- posn->parent->flags);
- */
- /* do nothing; this indicates that this side
- * split and reformed, and we only need to
- * mark it once.
- */
- } else if (posn->item->object.flags & other_mark) {
- return posn->item;
- } else {
- /*
- printf("%d based on %s\n",
- this_mark,
- sha1_to_hex(posn->parent->sha1));
- */
- posn->item->object.flags |= this_mark;
-
- parent = posn->item->parents;
- while (parent) {
- temp = malloc(sizeof(struct commit_list));
- temp->next = *list_p;
- temp->item = parent->item;
- *list_p = temp;
- parent = parent->next;
- }
- }
- posn = posn->next;
+ struct commit *item = (*list_p)->item;
+
+ if (item->object.flags & this_mark) {
+ /*
+ printf("%d already seen %s %x\n",
+ this_mark
+ sha1_to_hex(posn->parent->sha1),
+ posn->parent->flags);
+ */
+ /* do nothing; this indicates that this side
+ * split and reformed, and we only need to
+ * mark it once.
+ */
+ *list_p = (*list_p)->next;
+ } else if (item->object.flags & other_mark) {
+ return item;
+ } else {
+ /*
+ printf("%d based on %s\n",
+ this_mark,
+ sha1_to_hex(posn->parent->sha1));
+ */
+ pop_most_recent_commit(list_p);
+ item->object.flags |= this_mark;
}
return NULL;
}
struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
{
- struct commit_list *rev1list = malloc(sizeof(struct commit_list));
- struct commit_list *rev2list = malloc(sizeof(struct commit_list));
+ struct commit_list *rev1list = NULL;
+ struct commit_list *rev2list = NULL;
- rev1list->item = rev1;
- rev1list->next = NULL;
+ commit_list_insert(rev1, &rev1list);
+ commit_list_insert(rev2, &rev2list);
- rev2list->item = rev2;
- rev2list->next = NULL;
+ parse_commit(rev1);
+ parse_commit(rev2);
while (rev1list || rev2list) {
struct commit *ret;
- ret = process_list(&rev1list, 0x1, 0x2);
- if (ret) {
- /* XXXX free lists */
- return ret;
+ if (!rev1list) {
+ // process 2
+ ret = process_list(&rev2list, 0x2, 0x1);
+ } else if (!rev2list) {
+ // process 1
+ ret = process_list(&rev1list, 0x1, 0x2);
+ } else if (rev1list->item->date < rev2list->item->date) {
+ // process 2
+ ret = process_list(&rev2list, 0x2, 0x1);
+ } else {
+ // process 1
+ ret = process_list(&rev1list, 0x1, 0x2);
}
- ret = process_list(&rev2list, 0x2, 0x1);
if (ret) {
- /* XXXX free lists */
+ free_commit_list(rev1list);
+ free_commit_list(rev2list);
return ret;
}
}
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 5/5] Various transport programs
2005-04-24 0:03 [PATCH 0/5] Better merge-base, alternative transport programs Daniel Barkalow
` (3 preceding siblings ...)
2005-04-24 0:18 ` [PATCH 4/5] Replace merge-base implementation Daniel Barkalow
@ 2005-04-24 0:24 ` Daniel Barkalow
4 siblings, 0 replies; 12+ messages in thread
From: Daniel Barkalow @ 2005-04-24 0:24 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
This patch adds three similar and related programs. http-pull downloads
objects from an HTTP server; rpull downloads objects by using ssh and
rpush on the other side; and rpush uploads objects by using ssh and rpull
on the other side.
The algorithm should be sufficient to make the network throughput required
depend only on how much content is new, not at all on how much content the
repository contains.
The combination should enable people to have remote repositories by way of
ssh login for authenticated users and HTTP for anonymous access.
Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: Makefile
===================================================================
--- 9b75904eab1300d83264a1840d396160482fee88/Makefile (mode:100644 sha1:57e70239503466fb3a77f1f2618ee64377e8e04b)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/Makefile (mode:100644 sha1:b60d8eb691f4edd56d5b310b0dd670e98c852228)
@@ -16,7 +16,7 @@
PROG= update-cache show-diff init-db write-tree read-tree commit-tree \
cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
check-files ls-tree merge-base merge-cache unpack-file git-export \
- diff-cache convert-cache
+ diff-cache convert-cache http-pull rpush rpull
all: $(PROG)
@@ -51,7 +51,13 @@
init-db: init-db.o
%: %.o $(LIB_FILE)
- $(CC) $(CFLAGS) -o $@ $< $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
+
+rpush: rsh.o
+
+rpull: rsh.o
+
+http-pull: LIBS += -lcurl
blob.o: $(LIB_H)
cat-file.o: $(LIB_H)
@@ -80,6 +86,9 @@
usage.o: $(LIB_H)
unpack-file.o: $(LIB_H)
write-tree.o: $(LIB_H)
+http-pull.o: $(LIB_H)
+rpull.o: $(LIB_H)
+rpush.o: $(LIB_H)
clean:
rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROG) $(LIB_FILE)
Index: http-pull.c
===================================================================
--- /dev/null (tree:9b75904eab1300d83264a1840d396160482fee88)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/http-pull.c (mode:100644 sha1:a17225719c53508a37905618c624ad8c4d0372ec)
@@ -0,0 +1,204 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "cache.h"
+#include "commit.h"
+#include <errno.h>
+#include <stdio.h>
+
+#include <curl/curl.h>
+#include <curl/easy.h>
+
+static CURL *curl;
+
+static char *base;
+
+static int tree = 0;
+static int commits = 0;
+static int all = 0;
+
+static SHA_CTX c;
+static z_stream stream;
+
+static int local;
+static int zret;
+
+static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
+ void *data) {
+ char expn[4096];
+ size_t size = eltsize * nmemb;
+ int posn = 0;
+ do {
+ ssize_t retval = write(local, ptr + posn, size - posn);
+ if (retval < 0)
+ return posn;
+ posn += retval;
+ } while (posn < size);
+
+ stream.avail_in = size;
+ stream.next_in = ptr;
+ do {
+ stream.next_out = expn;
+ stream.avail_out = sizeof(expn);
+ zret = inflate(&stream, Z_SYNC_FLUSH);
+ SHA1_Update(&c, expn, sizeof(expn) - stream.avail_out);
+ } while (stream.avail_in && zret == Z_OK);
+ return size;
+}
+
+static int fetch(unsigned char *sha1)
+{
+ char *hex = sha1_to_hex(sha1);
+ char *filename = sha1_file_name(sha1);
+ char real_sha1[20];
+ char *url;
+ char *posn;
+
+ if (has_sha1_file(sha1)) {
+ return 0;
+ }
+
+ local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+
+ if (local < 0)
+ return error("Couldn't open %s\n", filename);
+
+ memset(&stream, 0, sizeof(stream));
+
+ inflateInit(&stream);
+
+ SHA1_Init(&c);
+
+ curl_easy_setopt(curl, CURLOPT_FILE, NULL);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
+
+ url = malloc(strlen(base) + 50);
+ strcpy(url, base);
+ posn = url + strlen(base);
+ strcpy(posn, "objects/");
+ posn += 8;
+ memcpy(posn, hex, 2);
+ posn += 2;
+ *(posn++) = '/';
+ strcpy(posn, hex + 2);
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+
+ /*printf("Getting %s\n", hex);*/
+
+ if (curl_easy_perform(curl))
+ return error("Couldn't get %s for %s\n", url, hex);
+
+ close(local);
+ inflateEnd(&stream);
+ SHA1_Final(real_sha1, &c);
+ if (zret != Z_STREAM_END) {
+ unlink(filename);
+ return error("File %s (%s) corrupt\n", hex, url);
+ }
+ if (memcmp(sha1, real_sha1, 20)) {
+ unlink(filename);
+ return error("File %s has bad hash\n", hex);
+ }
+
+ return 0;
+}
+
+static int process_tree(unsigned char *sha1)
+{
+ struct tree *tree = lookup_tree(sha1);
+ struct tree_entry_list *entries;
+
+ if (parse_tree(tree))
+ return -1;
+
+ for (entries = tree->entries; entries; entries = entries->next) {
+ if (fetch(entries->item.tree->object.sha1))
+ return -1;
+ if (entries->directory) {
+ if (process_tree(entries->item.tree->object.sha1))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int process_commit(unsigned char *sha1)
+{
+ struct commit *obj = lookup_commit(sha1);
+
+ if (fetch(sha1))
+ return -1;
+
+ if (parse_commit(obj))
+ return -1;
+
+ if (tree) {
+ if (fetch(obj->tree->object.sha1))
+ return -1;
+ if (process_tree(obj->tree->object.sha1))
+ return -1;
+ if (!all)
+ tree = 0;
+ }
+ if (commits) {
+ struct commit_list *parents = obj->parents;
+ for (; parents; parents = parents->next) {
+ if (has_sha1_file(parents->item->object.sha1))
+ continue;
+ if (fetch(parents->item->object.sha1)) {
+ /* The server might not have it, and
+ * we don't mind.
+ */
+ continue;
+ }
+ if (process_commit(parents->item->object.sha1))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *commit_id;
+ char *url;
+ int arg = 1;
+ unsigned char sha1[20];
+
+ while (arg < argc && argv[arg][0] == '-') {
+ if (argv[arg][1] == 't') {
+ tree = 1;
+ } else if (argv[arg][1] == 'c') {
+ commits = 1;
+ } else if (argv[arg][1] == 'a') {
+ all = 1;
+ tree = 1;
+ commits = 1;
+ }
+ arg++;
+ }
+ if (argc < arg + 2) {
+ usage("http-pull [-c] [-t] [-a] commit-id url");
+ return 1;
+ }
+ commit_id = argv[arg];
+ url = argv[arg + 1];
+
+ get_sha1_hex(commit_id, sha1);
+
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ curl = curl_easy_init();
+
+ base = url;
+
+ if (fetch(sha1))
+ return 1;
+ if (process_commit(sha1))
+ return 1;
+
+ curl_global_cleanup();
+ return 0;
+}
Index: rpull.c
===================================================================
--- /dev/null (tree:9b75904eab1300d83264a1840d396160482fee88)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/rpull.c (mode:100644 sha1:c27af2c2464de28732b8ad1fff3ed8a0804250d6)
@@ -0,0 +1,128 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "cache.h"
+#include "commit.h"
+#include <errno.h>
+#include <stdio.h>
+#include "rsh.h"
+
+static int tree = 0;
+static int commits = 0;
+static int all = 0;
+
+static int fd_in;
+static int fd_out;
+
+static int fetch(unsigned char *sha1)
+{
+ if (has_sha1_file(sha1))
+ return 0;
+ write(fd_out, sha1, 20);
+ return write_sha1_from_fd(sha1, fd_in);
+}
+
+static int process_tree(unsigned char *sha1)
+{
+ struct tree *tree = lookup_tree(sha1);
+ struct tree_entry_list *entries;
+
+ if (parse_tree(tree))
+ return -1;
+
+ for (entries = tree->entries; entries; entries = entries->next) {
+ /*
+ fprintf(stderr, "Tree %s ", sha1_to_hex(sha1));
+ fprintf(stderr, "needs %s\n",
+ sha1_to_hex(entries->item.tree->object.sha1));
+ */
+ if (fetch(entries->item.tree->object.sha1)) {
+ return error("Missing item %s",
+ sha1_to_hex(entries->item.tree->object.sha1));
+ }
+ if (entries->directory) {
+ if (process_tree(entries->item.tree->object.sha1))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int process_commit(unsigned char *sha1)
+{
+ struct commit *obj = lookup_commit(sha1);
+
+ if (fetch(sha1)) {
+ return error("Fetching %s", sha1_to_hex(sha1));
+ }
+
+ if (parse_commit(obj))
+ return -1;
+
+ if (tree) {
+ if (fetch(obj->tree->object.sha1))
+ return -1;
+ if (process_tree(obj->tree->object.sha1))
+ return -1;
+ if (!all)
+ tree = 0;
+ }
+ if (commits) {
+ struct commit_list *parents = obj->parents;
+ for (; parents; parents = parents->next) {
+ if (has_sha1_file(parents->item->object.sha1))
+ continue;
+ if (fetch(parents->item->object.sha1)) {
+ /* The server might not have it, and
+ * we don't mind.
+ */
+ error("Missing tree %s; continuing",
+ sha1_to_hex(parents->item->object.sha1));
+ continue;
+ }
+ if (process_commit(parents->item->object.sha1))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *commit_id;
+ char *url;
+ int arg = 1;
+ unsigned char sha1[20];
+
+ while (arg < argc && argv[arg][0] == '-') {
+ if (argv[arg][1] == 't') {
+ tree = 1;
+ } else if (argv[arg][1] == 'c') {
+ commits = 1;
+ } else if (argv[arg][1] == 'a') {
+ all = 1;
+ tree = 1;
+ commits = 1;
+ }
+ arg++;
+ }
+ if (argc < arg + 2) {
+ usage("rpull [-c] [-t] [-a] commit-id url");
+ return 1;
+ }
+ commit_id = argv[arg];
+ url = argv[arg + 1];
+
+ if (setup_connection(&fd_in, &fd_out, "rpush", url, arg, argv + 1))
+ return 1;
+
+ get_sha1_hex(commit_id, sha1);
+
+ if (fetch(sha1))
+ return 1;
+ if (process_commit(sha1))
+ return 1;
+
+ return 0;
+}
Index: rpush.c
===================================================================
--- /dev/null (tree:9b75904eab1300d83264a1840d396160482fee88)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/rpush.c (mode:100644 sha1:0293a1a46311d7e20b13177143741ab9d6d0d201)
@@ -0,0 +1,69 @@
+#include "cache.h"
+#include "rsh.h"
+#include <sys/socket.h>
+#include <errno.h>
+
+void service(int fd_in, int fd_out) {
+ ssize_t size;
+ int posn;
+ char sha1[20];
+ unsigned long objsize;
+ void *buf;
+ do {
+ posn = 0;
+ do {
+ size = read(fd_in, sha1 + posn, 20 - posn);
+ if (size < 0) {
+ perror("rpush: read ");
+ return;
+ }
+ if (!size)
+ return;
+ posn += size;
+ } while (posn < 20);
+
+ /* fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1)); */
+
+ buf = map_sha1_file(sha1, &objsize);
+ if (!buf) {
+ fprintf(stderr, "rpush: could not find %s\n",
+ sha1_to_hex(sha1));
+ 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);
+ } while (1);
+}
+
+int main(int argc, char **argv)
+{
+ int arg = 1;
+ char *commit_id;
+ char *url;
+ int fd_in, fd_out;
+ while (arg < argc && argv[arg][0] == '-') {
+ arg++;
+ }
+ if (argc < arg + 2) {
+ usage("rpush [-c] [-t] [-a] commit-id url");
+ return 1;
+ }
+ commit_id = argv[arg];
+ url = argv[arg + 1];
+ if (setup_connection(&fd_in, &fd_out, "rpull", url, arg, argv + 1))
+ return 1;
+
+ service(fd_in, fd_out);
+ return 0;
+}
Index: rsh.c
===================================================================
--- /dev/null (tree:9b75904eab1300d83264a1840d396160482fee88)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/rsh.c (mode:100644 sha1:4d6a90bf6c1b290975fb2ac22f25979be56cb476)
@@ -0,0 +1,63 @@
+#include "rsh.h"
+
+#include <string.h>
+#include <sys/socket.h>
+
+#include "cache.h"
+
+#define COMMAND_SIZE 4096
+
+int setup_connection(int *fd_in, int *fd_out, char *remote_prog,
+ char *url, int rmt_argc, char **rmt_argv)
+{
+ char *host;
+ char *path;
+ int sv[2];
+ char command[COMMAND_SIZE];
+ char *posn;
+ int i;
+
+ if (!strcmp(url, "-")) {
+ *fd_in = 0;
+ *fd_out = 1;
+ return 0;
+ }
+
+ host = strstr(url, "//");
+ if (!host) {
+ return error("Bad URL: %s", url);
+ }
+ host += 2;
+ path = strchr(host, '/');
+ if (!path) {
+ return error("Bad URL: %s", url);
+ }
+ *(path++) = '\0';
+ /* ssh <host> 'cd /<path>; stdio-pull <arg...> <commit-id>' */
+ snprintf(command, COMMAND_SIZE,
+ "cd /%s; SHA1_FILE_DIRECTORY=objects %s",
+ path, remote_prog);
+ posn = command + strlen(command);
+ for (i = 0; i < rmt_argc; i++) {
+ *(posn++) = ' ';
+ strncpy(posn, rmt_argv[i], COMMAND_SIZE - (posn - command));
+ posn += strlen(rmt_argv[i]);
+ if (posn - command + 4 >= COMMAND_SIZE) {
+ return error("Command line too long");
+ }
+ }
+ strcpy(posn, " -");
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+ return error("Couldn't create socket");
+ }
+ if (!fork()) {
+ close(sv[1]);
+ dup2(sv[0], 0);
+ dup2(sv[0], 1);
+ execlp("ssh", "ssh", host, command, NULL);
+ }
+ close(sv[0]);
+ *fd_in = sv[1];
+ *fd_out = sv[1];
+ return 0;
+}
Index: rsh.h
===================================================================
--- /dev/null (tree:9b75904eab1300d83264a1840d396160482fee88)
+++ a56d8adaecc49ce7f26536f9f5d54ec813072e4f/rsh.h (mode:100644 sha1:97e4f20b2b80662269827d77f3104025143087e7)
@@ -0,0 +1,7 @@
+#ifndef RSH_H
+#define RSH_H
+
+int setup_connection(int *fd_in, int *fd_out, char *remote_prog,
+ char *url, int rmt_argc, char **rmt_argv);
+
+#endif
^ permalink raw reply [flat|nested] 12+ messages in thread