git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [PATCH] Reorganize common code
  @ 2005-04-13 22:00 13% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-04-13 22:00 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

This splits read-cache.c into util.c, cache.c, and objects.c, based on
what the code is used for; similarly, cache.h becomes util.h, cache.h, and
objects.h. For simplicity, cache.h includes the other two to give the
previous overall behavior.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>

Index: Makefile
===================================================================
--- 783978eb212c1402ba2612bb32626e93af78b72d/Makefile  (mode:100644 sha1:2b626ec05b2e29016d26b5cb7b4f82ec5c4e79d6)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/Makefile  (mode:100644 sha1:0b263fa693cb2addb2516a8f7af2ea05b95d3c8c)
@@ -20,7 +20,7 @@
 	gitmerge.sh gitpull.sh gitrm.sh gittag.sh gittrack.sh gitexport.sh \
 	gitapply.sh
 
-COMMON=	read-cache.o
+COMMON=	cache.o objects.o util.o
 
 GEN_SCRIPT= gitversion.sh
 
@@ -36,7 +36,7 @@
 $(PROG):%: %.o $(COMMON)
 	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
 
-read-cache.o: cache.h
+cache.o: cache.h
 show-diff.o: cache.h
 
 gitversion.sh: $(VERSION)
Index: cache.c
===================================================================
--- /dev/null  (tree:783978eb212c1402ba2612bb32626e93af78b72d)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/cache.c  (mode:100644 sha1:fe61eae561e8ebaab9d9fe6d8f146ed7353b6a1c)
@@ -0,0 +1,224 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include <stdarg.h>
+#include "cache.h"
+
+const char *sha1_file_directory = NULL;
+struct cache_entry **active_cache = NULL;
+unsigned int active_nr = 0, active_alloc = 0;
+
+int cache_match_stat(struct cache_entry *ce, struct stat *st)
+{
+	unsigned int changed = 0;
+
+	/* nsec seems unreliable - not all filesystems support it, so
+	 * as long as it is in the inode cache you get right nsec
+	 * but after it gets flushed, you get zero nsec. */
+	if (ce->mtime.sec  != (unsigned int)st->st_mtim.tv_sec
+#ifdef NSEC
+	    || ce->mtime.nsec != (unsigned int)st->st_mtim.tv_nsec
+#endif
+	    )
+		changed |= MTIME_CHANGED;
+	if (ce->ctime.sec  != (unsigned int)st->st_ctim.tv_sec
+#ifdef NSEC
+	    || ce->ctime.nsec != (unsigned int)st->st_ctim.tv_nsec
+#endif
+	    )
+		changed |= CTIME_CHANGED;
+	if (ce->st_uid != (unsigned int)st->st_uid ||
+	    ce->st_gid != (unsigned int)st->st_gid)
+		changed |= OWNER_CHANGED;
+	if (ce->st_mode != (unsigned int)st->st_mode)
+		changed |= MODE_CHANGED;
+	if (ce->st_dev != (unsigned int)st->st_dev ||
+	    ce->st_ino != (unsigned int)st->st_ino)
+		changed |= INODE_CHANGED;
+	if (ce->st_size != (unsigned int)st->st_size)
+		changed |= DATA_CHANGED;
+	return changed;
+}
+
+int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
+{
+	int len = len1 < len2 ? len1 : len2;
+	int cmp;
+
+	cmp = memcmp(name1, name2, len);
+	if (cmp)
+		return cmp;
+	if (len1 < len2)
+		return -1;
+	if (len1 > len2)
+		return 1;
+	return 0;
+}
+
+int cache_name_pos(const char *name, int namelen)
+{
+	int first, last;
+
+	first = 0;
+	last = active_nr;
+	while (last > first) {
+		int next = (last + first) >> 1;
+		struct cache_entry *ce = active_cache[next];
+		int cmp = cache_name_compare(name, namelen, ce->name, ce->namelen);
+		if (!cmp)
+			return next;
+		if (cmp < 0) {
+			last = next;
+			continue;
+		}
+		first = next+1;
+	}
+	return -first-1;
+}
+
+int remove_file_from_cache(char *path)
+{
+	int pos = cache_name_pos(path, strlen(path));
+	if (pos >= 0) {
+		active_nr--;
+		if (pos < active_nr)
+			memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
+	}
+	return 0;
+}
+
+int add_cache_entry(struct cache_entry *ce, int ok_to_add)
+{
+	int pos;
+
+	pos = cache_name_pos(ce->name, ce->namelen);
+
+	/* existing match? Just replace it */
+	if (pos >= 0) {
+		active_cache[pos] = ce;
+		return 0;
+	}
+	pos = -pos-1;
+
+	if (!ok_to_add)
+		return -1;
+
+	/* Make sure the array is big enough .. */
+	if (active_nr == active_alloc) {
+		active_alloc = alloc_nr(active_alloc);
+		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+	}
+
+	/* Add it in.. */
+	active_nr++;
+	if (active_nr > pos)
+		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
+	active_cache[pos] = ce;
+	return 0;
+}
+
+static int verify_hdr(struct cache_header *hdr, unsigned long size)
+{
+	SHA_CTX c;
+	unsigned char sha1[20];
+
+	if (hdr->signature != CACHE_SIGNATURE)
+		return error("bad signature");
+	if (hdr->version != 1)
+		return error("bad version");
+	SHA1_Init(&c);
+	SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
+	SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
+	SHA1_Final(sha1, &c);
+	if (memcmp(sha1, hdr->sha1, 20))
+		return error("bad header sha1");
+	return 0;
+}
+
+int read_cache(void)
+{
+	int fd, i;
+	struct stat st;
+	unsigned long size, offset;
+	void *map;
+	struct cache_header *hdr;
+
+	errno = EBUSY;
+	if (active_cache)
+		return error("more than one cachefile");
+	errno = ENOENT;
+	sha1_file_directory = getenv(DB_ENVIRONMENT);
+	if (!sha1_file_directory)
+		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
+	if (access(sha1_file_directory, X_OK) < 0)
+		return error("no access to SHA1 file directory");
+	fd = open(".git/index", O_RDONLY);
+	if (fd < 0)
+		return (errno == ENOENT) ? 0 : error("open failed");
+
+	size = 0; // avoid gcc warning
+	map = (void *)-1;
+	if (!fstat(fd, &st)) {
+		size = st.st_size;
+		errno = EINVAL;
+		if (size >= sizeof(struct cache_header))
+			map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+	}
+	close(fd);
+	if (-1 == (int)(long)map)
+		return error("mmap failed");
+
+	hdr = map;
+	if (verify_hdr(hdr, size) < 0)
+		goto unmap;
+
+	active_nr = hdr->entries;
+	active_alloc = alloc_nr(active_nr);
+	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
+
+	offset = sizeof(*hdr);
+	for (i = 0; i < hdr->entries; i++) {
+		struct cache_entry *ce = map + offset;
+		offset = offset + ce_size(ce);
+		active_cache[i] = ce;
+	}
+	return active_nr;
+
+unmap:
+	munmap(map, size);
+	errno = EINVAL;
+	return error("verify header failed");
+}
+
+int write_cache(int newfd, struct cache_entry **cache, int entries)
+{
+	SHA_CTX c;
+	struct cache_header hdr;
+	int i;
+
+	hdr.signature = CACHE_SIGNATURE;
+	hdr.version = 1;
+	hdr.entries = entries;
+
+	SHA1_Init(&c);
+	SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
+	for (i = 0; i < entries; i++) {
+		struct cache_entry *ce = cache[i];
+		int size = ce_size(ce);
+		SHA1_Update(&c, ce, size);
+	}
+	SHA1_Final(hdr.sha1, &c);
+
+	if (write(newfd, &hdr, sizeof(hdr)) != sizeof(hdr))
+		return -1;
+
+	for (i = 0; i < entries; i++) {
+		struct cache_entry *ce = cache[i];
+		int size = ce_size(ce);
+		if (write(newfd, ce, size) != size)
+			return -1;
+	}
+	return 0;
+}
Index: cache.h
===================================================================
--- 783978eb212c1402ba2612bb32626e93af78b72d/cache.h  (mode:100644 sha1:d3e9a21b7d9a2ac32abacf5cc40ee1a4d83f9fe8)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/cache.h  (mode:100644 sha1:e3302b454e5d55d4d7bd46bbfe870cb34733ce46)
@@ -14,6 +14,9 @@
 #include <openssl/sha.h>
 #include <zlib.h>
 
+#include "util.h"
+#include "objects.h"
+
 /*
  * Basic data structures for the directory cache
  *
@@ -59,13 +62,9 @@
 	char name[0];
 };
 
-const char *sha1_file_directory;
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc;
 
-#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
-#define DEFAULT_DB_ENVIRONMENT ".git/objects"
-
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 #define ce_size(ce) cache_entry_size((ce)->namelen)
 
@@ -74,7 +73,10 @@
 /* Initialize and use the cache information */
 extern int read_cache(void);
 extern int write_cache(int newfd, struct cache_entry **cache, int entries);
+
+/* Returns the location of the given name in the cache. */
 extern int cache_name_pos(const char *name, int namelen);
+
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
 extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
@@ -86,28 +88,7 @@
 #define INODE_CHANGED   0x0010
 #define DATA_CHANGED    0x0020
 
-/* Return a statically allocated filename matching the sha1 signature */
-extern char *sha1_file_name(const unsigned char *sha1);
-
-/* Write a memory buffer out to the sha file */
-extern int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size);
-
-/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
-extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-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(const unsigned char *sha1, void *buf, unsigned long size);
-
-/* 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! */
-
-/* General helper functions */
-extern void usage(const char *err);
-extern void die(const char *err, ...);
-extern int error(const char *err, ...);
-
-extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern int cache_name_compare(const char *name1, int len1, 
+			      const char *name2, int len2);
 
 #endif /* CACHE_H */
Index: objects.c
===================================================================
--- /dev/null  (tree:783978eb212c1402ba2612bb32626e93af78b72d)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/objects.c  (mode:100644 sha1:ee0aed670a76e0af9e4150c93915dad53a198ba5)
@@ -0,0 +1,240 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include <stdarg.h>
+#include "cache.h"
+#include "objects.h"
+#include <openssl/sha.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <zlib.h>
+
+
+static unsigned hexval(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return ~0;
+}
+
+int get_sha1_hex(const char *hex, unsigned char *sha1)
+{
+	int i;
+	for (i = 0; i < 20; i++) {
+		unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+		if (val & ~0xff)
+			return -1;
+		*sha1++ = val;
+		hex += 2;
+	}
+	return 0;
+}
+
+char * sha1_to_hex(const unsigned char *sha1)
+{
+	static char buffer[50];
+	static const char hex[] = "0123456789abcdef";
+	char *buf = buffer;
+	int i;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	return buffer;
+}
+
+/*
+ * NOTE! This returns a statically allocated buffer, so you have to be
+ * careful about using it. Do a "strdup()" if you need to save the
+ * filename.
+ */
+char *sha1_file_name(const unsigned char *sha1)
+{
+	int i;
+	static char *name, *base;
+
+	if (!base) {
+		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+		int len = strlen(sha1_file_directory);
+		base = malloc(len + 60);
+		memcpy(base, sha1_file_directory, len);
+		memset(base+len, 0, 60);
+		base[len] = '/';
+		base[len+3] = '/';
+		name = base + len + 1;
+	}
+	for (i = 0; i < 20; i++) {
+		static char hex[] = "0123456789abcdef";
+		unsigned int val = sha1[i];
+		char *pos = name + i*2 + (i > 0);
+		*pos++ = hex[val >> 4];
+		*pos = hex[val & 0xf];
+	}
+	return base;
+}
+
+int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size)
+{
+	unsigned char real_sha1[20];
+	SHA_CTX c;
+
+	SHA1_Init(&c);
+	SHA1_Update(&c, map, size);
+	SHA1_Final(real_sha1, &c);
+	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
+}
+
+void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+{
+	char *filename = sha1_file_name(sha1);
+	int fd = open(filename, O_RDONLY);
+	struct stat st;
+	void *map;
+
+	if (fd < 0) {
+		perror(filename);
+		return NULL;
+	}
+	if (fstat(fd, &st) < 0) {
+		close(fd);
+		return NULL;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	close(fd);
+	if (-1 == (int)(long)map)
+		return NULL;
+	*size = st.st_size;
+	return map;
+}
+
+void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+{
+	int ret, bytes;
+	z_stream stream;
+	char buffer[8192];
+	char *buf;
+
+	/* Get the data stream */
+	memset(&stream, 0, sizeof(stream));
+	stream.next_in = map;
+	stream.avail_in = mapsize;
+	stream.next_out = buffer;
+	stream.avail_out = sizeof(buffer);
+
+	inflateInit(&stream);
+	ret = inflate(&stream, 0);
+	if (sscanf(buffer, "%10s %lu", type, size) != 2)
+		return NULL;
+
+	bytes = strlen(buffer) + 1;
+	buf = malloc(*size);
+	if (!buf)
+		return NULL;
+
+	memcpy(buf, buffer + bytes, stream.total_out - bytes);
+	bytes = stream.total_out - bytes;
+	if (bytes < *size && ret == Z_OK) {
+		stream.next_out = buf + bytes;
+		stream.avail_out = *size - bytes;
+		while (inflate(&stream, Z_FINISH) == Z_OK)
+			/* nothing */;
+	}
+	inflateEnd(&stream);
+	return buf;
+}
+
+void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (map) {
+		buf = unpack_sha1_file(map, mapsize, type, size);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
+int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
+{
+	int size;
+	char *compressed;
+	z_stream stream;
+	unsigned char sha1[20];
+	SHA_CTX c;
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	deflateInit(&stream, Z_BEST_COMPRESSION);
+	size = deflateBound(&stream, len);
+	compressed = malloc(size);
+
+	/* Compress it */
+	stream.next_in = buf;
+	stream.avail_in = len;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	while (deflate(&stream, Z_FINISH) == Z_OK)
+		/* nothing */;
+	deflateEnd(&stream);
+	size = stream.total_out;
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, compressed, size);
+	SHA1_Final(sha1, &c);
+
+	if (write_sha1_buffer(sha1, compressed, size) < 0)
+		return -1;
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+	return 0;
+}
+
+int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
+{
+	char *filename = sha1_file_name(sha1);
+	int fd;
+
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		void *map;
+
+		if (errno != EEXIST)
+			return -1;
+		/* #define NO_COLLISION_CHECK to possibly speed things up,
+		 * but the speedup should be really negligible. */
+#ifndef NO_COLLISION_CHECK
+		fd = open(filename, O_RDONLY);
+		if (fd < 0)
+			return -1;
+		map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+		if (map == MAP_FAILED)
+			return -1;
+		if (memcmp(buf, map, size))
+			return error("SHA1 collision detected!"
+					" This is bad, bad, BAD!\a\n");
+#endif
+		return 0;
+	}
+	write(fd, buf, size);
+	close(fd);
+	return 0;
+}
Index: objects.h
===================================================================
--- /dev/null  (tree:783978eb212c1402ba2612bb32626e93af78b72d)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/objects.h  (mode:100644 sha1:b6469e3e2ef191b36a23da23cbb8bf70ad54da0e)
@@ -0,0 +1,43 @@
+#ifndef OBJECTS_H
+#define OBJECTS_H
+
+/* Operations on the object database. */
+const char *sha1_file_directory;
+
+#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
+#define DEFAULT_DB_ENVIRONMENT ".git/objects"
+
+/* Takes a key and returns the contents, and sets *type to its type
+ * and size to its size.  
+ */
+extern void * read_sha1_file(const unsigned char *sha1, char *type,
+			     unsigned long *size);
+
+/* Writes the given data and length to a file, and returns the key. */
+extern int write_sha1_file(char *buf, unsigned len, 
+			   unsigned char *return_sha1);
+
+/* mmap the given file, and put its size in *size. */
+extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
+
+/* Given a map, its size, and its expected type, return its contents and set
+ * *size to the size of the contents. 
+ */
+extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type,
+			       unsigned long *size);
+
+/* Return a statically allocated filename matching the sha1 signature */
+extern char *sha1_file_name(const unsigned char *sha1);
+
+/* Write a memory buffer out to the sha file */
+extern int write_sha1_buffer(const unsigned char *sha1, void *buf, 
+			     unsigned int size);
+/* compares the given buffer against its expected sha1 hash. */
+extern int check_sha1_signature(const unsigned char *sha1, void *buf, 
+				unsigned long size);
+
+/* 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 ret! */
+
+#endif /* OBJECTS_H */
Index: read-cache.c
===================================================================
--- 783978eb212c1402ba2612bb32626e93af78b72d/read-cache.c  (mode:100644 sha1:7cdd0f82992789e64f6ea272e43ee4af8cdf7f2a)
+++ /dev/null  (tree:e8194c62bfc68725972a6847fa2c6d529ca64137)
@@ -1,478 +0,0 @@
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include <stdarg.h>
-#include "cache.h"
-
-const char *sha1_file_directory = NULL;
-struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0;
-
-void usage(const char *err)
-{
-	fprintf(stderr, "usage: %s\n", err);
-	exit(1);
-}
-
-static void report(const char *prefix, const char *err, va_list params)
-{
-	fputs(prefix, stderr);
-	vfprintf(stderr, err, params);
-	fputs("\n", stderr);
-}
-
-void die(const char *err, ...)
-{
-	va_list params;
-
-	va_start(params, err);
-	report("fatal: ", err, params);
-	va_end(params);
-	exit(1);
-}
-
-int error(const char *err, ...)
-{
-	va_list params;
-
-	va_start(params, err);
-	report("error: ", err, params);
-	va_end(params);
-	return -1;
-}
-
-
-static unsigned hexval(char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	if (c >= 'A' && c <= 'F')
-		return c - 'A' + 10;
-	return ~0;
-}
-
-int get_sha1_hex(const char *hex, unsigned char *sha1)
-{
-	int i;
-	for (i = 0; i < 20; i++) {
-		unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
-		if (val & ~0xff)
-			return -1;
-		*sha1++ = val;
-		hex += 2;
-	}
-	return 0;
-}
-
-char * sha1_to_hex(const unsigned char *sha1)
-{
-	static char buffer[50];
-	static const char hex[] = "0123456789abcdef";
-	char *buf = buffer;
-	int i;
-
-	for (i = 0; i < 20; i++) {
-		unsigned int val = *sha1++;
-		*buf++ = hex[val >> 4];
-		*buf++ = hex[val & 0xf];
-	}
-	return buffer;
-}
-
-/*
- * NOTE! This returns a statically allocated buffer, so you have to be
- * careful about using it. Do a "strdup()" if you need to save the
- * filename.
- */
-char *sha1_file_name(const unsigned char *sha1)
-{
-	int i;
-	static char *name, *base;
-
-	if (!base) {
-		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
-		int len = strlen(sha1_file_directory);
-		base = malloc(len + 60);
-		memcpy(base, sha1_file_directory, len);
-		memset(base+len, 0, 60);
-		base[len] = '/';
-		base[len+3] = '/';
-		name = base + len + 1;
-	}
-	for (i = 0; i < 20; i++) {
-		static char hex[] = "0123456789abcdef";
-		unsigned int val = sha1[i];
-		char *pos = name + i*2 + (i > 0);
-		*pos++ = hex[val >> 4];
-		*pos = hex[val & 0xf];
-	}
-	return base;
-}
-
-int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size)
-{
-	unsigned char real_sha1[20];
-	SHA_CTX c;
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, map, size);
-	SHA1_Final(real_sha1, &c);
-	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
-}
-
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
-{
-	char *filename = sha1_file_name(sha1);
-	int fd = open(filename, O_RDONLY);
-	struct stat st;
-	void *map;
-
-	if (fd < 0) {
-		perror(filename);
-		return NULL;
-	}
-	if (fstat(fd, &st) < 0) {
-		close(fd);
-		return NULL;
-	}
-	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	close(fd);
-	if (-1 == (int)(long)map)
-		return NULL;
-	*size = st.st_size;
-	return map;
-}
-
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
-{
-	int ret, bytes;
-	z_stream stream;
-	char buffer[8192];
-	char *buf;
-
-	/* Get the data stream */
-	memset(&stream, 0, sizeof(stream));
-	stream.next_in = map;
-	stream.avail_in = mapsize;
-	stream.next_out = buffer;
-	stream.avail_out = sizeof(buffer);
-
-	inflateInit(&stream);
-	ret = inflate(&stream, 0);
-	if (sscanf(buffer, "%10s %lu", type, size) != 2)
-		return NULL;
-
-	bytes = strlen(buffer) + 1;
-	buf = malloc(*size);
-	if (!buf)
-		return NULL;
-
-	memcpy(buf, buffer + bytes, stream.total_out - bytes);
-	bytes = stream.total_out - bytes;
-	if (bytes < *size && ret == Z_OK) {
-		stream.next_out = buf + bytes;
-		stream.avail_out = *size - bytes;
-		while (inflate(&stream, Z_FINISH) == Z_OK)
-			/* nothing */;
-	}
-	inflateEnd(&stream);
-	return buf;
-}
-
-void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
-{
-	unsigned long mapsize;
-	void *map, *buf;
-
-	map = map_sha1_file(sha1, &mapsize);
-	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
-		munmap(map, mapsize);
-		return buf;
-	}
-	return NULL;
-}
-
-int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
-{
-	int size;
-	char *compressed;
-	z_stream stream;
-	unsigned char sha1[20];
-	SHA_CTX c;
-
-	/* Set it up */
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
-	size = deflateBound(&stream, len);
-	compressed = malloc(size);
-
-	/* Compress it */
-	stream.next_in = buf;
-	stream.avail_in = len;
-	stream.next_out = compressed;
-	stream.avail_out = size;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/* nothing */;
-	deflateEnd(&stream);
-	size = stream.total_out;
-
-	/* Sha1.. */
-	SHA1_Init(&c);
-	SHA1_Update(&c, compressed, size);
-	SHA1_Final(sha1, &c);
-
-	if (write_sha1_buffer(sha1, compressed, size) < 0)
-		return -1;
-	if (returnsha1)
-		memcpy(returnsha1, sha1, 20);
-	return 0;
-}
-
-int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
-{
-	char *filename = sha1_file_name(sha1);
-	int fd;
-
-	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
-	if (fd < 0) {
-		void *map;
-
-		if (errno != EEXIST)
-			return -1;
-		/* #define NO_COLLISION_CHECK to possibly speed things up,
-		 * but the speedup should be really negligible. */
-#ifndef NO_COLLISION_CHECK
-		fd = open(filename, O_RDONLY);
-		if (fd < 0)
-			return -1;
-		map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-		if (map == MAP_FAILED)
-			return -1;
-		if (memcmp(buf, map, size))
-			return error("SHA1 collision detected!"
-					" This is bad, bad, BAD!\a\n");
-#endif
-		return 0;
-	}
-	write(fd, buf, size);
-	close(fd);
-	return 0;
-}
-
-int cache_match_stat(struct cache_entry *ce, struct stat *st)
-{
-	unsigned int changed = 0;
-
-	/* nsec seems unreliable - not all filesystems support it, so
-	 * as long as it is in the inode cache you get right nsec
-	 * but after it gets flushed, you get zero nsec. */
-	if (ce->mtime.sec  != (unsigned int)st->st_mtim.tv_sec
-#ifdef NSEC
-	    || ce->mtime.nsec != (unsigned int)st->st_mtim.tv_nsec
-#endif
-	    )
-		changed |= MTIME_CHANGED;
-	if (ce->ctime.sec  != (unsigned int)st->st_ctim.tv_sec
-#ifdef NSEC
-	    || ce->ctime.nsec != (unsigned int)st->st_ctim.tv_nsec
-#endif
-	    )
-		changed |= CTIME_CHANGED;
-	if (ce->st_uid != (unsigned int)st->st_uid ||
-	    ce->st_gid != (unsigned int)st->st_gid)
-		changed |= OWNER_CHANGED;
-	if (ce->st_mode != (unsigned int)st->st_mode)
-		changed |= MODE_CHANGED;
-	if (ce->st_dev != (unsigned int)st->st_dev ||
-	    ce->st_ino != (unsigned int)st->st_ino)
-		changed |= INODE_CHANGED;
-	if (ce->st_size != (unsigned int)st->st_size)
-		changed |= DATA_CHANGED;
-	return changed;
-}
-
-int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
-{
-	int len = len1 < len2 ? len1 : len2;
-	int cmp;
-
-	cmp = memcmp(name1, name2, len);
-	if (cmp)
-		return cmp;
-	if (len1 < len2)
-		return -1;
-	if (len1 > len2)
-		return 1;
-	return 0;
-}
-
-int cache_name_pos(const char *name, int namelen)
-{
-	int first, last;
-
-	first = 0;
-	last = active_nr;
-	while (last > first) {
-		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
-		int cmp = cache_name_compare(name, namelen, ce->name, ce->namelen);
-		if (!cmp)
-			return next;
-		if (cmp < 0) {
-			last = next;
-			continue;
-		}
-		first = next+1;
-	}
-	return -first-1;
-}
-
-int remove_file_from_cache(char *path)
-{
-	int pos = cache_name_pos(path, strlen(path));
-	if (pos >= 0) {
-		active_nr--;
-		if (pos < active_nr)
-			memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
-	}
-	return 0;
-}
-
-int add_cache_entry(struct cache_entry *ce, int ok_to_add)
-{
-	int pos;
-
-	pos = cache_name_pos(ce->name, ce->namelen);
-
-	/* existing match? Just replace it */
-	if (pos >= 0) {
-		active_cache[pos] = ce;
-		return 0;
-	}
-	pos = -pos-1;
-
-	if (!ok_to_add)
-		return -1;
-
-	/* Make sure the array is big enough .. */
-	if (active_nr == active_alloc) {
-		active_alloc = alloc_nr(active_alloc);
-		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
-	}
-
-	/* Add it in.. */
-	active_nr++;
-	if (active_nr > pos)
-		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
-	return 0;
-}
-
-static int verify_hdr(struct cache_header *hdr, unsigned long size)
-{
-	SHA_CTX c;
-	unsigned char sha1[20];
-
-	if (hdr->signature != CACHE_SIGNATURE)
-		return error("bad signature");
-	if (hdr->version != 1)
-		return error("bad version");
-	SHA1_Init(&c);
-	SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
-	SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
-	SHA1_Final(sha1, &c);
-	if (memcmp(sha1, hdr->sha1, 20))
-		return error("bad header sha1");
-	return 0;
-}
-
-int read_cache(void)
-{
-	int fd, i;
-	struct stat st;
-	unsigned long size, offset;
-	void *map;
-	struct cache_header *hdr;
-
-	errno = EBUSY;
-	if (active_cache)
-		return error("more than one cachefile");
-	errno = ENOENT;
-	sha1_file_directory = getenv(DB_ENVIRONMENT);
-	if (!sha1_file_directory)
-		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
-	if (access(sha1_file_directory, X_OK) < 0)
-		return error("no access to SHA1 file directory");
-	fd = open(".git/index", O_RDONLY);
-	if (fd < 0)
-		return (errno == ENOENT) ? 0 : error("open failed");
-
-	size = 0; // avoid gcc warning
-	map = (void *)-1;
-	if (!fstat(fd, &st)) {
-		size = st.st_size;
-		errno = EINVAL;
-		if (size >= sizeof(struct cache_header))
-			map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-	}
-	close(fd);
-	if (-1 == (int)(long)map)
-		return error("mmap failed");
-
-	hdr = map;
-	if (verify_hdr(hdr, size) < 0)
-		goto unmap;
-
-	active_nr = hdr->entries;
-	active_alloc = alloc_nr(active_nr);
-	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
-
-	offset = sizeof(*hdr);
-	for (i = 0; i < hdr->entries; i++) {
-		struct cache_entry *ce = map + offset;
-		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
-	}
-	return active_nr;
-
-unmap:
-	munmap(map, size);
-	errno = EINVAL;
-	return error("verify header failed");
-}
-
-int write_cache(int newfd, struct cache_entry **cache, int entries)
-{
-	SHA_CTX c;
-	struct cache_header hdr;
-	int i;
-
-	hdr.signature = CACHE_SIGNATURE;
-	hdr.version = 1;
-	hdr.entries = entries;
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
-		int size = ce_size(ce);
-		SHA1_Update(&c, ce, size);
-	}
-	SHA1_Final(hdr.sha1, &c);
-
-	if (write(newfd, &hdr, sizeof(hdr)) != sizeof(hdr))
-		return -1;
-
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
-		int size = ce_size(ce);
-		if (write(newfd, ce, size) != size)
-			return -1;
-	}
-	return 0;
-}
Index: util.h
===================================================================
--- /dev/null  (tree:783978eb212c1402ba2612bb32626e93af78b72d)
+++ e8194c62bfc68725972a6847fa2c6d529ca64137/util.h  (mode:100644 sha1:d81ccd0b3363ff2a883e8d9e543af043728fd32a)
@@ -0,0 +1,9 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+/* General helper functions */
+extern void usage(const char *err);
+extern void die(const char *err, ...);
+extern int error(const char *err, ...);
+
+#endif


^ permalink raw reply	[relevance 13%]

* Re: [ANNOUNCE] git-pasky-0.4
  @ 2005-04-14 10:33 18% ` Russell King
  0 siblings, 0 replies; 200+ results
From: Russell King @ 2005-04-14 10:33 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

On Thu, Apr 14, 2005 at 02:19:38AM +0200, Petr Baudis wrote:
>   I'm happy to announce git-pasky-0.4, my set of scripts upon Linus
> Torvald's git, which aims to provide a humanly usable interface, to a
> degree similar to a SCM tool.

Here's my updated patch, against latest git-pasky.  Now using
hton*/ntoh* directly rather than wrapping them.  Enjoy.

--- cache.h
+++ cache.h	Thu Apr 14 11:27:22 2005
@@ -14,6 +14,8 @@
 #include <openssl/sha.h>
 #include <zlib.h>
 
+#include <netinet/in.h>
+
 /*
  * Basic data structures for the directory cache
  *
@@ -67,7 +69,7 @@
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
-#define ce_size(ce) cache_entry_size((ce)->namelen)
+#define ce_size(ce) cache_entry_size(ntohs((ce)->namelen))
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
--- checkout-cache.c
+++ checkout-cache.c	Thu Apr 14 11:25:40 2005
@@ -77,7 +77,7 @@
 		return error("checkout-cache: unable to read sha1 file of %s (%s)",
 			ce->name, sha1_to_hex(ce->sha1));
 	}
-	fd = create_file(ce->name, ce->st_mode);
+	fd = create_file(ce->name, ntohl(ce->st_mode));
 	if (fd < 0) {
 		free(new);
 		return error("checkout-cache: unable to create %s (%s)",
--- read-cache.c
+++ read-cache.c	Thu Apr 14 11:25:40 2005
@@ -288,27 +288,34 @@
 	/* nsec seems unreliable - not all filesystems support it, so
 	 * as long as it is in the inode cache you get right nsec
 	 * but after it gets flushed, you get zero nsec. */
-	if (ce->mtime.sec  != (unsigned int)st->st_mtim.tv_sec
+#if 0
+	if (ntohl(ce->mtime.sec)  != (unsigned int)st->st_mtim.tv_sec
 #ifdef NSEC
-	    || ce->mtime.nsec != (unsigned int)st->st_mtim.tv_nsec
+	    || ntohl(ce->mtime.nsec) != (unsigned int)st->st_mtim.tv_nsec
 #endif
 	    )
 		changed |= MTIME_CHANGED;
-	if (ce->ctime.sec  != (unsigned int)st->st_ctim.tv_sec
+	if (ntohl(ce->ctime.sec)  != (unsigned int)st->st_ctim.tv_sec
 #ifdef NSEC
-	    || ce->ctime.nsec != (unsigned int)st->st_ctim.tv_nsec
+	    || ntohl(ce->ctime.nsec) != (unsigned int)st->st_ctim.tv_nsec
 #endif
 	    )
 		changed |= CTIME_CHANGED;
-	if (ce->st_uid != (unsigned int)st->st_uid ||
-	    ce->st_gid != (unsigned int)st->st_gid)
+#else
+	if (ntohl(ce->mtime.sec)  != (unsigned int)st->st_mtime)
+		changed |= MTIME_CHANGED;
+	if (ntohl(ce->ctime.sec)  != (unsigned int)st->st_ctime)
+		changed |= CTIME_CHANGED;
+#endif
+	if (ntohl(ce->st_uid) != (unsigned int)st->st_uid ||
+	    ntohl(ce->st_gid) != (unsigned int)st->st_gid)
 		changed |= OWNER_CHANGED;
-	if (ce->st_mode != (unsigned int)st->st_mode)
+	if (ntohl(ce->st_mode) != (unsigned int)st->st_mode)
 		changed |= MODE_CHANGED;
-	if (ce->st_dev != (unsigned int)st->st_dev ||
-	    ce->st_ino != (unsigned int)st->st_ino)
+	if (ntohl(ce->st_dev) != (unsigned int)st->st_dev ||
+	    ntohl(ce->st_ino) != (unsigned int)st->st_ino)
 		changed |= INODE_CHANGED;
-	if (ce->st_size != (unsigned int)st->st_size)
+	if (ntohl(ce->st_size) != (unsigned int)st->st_size)
 		changed |= DATA_CHANGED;
 	return changed;
 }
@@ -337,7 +344,7 @@
 	while (last > first) {
 		int next = (last + first) >> 1;
 		struct cache_entry *ce = active_cache[next];
-		int cmp = cache_name_compare(name, namelen, ce->name, ce->namelen);
+		int cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->namelen));
 		if (!cmp)
 			return next;
 		if (cmp < 0) {
@@ -364,7 +371,7 @@
 {
 	int pos;
 
-	pos = cache_name_pos(ce->name, ce->namelen);
+	pos = cache_name_pos(ce->name, ntohs(ce->namelen));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
@@ -395,9 +402,9 @@
 	SHA_CTX c;
 	unsigned char sha1[20];
 
-	if (hdr->signature != CACHE_SIGNATURE)
+	if (hdr->signature != htonl(CACHE_SIGNATURE))
 		return error("bad signature");
-	if (hdr->version != 1)
+	if (hdr->version != htonl(1))
 		return error("bad version");
 	SHA1_Init(&c);
 	SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
@@ -445,12 +452,12 @@
 	if (verify_hdr(hdr, size) < 0)
 		goto unmap;
 
-	active_nr = hdr->entries;
+	active_nr = ntohl(hdr->entries);
 	active_alloc = alloc_nr(active_nr);
 	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
 
 	offset = sizeof(*hdr);
-	for (i = 0; i < hdr->entries; i++) {
+	for (i = 0; i < ntohl(hdr->entries); i++) {
 		struct cache_entry *ce = map + offset;
 		offset = offset + ce_size(ce);
 		active_cache[i] = ce;
@@ -469,9 +476,9 @@
 	struct cache_header hdr;
 	int i;
 
-	hdr.signature = CACHE_SIGNATURE;
-	hdr.version = 1;
-	hdr.entries = entries;
+	hdr.signature = htonl(CACHE_SIGNATURE);
+	hdr.version = htonl(1);
+	hdr.entries = htonl(entries);
 
 	SHA1_Init(&c);
 	SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
--- read-tree.c
+++ read-tree.c	Thu Apr 14 11:25:11 2005
@@ -13,8 +13,8 @@
 
 	memset(ce, 0, size);
 
-	ce->st_mode = mode;
-	ce->namelen = baselen + len;
+	ce->st_mode = htonl(mode);
+	ce->namelen = htons(baselen + len);
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
--- show-diff.c
+++ show-diff.c	Thu Apr 14 11:25:28 2005
@@ -90,7 +90,7 @@
 		changed = cache_match_stat(ce, &st);
 		if (!changed)
 			continue;
-		printf("%.*s:  ", ce->namelen, ce->name);
+		printf("%.*s:  ", ntohs(ce->namelen), ce->name);
 		for (n = 0; n < 20; n++)
 			printf("%02x", ce->sha1[n]);
 		printf("\n");
--- update-cache.c
+++ update-cache.c	Thu Apr 14 11:30:07 2005
@@ -68,18 +68,18 @@
  */
 static void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 {
-	ce->ctime.sec = st->st_ctime;
+	ce->ctime.sec = htonl(st->st_ctime);
 #ifdef NSEC
-	ce->ctime.nsec = st->st_ctim.tv_nsec;
+	ce->ctime.nsec = htonl(st->st_ctim.tv_nsec);
 #endif
-	ce->mtime.sec = st->st_mtime;
+	ce->mtime.sec = htonl(st->st_mtime);
 #ifdef NSEC
-	ce->mtime.nsec = st->st_mtim.tv_nsec;
+	ce->mtime.nsec = htonl(st->st_mtim.tv_nsec);
 #endif
-	ce->st_dev = st->st_dev;
-	ce->st_ino = st->st_ino;
-	ce->st_uid = st->st_uid;
-	ce->st_gid = st->st_gid;
+	ce->st_dev = htonl(st->st_dev);
+	ce->st_ino = htonl(st->st_ino);
+	ce->st_uid = htonl(st->st_uid);
+	ce->st_gid = htonl(st->st_gid);
 }
 
 static int add_file_to_cache(char *path)
@@ -107,9 +107,9 @@
 	memset(ce, 0, size);
 	memcpy(ce->name, path, namelen);
 	fill_stat_cache_info(ce, &st);
-	ce->st_mode = st.st_mode;
-	ce->st_size = st.st_size;
-	ce->namelen = namelen;
+	ce->st_mode = htonl(st.st_mode);
+	ce->st_size = htonl(st.st_size);
+	ce->namelen = htons(namelen);
 
 	if (index_fd(path, namelen, ce, fd, &st) < 0)
 		return -1;
@@ -190,7 +190,7 @@
 	updated = malloc(size);
 	memcpy(updated, ce, size);
 	fill_stat_cache_info(updated, &st);
-	updated->st_size = st.st_size;
+	updated->st_size = htonl(st.st_size);
 	return updated;
 }
 
--- write-tree.c
+++ write-tree.c	Thu Apr 14 11:25:40 2005
@@ -45,7 +45,7 @@
 	do {
 		struct cache_entry *ce = cachep[nr];
 		const char *pathname = ce->name, *filename, *dirname;
-		int pathlen = ce->namelen, entrylen;
+		int pathlen = ntohs(ce->namelen), entrylen;
 		unsigned char *sha1;
 		unsigned int mode;
 
@@ -54,7 +54,7 @@
 			break;
 
 		sha1 = ce->sha1;
-		mode = ce->st_mode;
+		mode = ntohl(ce->st_mode);
 
 		/* Do we have _further_ subdirectories? */
 		filename = pathname + baselen;

-- 
Russell King


^ permalink raw reply	[relevance 18%]

* Re: Merge with git-pasky II.
  @ 2005-04-16  1:44 10%                   ` Simon Fowler
  0 siblings, 0 replies; 200+ results
From: Simon Fowler @ 2005-04-16  1:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: David Woodhouse, Junio C Hamano, Petr Baudis, git


[-- Attachment #1.1: Type: text/plain, Size: 1189 bytes --]

On Fri, Apr 15, 2005 at 08:32:46AM -0700, Linus Torvalds wrote:
> In other words, I'm right. I'm always right, but sometimes I'm more right 
> than other times. And dammit, when I say "files don't matter", I'm really 
> really Right(tm).
> 
You're right, of course (All Hail Linus!), if you can make it work
efficiently enough.

Just to put something else on the table, here's how I'd go about
tracking renames and the like, in another world where Linus /does/
make the odd mistake - it's basically a unique id for files in the
repository, added when the file is first recognised and updated when
update-cache adds a new version to the cache. Renames copy the id
across to the new name, and add it into the cache.

This gives you an O(n) way to tell what file was what across
renames, and it might even be useful in Linus' world, or if someone
wanted to build a traditional SCM on top of a git-a-like.

Attached is a patch, and a rename-file.c to use it.

Simon

-- 
PGP public key Id 0x144A991C, or http://himi.org/stuff/himi.asc
(crappy) Homepage: http://himi.org
doe #237 (see http://www.lemuria.org/DeCSS) 
My DeCSS mirror: ftp://himi.org/pub/mirrors/css/ 

[-- Attachment #1.2: guid2.patch --]
[-- Type: text/plain, Size: 19027 bytes --]

COPYING:  fe2a4177a760fd110e78788734f167bd633be8de
Makefile:  ca50293c4f211452d999b81f122e99babb9f2987
--- Makefile
+++ Makefile	2005-04-15 22:17:49.000000000 +1000
@@ -14,7 +14,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
+	check-files ls-tree rename-file
 
 SCRIPT=	parent-id tree-id git gitXnormid.sh gitadd.sh gitaddremote.sh \
 	gitcommit.sh gitdiff-do gitdiff.sh gitlog.sh gitls.sh gitlsobj.sh \
@@ -73,6 +73,9 @@
 ls-tree: ls-tree.o read-cache.o
 	$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
 
+rename-file: rename-file.o read-cache.o
+	$(CC) $(CFLAGS) -o rename-file rename-file.o read-cache.o $(LIBS)
+
 read-cache.o: cache.h
 show-diff.o: cache.h
 
README:  ded1a3b20e9bbe1f40e487ba5f9361719a1b6b85
VERSION:  c27bd67cd632cc15dd520fbfbf807d482efa2dcf
cache.h:  4d382549041d3281f8d44aa2e52f9f8ec47dd420
--- cache.h
+++ cache.h	2005-04-14 22:35:59.000000000 +1000
@@ -55,6 +55,7 @@
 	unsigned int st_gid;
 	unsigned int st_size;
 	unsigned char sha1[20];
+	unsigned char guid[20];
 	unsigned short namelen;
 	char name[0];
 };
cat-file.c:  45be1badaa8517d4e3a69e0bf1cac2e90191e475
check-files.c:  927b0b9aca742183fc8e7ccd73d73d8d5427e98f
checkout-cache.c:  f06871cdbc1b18ea93bdf4e17126aeb4cca1373e
commit-id:  65c81756c8f10d513d073ecbd741a3244663c4c9
commit-tree.c:  12196c79f31d004dff0df1f50dda67d8204f5568
diff-tree.c:  7dcc9eb7782fa176e27f1677b161ce78ac1d2070
--- diff-tree.c
+++ diff-tree.c	2005-04-16 10:46:52.000000000 +1000
@@ -1,33 +1,144 @@
+#include <sys/param.h>
 #include "cache.h"
 
-static int recursive = 0;
+enum diff_type {
+	REMOVE,
+	ADD,
+	RENAME,
+	MODIFY,
+};
+
+struct guid_cache_entry {
+	enum diff_type diff;
+	unsigned char guid[20];
+	unsigned char sha1[20];
+	struct guid_cache_entry *old;
+	unsigned int mode;
+	unsigned int pathlen;
+	unsigned char path[0];
+};	
+
+struct guid_cache {
+	unsigned int nr;
+	unsigned int alloc;
+	struct guid_cache_entry **cache;
+};
 
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+struct guid_cache guid_cache;
+struct guid_cache *cache = &guid_cache;
 
-static void update_tree_entry(void **bufp, unsigned long *sizep)
+int guid_cache_pos(const char *guid)
 {
-	void *buf = *bufp;
-	unsigned long size = *sizep;
-	int len = strlen(buf) + 1 + 20;
+	int first, last;
 
-	if (size < len)
-		die("corrupt tree file");
-	*bufp = buf + len;
-	*sizep = size - len;
+	first = 0;
+	last = cache->nr;
+	while (last > first) {
+		int next = (last + first) >> 1;
+		struct guid_cache_entry *gce = cache->cache[next];
+		int cmp = memcmp(guid, gce->guid, 20);
+		if (!cmp)
+			return next;
+		if (cmp < 0) {
+			last = next;
+			continue;
+		}
+		first = next + 1;
+	}
+	return - first-1;
 }
 
-static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep)
+int add_guid_cache_entry(struct guid_cache_entry *gce)
+{
+	int pos;
+	
+	pos = guid_cache_pos(gce->guid);
+	
+	/* if this is a rename or modify, the guid will show up a
+	 * second time */
+	if (pos >= 0) {
+		struct guid_cache_entry *old = cache->cache[pos];
+		int cmp = cache_name_compare(old->path, old->pathlen, gce->path, gce->pathlen);
+
+		if (!cmp) {
+			/* pathname matches, so this must be a
+			 * modify. */
+			gce->old = old;
+			gce->diff = MODIFY;
+			cache->cache[pos] = gce;
+		} else {
+			/* the pathnames are different, so the file
+			 * must have been renamed somewhere along the
+			 * line.  */
+			gce->old = old;
+			gce->diff = RENAME;
+			cache->cache[pos] = gce;
+		}
+		return 0;
+	}
+	pos = -pos-1;
+
+	if (cache->nr == cache->alloc) {
+		cache->alloc = alloc_nr(cache->alloc);
+		cache->cache = realloc(cache->cache, cache->alloc * sizeof(struct guid_cache_entry *));
+	}
+
+	cache->nr++;
+	if (cache->nr > pos)
+		memmove(cache->cache + pos + 1, cache->cache + pos, (cache->nr - pos - 1) * sizeof(struct guid_cache_entry *));
+	cache->cache[pos] = gce;
+	return 0;
+}
+
+static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep, const unsigned char **guid)
 {
 	int len = strlen(tree)+1;
 	const unsigned char *sha1 = tree + len;
 	const char *path = strchr(tree, ' ');
 
-	if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1)
+	if (!path || size < len + 40 || sscanf(tree, "%o", modep) != 1)
 		die("corrupt tree file");
 	*pathp = path+1;
+	*guid = tree + len + 20;
 	return sha1;
 }
 
+static void guid_cache_tree_entry(void *buf, unsigned int len, const char *base, enum diff_type diff)
+{
+	unsigned mode;
+	const char *path;
+	const unsigned char *guid;
+	const unsigned char *sha1 = extract(buf, len, &path, &mode, &guid);
+	struct guid_cache_entry *gce;
+	int baselen = strlen(base);
+	
+	gce = calloc(1, sizeof(struct guid_cache_entry) + baselen + strlen(path) + 1);
+	memcpy(gce->guid, guid, 20);
+	memcpy(gce->sha1, sha1, 20);
+	gce->diff = diff;
+	gce->mode = mode;
+	gce->pathlen = snprintf(gce->path, MAXPATHLEN, "%s%s", base, path);
+	gce->path[gce->pathlen + 1] = '\0';
+
+	add_guid_cache_entry(gce);
+}
+	
+static int recursive = 0;
+
+static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+
+static void update_tree_entry(void **bufp, unsigned long *sizep)
+{
+	void *buf = *bufp;
+	unsigned long size = *sizep;
+	int len = strlen(buf) + 1 + 40;
+
+	if (size < len)
+		die("corrupt tree file");
+	*bufp = buf + len;
+	*sizep = size - len;
+}
+
 static char *malloc_base(const char *base, const char *path, int pathlen)
 {
 	int baselen = strlen(base);
@@ -38,23 +149,24 @@
 	return newbase;
 }
 
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base);
+static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff);
 
 /* A whole sub-tree went away or appeared */
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base)
+static void changed_tree(void *tree, unsigned long size, const char *base, enum diff_type diff)
 {
 	while (size) {
-		show_file(prefix, tree, size, base);
+		changed_file(tree, size, base, diff);
 		update_tree_entry(&tree, &size);
 	}
 }
 
 /* A file entry went away or appeared */
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
+static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff)
 {
 	unsigned mode;
 	const char *path;
-	const unsigned char *sha1 = extract(tree, size, &path, &mode);
+	const unsigned char *guid;
+	const unsigned char *sha1 = extract(tree, size, &path, &mode, &guid);
 
 	if (recursive && S_ISDIR(mode)) {
 		char type[20];
@@ -66,38 +178,96 @@
 		if (!tree || strcmp(type, "tree"))
 			die("corrupt tree sha %s", sha1_to_hex(sha1));
 
-		show_tree(prefix, tree, size, newbase);
+		changed_tree(tree, size, newbase, diff);
 		
 		free(tree);
 		free(newbase);
 		return;
 	}
 
-	printf("%s%o\t%s\t%s\t%s%s%c", prefix, mode,
-	       S_ISDIR(mode) ? "tree" : "blob",
-	       sha1_to_hex(sha1), base, path, 0);
+	guid_cache_tree_entry(tree, size, base, diff);
 }
 
+static void show_one_file(struct guid_cache_entry *gce)
+{
+	struct guid_cache_entry *old;
+	char old_sha1[50];
+	char old_sha2[50];
+
+	switch(gce->diff) {
+	case REMOVE:
+		sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+		printf("-%o\t%s\t%s\t%s\t%s%c", gce->mode,
+		       S_ISDIR(gce->mode) ? "tree" : "blob",
+		       old_sha1, sha1_to_hex(gce->guid), gce->path, 0);
+		break;
+	case ADD:
+		sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+		printf("+%o\t%s\t%s\t%s\t%s%c", gce->mode,
+		       S_ISDIR(gce->mode) ? "tree" : "blob",
+		       old_sha1, sha1_to_hex(gce->guid), gce->path, 0);
+		break;
+	case MODIFY:
+		old = gce->old;
+		if (old) {
+			sprintf(old_sha1, "%s", sha1_to_hex(old->sha1));
+			sprintf(old_sha2, "%s", sha1_to_hex(gce->sha1));
+			
+			printf("*%o->%o\t%s\t%s->%s\t%s\t%s%c", old->mode, gce->mode,
+			       S_ISDIR(old->mode) ? "tree" : "blob",
+			       old_sha1, old_sha2, sha1_to_hex(gce->guid), gce->path, 0);
+		} else {
+			die("diff-tree: internal error");
+		}
+		break;
+	case RENAME:
+		old = gce->old;
+		if (old) {
+			sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1));
+			sprintf(old_sha2, "%s", sha1_to_hex(old->sha1));
+			
+			printf("r%o->%o\t%s\t%s->%s\t%s\t%s%c", gce->mode, old->mode,
+			       S_ISDIR(old->mode) ? "tree" : "blob",
+			       old_sha1, old_sha2, sha1_to_hex(old->guid), old->path, 0);
+		} else {
+			die("diff-tree: internal error");
+		}
+		break;
+	default:
+		die("diff-tree: internal error");
+	}
+}
+
+/* simply iterate over both caches looking for matching guids,
+ * showing all files in both caches */
+static void show_cache(void)
+{
+	int i;
+
+	for (i = 0; i < cache->nr; i++)
+		show_one_file(cache->cache[i]);
+}
+	
 static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
 {
 	unsigned mode1, mode2;
 	const char *path1, *path2;
 	const unsigned char *sha1, *sha2;
+	const unsigned char *guid1, *guid2;
 	int cmp, pathlen1, pathlen2;
-	char old_sha1_hex[50];
 
-	sha1 = extract(tree1, size1, &path1, &mode1);
-	sha2 = extract(tree2, size2, &path2, &mode2);
+	sha1 = extract(tree1, size1, &path1, &mode1, &guid1);
+	sha2 = extract(tree2, size2, &path2, &mode2, &guid2);
 
 	pathlen1 = strlen(path1);
 	pathlen2 = strlen(path2);
 	cmp = cache_name_compare(path1, pathlen1, path2, pathlen2);
 	if (cmp < 0) {
-		show_file("-", tree1, size1, base);
+		changed_file(tree1, size1, base, REMOVE);
 		return -1;
 	}
 	if (cmp > 0) {
-		show_file("+", tree2, size2, base);
+		changed_file(tree2, size2, base, ADD);
 		return 1;
 	}
 	if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
@@ -108,8 +278,8 @@
 	 * file, we need to consider it a remove and an add.
 	 */
 	if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-		show_file("-", tree1, size1, base);
-		show_file("+", tree2, size2, base);
+		changed_file(tree1, size1, base, REMOVE);
+		changed_file(tree2, size2, base, ADD);
 		return 0;
 	}
 
@@ -121,10 +291,14 @@
 		return retval;
 	}
 
-	strcpy(old_sha1_hex, sha1_to_hex(sha1));
-	printf("*%o->%o\t%s\t%s->%s\t%s%s%c", mode1, mode2,
-	       S_ISDIR(mode1) ? "tree" : "blob",
-	       old_sha1_hex, sha1_to_hex(sha2), base, path1, 0);
+	if (!memcmp(guid1, guid2, 20)) {
+		changed_file(tree1, size1, base, MODIFY);
+		changed_file(tree2, size2, base, MODIFY);
+		return 0;
+	}
+	
+	changed_file(tree1, size1, base, REMOVE);
+	changed_file(tree2, size2, base, ADD);
 	return 0;
 }
 
@@ -132,12 +306,12 @@
 {
 	while (size1 | size2) {
 		if (!size1) {
-			show_file("+", tree2, size2, base);
+			changed_file(tree2, size2, base, ADD);
 			update_tree_entry(&tree2, &size2);
 			continue;
 		}
 		if (!size2) {
-			show_file("-", tree1, size1, base);
+			changed_file(tree1, size1, base, REMOVE);
 			update_tree_entry(&tree1, &size1);
 			continue;
 		}
@@ -179,6 +353,7 @@
 int main(int argc, char **argv)
 {
 	unsigned char old[20], new[20];
+	int retval;
 
 	while (argc > 3) {
 		char *arg = argv[1];
@@ -193,5 +368,7 @@
 
 	if (argc != 3 || get_sha1_hex(argv[1], old) || get_sha1_hex(argv[2], new))
 		usage("diff-tree <tree sha1> <tree sha1>");
-	return diff_tree_sha1(old, new, "");
+	retval =  diff_tree_sha1(old, new, "");
+	show_cache();
+	return retval;
 }
fsck-cache.c:  9c900fe458cecd2bdb4c4571a584115b5cf24f22
--- fsck-cache.c
+++ fsck-cache.c	2005-04-15 20:39:49.000000000 +1000
@@ -165,9 +165,10 @@
 	while (size) {
 		int len = 1+strlen(data);
 		unsigned char *file_sha1 = data + len;
+		unsigned char *guid = file_sha1 + 20;
 		char *path = strchr(data, ' ');
 		unsigned int mode;
-		if (size < len + 20 || !path || sscanf(data, "%o", &mode) != 1)
+		if (size < len + 40 || !path || sscanf(data, "%o", &mode) != 1)
 			return -1;
 
 		/* Warn about trees that don't do the recursive thing.. */
@@ -176,8 +177,8 @@
 			warn_old_tree = 0;
 		}
 
-		data += len + 20;
-		size -= len + 20;
+		data += len + 40;
+		size -= len + 40;
 		mark_needs_sha1(sha1, S_ISDIR(mode) ? "tree" : "blob", file_sha1);
 	}
 	return 0;
git:  2c557dcf2032325acc265b577ee104e605fdaede
gitXnormid.sh:  a5d7a9f4a6e8d4860f35f69500965c2a493d80de
gitadd.sh:  3ed93ea0fcb995673ba9ee1982e0e7abdbe35982
gitaddremote.sh:  bf1f28823da5b5270aa8fa05b321faa514a57a11
gitapply.sh:  d0e3c46e2ce1ee74e1a87ee6137955fa9b35c27b
gitcancel.sh:  ec58f7444a42cd3cbaae919fc68c70a3866420c0
gitcommit.sh:  3629f67bbd3f171d091552814908b67af7537f4d
gitdiff-do:  d6174abceab34d22010c36a8453a6c3f3f184fe0
gitdiff.sh:  5e47c4779d73c3f2f39f6be714c0145175933197
gitexport.sh:  dad00bf251b38ce522c593ea9631f842d8ccc934
gitlntree.sh:  17c4966ea64aeced96ae4f1b00f3775c1904b0f1
gitlog.sh:  177c6d12dd9fa4b4920b08451ffe4badde544a39
gitls.sh:  b6f15d82f16c1e9982c5031f3be22eb5430273af
gitlsobj.sh:  128461d3de6a42cfaaa989fc6401bebdfa885b3f
gitmerge.sh:  23e4a3ff342c6005928ceea598a2f52de6fb9817
gitpull.sh:  0883898dda579e3fa44944b7b1d909257f6dc63e
gitrm.sh:  5c18c38a890c9fd9ad2b866ee7b529539d2f3f8f
gittag.sh:  c8cb31385d5a9622e95a4e0b2d6a4198038a659c
gittrack.sh:  03d6db1fb3a70605ef249c632c04e542457f0808
init-db.c:  aa00fbb1b95624f6c30090a17354c9c08a6ac596
ls-tree.c:  3e2a6c7d183a42e41f1073dfec6794e8f8a5e75c
--- ls-tree.c
+++ ls-tree.c	2005-04-15 15:55:40.000000000 +1000
@@ -10,6 +10,7 @@
 	void *buffer;
 	unsigned long size;
 	char type[20];
+	char old_sha1[50];
 
 	buffer = read_sha1_file(sha1, type, &size);
 	if (!buffer)
@@ -19,19 +20,21 @@
 	while (size) {
 		int len = strlen(buffer)+1;
 		unsigned char *sha1 = buffer + len;
+		unsigned char *guid = buffer + len + 20;
 		char *path = strchr(buffer, ' ')+1;
 		unsigned int mode;
 		unsigned char *type;
 
-		if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
+		if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1)
 			die("corrupt 'tree' file");
-		buffer = sha1 + 20;
-		size -= len + 20;
+		buffer = sha1 + 40;
+		size -= len + 40;
 		/* XXX: We do some ugly mode heuristics here.
 		 * It seems not worth it to read each file just to get this
 		 * and the file size. -- pasky@ucw.cz */
 		type = S_ISDIR(mode) ? "tree" : "blob";
-		printf("%03o\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), path);
+		sprintf(old_sha1, sha1_to_hex(guid));
+		printf("%03o\t%s\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), old_sha1, path);
 	}
 	return 0;
 }
parent-id:  1801c6fe426592832e7250f8b760fb9d2e65220f
read-cache.c:  7a6ae8b9b489f6b67c82e065dedd5716a6bfc0ef
--- read-cache.c
+++ read-cache.c	2005-04-16 10:52:51.000000000 +1000
@@ -4,6 +4,8 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include <stdarg.h>
+#include <time.h>
+#include <sys/param.h>
 #include "cache.h"
 
 const char *sha1_file_directory = NULL;
@@ -233,6 +235,22 @@
 	return 0;
 }
 
+void new_guid(const char *filename, int namelen, unsigned char *returnguid)
+{
+	size_t size;
+	time_t now = time(NULL);
+	char buf[MAXPATHLEN + 20];
+	unsigned char guid[20];
+	
+	size = snprintf(buf, MAXPATHLEN + 20, "%ld%s", now, filename) + 1;
+	
+	SHA1(buf, size, guid);
+
+	if (returnguid)
+		memcpy(returnguid, guid, 20);
+	return;
+}
+
 static inline int collision_check(char *filename, void *buf, unsigned int size)
 {
 #ifdef COLLISION_CHECK
@@ -363,11 +381,14 @@
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 {
 	int pos;
+	unsigned char guid[20];
 
 	pos = cache_name_pos(ce->name, ce->namelen);
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
+		struct cache_entry *old_ce = active_cache[pos];
+		memcpy(ce->guid, old_ce->guid, 20);
 		active_cache[pos] = ce;
 		return 0;
 	}
@@ -376,6 +397,12 @@
 	if (!ok_to_add)
 		return -1;
 
+	memset(guid, 0, 20);
+	if (!memcmp(ce->guid, guid, 20)) {
+		new_guid(ce->name, ce->namelen, guid);
+		memcpy(ce->guid, guid, 20);
+	}
+
 	/* Make sure the array is big enough .. */
 	if (active_nr == active_alloc) {
 		active_alloc = alloc_nr(active_alloc);
read-tree.c:  eb548148aa6d212f05c2c622ffbe62a06cd072f9
--- read-tree.c
+++ read-tree.c	2005-04-16 10:41:46.000000000 +1000
@@ -5,7 +5,9 @@
  */
 #include "cache.h"
 
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
+static int read_one_entry(unsigned char *sha1, unsigned char *guid, 
+			  const char *base, int baselen, 
+			  const char *pathname, unsigned mode)
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
@@ -18,6 +20,7 @@
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
+	memcpy(ce->guid, guid, 20);
 	return add_cache_entry(ce, 1);
 }
 
@@ -35,14 +38,15 @@
 	while (size) {
 		int len = strlen(buffer)+1;
 		unsigned char *sha1 = buffer + len;
+		unsigned char *guid = buffer + len + 20;
 		char *path = strchr(buffer, ' ')+1;
 		unsigned int mode;
-
-		if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
+		
+		if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1)
 			return -1;
 
-		buffer = sha1 + 20;
-		size -= len + 20;
+		buffer = sha1 + 40;
+		size -= len + 40;
 
 		if (S_ISDIR(mode)) {
 			int retval;
@@ -57,7 +61,7 @@
 				return -1;
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode) < 0)
+		if (read_one_entry(sha1, guid, base, baselen, path, mode) < 0)
 			return -1;
 	}
 	return 0;
rev-tree.c:  395b0b3bfadb0537ae0c62744b25ead4b487f3f6
show-diff.c:  a531ca4078525d1c8dcf84aae0bfa89fed6e5d96
show-files.c:  a9fa6767a418f870a34b39379f417bf37b17ee18
tree-id:  cb70e2c508a18107abe305633612ed702aa3ee4f
update-cache.c:  62d0a6c41560d40863c44599355af10d9e089312
write-tree.c:  1534477c91169ebddcf953e3f4d2872495477f6b
--- write-tree.c
+++ write-tree.c	2005-04-15 13:46:05.000000000 +1000
@@ -47,6 +47,7 @@
 		const char *pathname = ce->name, *filename, *dirname;
 		int pathlen = ce->namelen, entrylen;
 		unsigned char *sha1;
+		unsigned char *guid;
 		unsigned int mode;
 
 		/* Did we hit the end of the directory? Return how many we wrote */
@@ -54,6 +55,7 @@
 			break;
 
 		sha1 = ce->sha1;
+		guid = ce->guid;
 		mode = ce->st_mode;
 
 		/* Do we have _further_ subdirectories? */
@@ -86,6 +88,8 @@
 		buffer[offset++] = 0;
 		memcpy(buffer + offset, sha1, 20);
 		offset += 20;
+		memcpy(buffer + offset, guid, 20);
+		offset += 20;
 		nr++;
 	} while (nr < maxentries);
 

[-- Attachment #1.3: rename-file.c --]
[-- Type: text/x-csrc, Size: 1703 bytes --]

/*
 * rename files in a git repository, keeping the guid.
 * 
 * Copyright Simon Fowler <simon@dreamcraft.com.au>, 2005.
 */
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include "cache.h"

static int remove_lock = 0;

static void remove_lock_file(void)
{
	if (remove_lock)
		unlink(".git/index.lock");
}

int main(int argc, char *argv[])
{
	struct stat stats;
	struct cache_entry *ce, *new;
	int newfd, entries, pos, pos2;

	if (argc != 3)
		usage("rename-file <old> <new>");
	if (stat(argv[1], &stats)) {
		perror("rename-file: ");
		exit(1);
	}
	if (!stat(argv[2], &stats))
		die("rename-file: destination file already exists");
	
	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
	if (newfd < 0)
		die("unable to create new cachefile");

	atexit(remove_lock_file);
	remove_lock = 1;

	entries = read_cache();
	if (entries < 0)
		die("cache corrupted");

	pos = cache_name_pos(argv[1], strlen(argv[1]));
	pos2 = cache_name_pos(argv[2], strlen(argv[2]));
		
	if (pos < 0) 
		die("original file not in cache");
	if (pos2 >= 0)
		die("destination file already in cache");
	ce = active_cache[pos];
	new = malloc(sizeof(struct cache_entry) + strlen(argv[2]) + 1);
	memcpy(new, ce, sizeof(struct cache_entry));
	new->namelen = strlen(argv[2]);
	memcpy(new->name, argv[2], new->namelen);
	
	if (rename(argv[1], argv[2])) {
		perror("rename-file: ");
		exit(1);
	}

	remove_file_from_cache(argv[1]);
	add_cache_entry(new, 1);

	if (write_cache(newfd, active_cache, active_nr) ||
	    rename(".git/index.lock", ".git/index"))
		die("Unable to write new cachefile");
      
	remove_lock = 0;
	return 0;
}

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 10%]

* [PATCH] Byteorder fix for read-tree, new -m semantics version.
  @ 2005-04-16  9:27 19%                                           ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-04-16  9:27 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

The ce_namelen field has been renamed to ce_flags and split into
the top 2-bit unused, next 2-bit stage number and the lowest
12-bit name-length, stored in the network byte order.  A new
macro create_ce_flags() is defined to synthesize this value from
length and stage, but it forgets to turn the value into the
network byte order.  Here is a fix.

The patch is against 9c03bd47892d11d0bb28c442184786db3c189978.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

--- cache.h
+++ cache.h	2005-04-16 02:22:05.000000000 -0700
@@ -66,7 +66,7 @@
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 
-#define create_ce_flags(len, stage) ((len) | ((stage) << 12))
+#define create_ce_flags(len, stage) htons((len) | ((stage) << 12))
 
 const char *sha1_file_directory;
 struct cache_entry **active_cache;



^ permalink raw reply	[relevance 19%]

* active_cache leaks
@ 2005-04-17  7:07 20% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-17  7:07 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1071 bytes --]

Ok.. so there's been a couple attempts to patch the leak that were all
wrong due to mixed memory management for that array.  Here's a seed for
discussion on how to plug that leak.  Some would argue that it's not
leaking enough to fix, but for those that want to turn git into a library,
the lifetime of the cache could end up not being short any more, so it's
worth discussing how to fix it.

The q&d fix in this patch isn't elegant, but gets the job done.  More
interesting could be to have the entry itself contain a state bit, though
that wastes storage space.

Two basic changes:

1) introduce a set_active_cache() api and change all 'active_cache[i] = ce'
   calls to use it.
2) add a active_cache_malloced array to parallel the active_cache array.

I don't like #2, but see that q&d comment. :)

It's only lightly tested as I'm still trying to wrap my head around how to
actually use git and git-pasky.

I was tempted to add a get_cache_entry api as well, so that nothing
outside of read-cache.c touched active_cache directly, but that can come
next.

Later,
Brad


[-- Attachment #2: git-active-cache-leak.diff --]
[-- Type: TEXT/plain, Size: 2921 bytes --]

--- cache.h
+++ cache.h	2005-04-16 23:08:37.000000000 -0700
@@ -88,6 +88,7 @@
 extern int read_cache(void);
 extern int write_cache(int newfd, struct cache_entry **cache, int entries);
 extern int cache_name_pos(const char *name, int namelen);
+extern int set_cache_entry(struct cache_entry *ce, int pos, int malloced_entry);
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
 extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
--- read-cache.c
+++ read-cache.c	2005-04-16 23:32:34.000000000 -0700
@@ -8,6 +8,7 @@
 
 const char *sha1_file_directory = NULL;
 struct cache_entry **active_cache = NULL;
+static int * active_cache_malloced = NULL;
 unsigned int active_nr = 0, active_alloc = 0;
 
 void usage(const char *err)
@@ -381,6 +382,15 @@
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
+int set_cache_entry(struct cache_entry *ce, int pos, int malloced_entry)
+{
+	if (active_cache_malloced[pos])
+		free(active_cache[pos]);
+	active_cache[pos] = ce;
+	active_cache_malloced[pos] = malloced_entry;
+	return 0;
+}
+
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 {
 	int pos;
@@ -389,7 +399,7 @@
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
-		active_cache[pos] = ce;
+		set_cache_entry(ce, pos, 0);
 		return 0;
 	}
 	pos = -pos-1;
@@ -414,13 +424,16 @@
 	if (active_nr == active_alloc) {
 		active_alloc = alloc_nr(active_alloc);
 		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+		active_cache_malloced = realloc(active_cache, active_alloc * sizeof(int));
 	}
 
 	/* Add it in.. */
 	active_nr++;
-	if (active_nr > pos)
+	if (active_nr > pos) {
 		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
+		memmove(active_cache_malloced + pos + 1, active_cache_malloced + pos, (active_nr - pos - 1) * sizeof(int));
+	}
+	set_cache_entry(ce, pos, 1);
 	return 0;
 }
 
@@ -482,12 +495,13 @@
 	active_nr = ntohl(hdr->hdr_entries);
 	active_alloc = alloc_nr(active_nr);
 	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
+	active_cache_malloced = calloc(active_alloc, sizeof(int));
 
 	offset = sizeof(*hdr);
 	for (i = 0; i < active_nr; i++) {
 		struct cache_entry *ce = map + offset;
 		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
+		set_cache_entry(ce, i, 0);
 	}
 	return active_nr;
 
--- update-cache.c
+++ update-cache.c	2005-04-16 23:33:28.000000000 -0700
@@ -199,11 +199,14 @@
 		struct cache_entry *ce = active_cache[i];
 		struct cache_entry *new = refresh_entry(ce);
 
+		if (new == ce)
+			continue;
+
 		if (!new) {
 			printf("%s: needs update\n", ce->name);
 			continue;
 		}
-		active_cache[i] = new;
+		set_cache_entry(new, i, 1);
 	}
 }
 

^ permalink raw reply	[relevance 20%]

* [PATCH] use gcrypt instead of libssl for hash
@ 2005-04-17 10:52 19% Junichi Uekawa
    0 siblings, 1 reply; 200+ results
From: Junichi Uekawa @ 2005-04-17 10:52 UTC (permalink / raw)
  To: torvalds, git

[-- Attachment #1: Type: text/plain, Size: 4691 bytes --]


Hi,

This is the first  time for me to send you a patch; be gentle.
the following patch allows for use of gcrypt.

libssl seems to have a restrictive licensing wrt GPL applications.

This patch adds a requirement for libgcrypt11, and 
removes the requirement for libssl.

I hope I have not overlooked anything.


Signed-off-by: Junichi Uekawa <dancer@debian.org>


Makefile: 770595e02be4a9a55ff98910c53617c3b0f1e145
--- Makefile
+++ Makefile	2005-04-17 19:38:00.000000000 +0900
@@ -7,7 +7,7 @@
 # BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely randomly
 # break unless your underlying filesystem supports those sub-second times
 # (my ext3 doesn't).
-CFLAGS=-g -O3 -Wall
+CFLAGS=-g -O3 -Wall $(shell libgcrypt-config --cflags)
 
 CC=gcc
 
@@ -21,7 +21,7 @@
 install: $(PROG)
 	install $(PROG) $(HOME)/bin/
 
-LIBS= -lssl -lz
+LIBS= $(shell libgcrypt-config --libs) -lz
 
 init-db: init-db.o
 
cache.h: 5948db759b3f6fb5ade3b027f202330f71a8cb6a
--- cache.h
+++ cache.h	2005-04-17 19:25:40.000000000 +0900
@@ -12,7 +12,7 @@
 #include <sys/mman.h>
 #include <netinet/in.h>
 
-#include <openssl/sha.h>
+#include <gcrypt.h>
 #include <zlib.h>
 
 /*
read-cache.c: 740ffcce7026b268bd4dfe1d0a773ad7e3a24f96
--- read-cache.c
+++ read-cache.c	2005-04-17 19:34:37.000000000 +0900
@@ -116,11 +116,14 @@
 int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size)
 {
 	unsigned char real_sha1[20];
-	SHA_CTX c;
+	gcry_md_hd_t c;
 
-	SHA1_Init(&c);
-	SHA1_Update(&c, map, size);
-	SHA1_Final(real_sha1, &c);
+	gcry_md_open(&c, GCRY_MD_SHA1, 0);
+	gcry_md_write(c, map, size);
+	gcry_md_final(c);
+	memcpy(real_sha1, gcry_md_read(c, 0), 20);
+	gcry_md_close(c);
+	
 	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
 }
 
@@ -203,7 +206,7 @@
 	char *compressed;
 	z_stream stream;
 	unsigned char sha1[20];
-	SHA_CTX c;
+	gcry_md_hd_t c;
 
 	/* Set it up */
 	memset(&stream, 0, sizeof(stream));
@@ -222,9 +225,11 @@
 	size = stream.total_out;
 
 	/* Sha1.. */
-	SHA1_Init(&c);
-	SHA1_Update(&c, compressed, size);
-	SHA1_Final(sha1, &c);
+	gcry_md_open(&c, GCRY_MD_SHA1, 0);
+	gcry_md_write(c, compressed, size);
+	gcry_md_final(c);
+	memcpy(sha1, gcry_md_read(c, 0), 20);
+	gcry_md_close(c);
 
 	if (write_sha1_buffer(sha1, compressed, size) < 0)
 		return -1;
@@ -425,17 +430,20 @@
 
 static int verify_hdr(struct cache_header *hdr, unsigned long size)
 {
-	SHA_CTX c;
+	gcry_md_hd_t c;
 	unsigned char sha1[20];
 
 	if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
 		return error("bad signature");
 	if (hdr->hdr_version != htonl(1))
 		return error("bad version");
-	SHA1_Init(&c);
-	SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
-	SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
-	SHA1_Final(sha1, &c);
+	gcry_md_open(&c, GCRY_MD_SHA1, 0);
+	gcry_md_write(c, hdr, offsetof(struct cache_header, sha1));
+	gcry_md_write(c, hdr+1, size - sizeof(*hdr));
+	gcry_md_final(c);
+	memcpy(sha1, gcry_md_read(c, 0), 20);
+	gcry_md_close(c);
+
 	if (memcmp(sha1, hdr->sha1, 20))
 		return error("bad header sha1");
 	return 0;
@@ -498,7 +506,8 @@
 
 int write_cache(int newfd, struct cache_entry **cache, int entries)
 {
-	SHA_CTX c;
+	gcry_md_hd_t c;
+
 	struct cache_header hdr;
 	int i;
 
@@ -506,14 +515,16 @@
 	hdr.hdr_version = htonl(1);
 	hdr.hdr_entries = htonl(entries);
 
-	SHA1_Init(&c);
-	SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
+	gcry_md_open(&c, GCRY_MD_SHA1, 0);
+	gcry_md_write(c, &hdr, offsetof(struct cache_header, sha1));
 	for (i = 0; i < entries; i++) {
 		struct cache_entry *ce = cache[i];
 		int size = ce_size(ce);
-		SHA1_Update(&c, ce, size);
+		gcry_md_write(c, ce, size);
 	}
-	SHA1_Final(hdr.sha1, &c);
+	gcry_md_final(c);
+	memcpy(hdr.sha1, gcry_md_read(c, 0), 20);
+	gcry_md_close(c);
 
 	if (write(newfd, &hdr, sizeof(hdr)) != sizeof(hdr))
 		return -1;
update-cache.c: 5afecd1a4fd90d2505753ce2d5044d780fe69a7f
--- update-cache.c
+++ update-cache.c	2005-04-17 19:36:40.000000000 +0900
@@ -22,7 +22,7 @@
 	void *out = malloc(max_out_bytes);
 	void *metadata = malloc(namelen + 200);
 	void *in;
-	SHA_CTX c;
+	gcry_md_hd_t c;
 
 	in = "";
 	if (size)
@@ -54,9 +54,11 @@
 
 	deflateEnd(&stream);
 	
-	SHA1_Init(&c);
-	SHA1_Update(&c, out, stream.total_out);
-	SHA1_Final(ce->sha1, &c);
+	gcry_md_open(&c, GCRY_MD_SHA1, 0);
+	gcry_md_write(c, out, stream.total_out);
+	gcry_md_final(c);
+	memcpy(ce->sha1, gcry_md_read(c, 0), 20);
+	gcry_md_close(c);
 
 	return write_sha1_buffer(ce->sha1, out, stream.total_out);
 }
write-tree.c: 34a351b20fb38ea588f34bd9634f101b9dc533cb


regards,
	junichi


-- 
Junichi Uekawa, Debian Developer
17D6 120E 4455 1832 9423  7447 3059 BF92 CD37 56F4
http://www.netfort.gr.jp/~dancer/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 19%]

* Re: [PATCH] use gcrypt instead of libssl for hash
  @ 2005-04-18  3:58 19%   ` Edgar Toernig
  0 siblings, 0 replies; 200+ results
From: Edgar Toernig @ 2005-04-18  3:58 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junichi Uekawa, git

Linus Torvalds wrote:
>
> Well, libgcrypt seems to be pretty rare out there - I certainly don't have 
> it installed on my machine.

Well, I don't even have openssl ...

> Or merge the SHA1 code from the kernel, even, and make the project
> entirely self-sufficient.

... so I took the sha1 code from Firefox (it's MPL or GPL - you choose).

Here's the patch.

diff -ruN git-0.04-orig/Makefile git-0.04/Makefile
--- git-0.04-orig/Makefile	Mon Apr 11 05:48:10 2005
+++ git-0.04/Makefile	Mon Apr 18 05:41:49 2005
@@ -9,42 +9,57 @@
 install: $(PROG)
 	install $(PROG) $(HOME)/bin/
 
-LIBS= -lssl -lz
+LIBS= -lz
 
 init-db: init-db.o
 
-update-cache: update-cache.o read-cache.o
-	$(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)
+update-cache: update-cache.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o sha1.o $(LIBS)
 
-show-diff: show-diff.o read-cache.o
-	$(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o $(LIBS)
+show-diff: show-diff.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o sha1.o $(LIBS)
 
-write-tree: write-tree.o read-cache.o
-	$(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o $(LIBS)
+write-tree: write-tree.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o sha1.o $(LIBS)
 
-read-tree: read-tree.o read-cache.o
-	$(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o $(LIBS)
+read-tree: read-tree.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o sha1.o $(LIBS)
 
-commit-tree: commit-tree.o read-cache.o
-	$(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o $(LIBS)
+commit-tree: commit-tree.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o sha1.o $(LIBS)
 
-cat-file: cat-file.o read-cache.o
-	$(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)
+cat-file: cat-file.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o sha1.o $(LIBS)
 
-fsck-cache: fsck-cache.o read-cache.o
-	$(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o $(LIBS)
+fsck-cache: fsck-cache.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o sha1.o $(LIBS)
 
-checkout-cache: checkout-cache.o read-cache.o
-	$(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)
+checkout-cache: checkout-cache.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o sha1.o $(LIBS)
 
-diff-tree: diff-tree.o read-cache.o
-	$(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)
-
-read-cache.o: cache.h
-show-diff.o: cache.h
+diff-tree: diff-tree.o read-cache.o sha1.o
+	$(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o sha1.o $(LIBS)
 
 clean:
 	rm -f *.o $(PROG) temp_git_file_*
 
 backup: clean
 	cd .. ; tar czvf dircache.tar.gz dir-cache
+
+depend:
+	makedepend -Y -- -- *.c 2>/dev/null
+
+# DO NOT DELETE
+
+cat-file.o: cache.h sha1.h
+checkout-cache.o: cache.h sha1.h
+commit-tree.o: cache.h sha1.h
+diff-tree.o: cache.h sha1.h
+fsck-cache.o: cache.h sha1.h
+init-db.o: cache.h sha1.h
+read-cache.o: cache.h sha1.h
+read-tree.o: cache.h sha1.h
+sha1.o: sha1.h
+show-diff.o: cache.h sha1.h
+update-cache.o: cache.h sha1.h
+write-tree.o: cache.h sha1.h
diff -ruN git-0.04-orig/cache.h git-0.04/cache.h
--- git-0.04-orig/cache.h	Sun Apr 10 20:19:02 2005
+++ git-0.04/cache.h	Mon Apr 18 05:46:47 2005
@@ -11,7 +11,7 @@
 #include <errno.h>
 #include <sys/mman.h>
 
-#include <openssl/sha.h>
+#include "sha1.h"
 #include <zlib.h>
 
 /*
diff -ruN git-0.04-orig/sha1.c git-0.04/sha1.c
--- git-0.04-orig/sha1.c	Thu Jan  1 01:00:00 1970
+++ git-0.04/sha1.c	Mon Apr 18 05:40:25 2005
@@ -0,0 +1,152 @@
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is SHA 180-1 Reference Implementation (Compact version)
+ * 
+ * The Initial Developer of the Original Code is Paul Kocher of
+ * Cryptography Research.  Portions created by Paul Kocher are 
+ * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ *
+ *     Paul Kocher
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "sha1.h"
+
+static void shaHashBlock(SHA_CTX *ctx);
+
+void SHA1_Init(SHA_CTX *ctx) {
+  int i;
+
+  ctx->lenW = 0;
+  ctx->sizeHi = ctx->sizeLo = 0;
+
+  /* Initialize H with the magic constants (see FIPS180 for constants)
+   */
+  ctx->H[0] = 0x67452301;
+  ctx->H[1] = 0xefcdab89;
+  ctx->H[2] = 0x98badcfe;
+  ctx->H[3] = 0x10325476;
+  ctx->H[4] = 0xc3d2e1f0;
+
+  for (i = 0; i < 80; i++)
+    ctx->W[i] = 0;
+}
+
+
+void SHA1_Update(SHA_CTX *ctx, void *_dataIn, int len) {
+  unsigned char *dataIn = _dataIn;
+  int i;
+
+  /* Read the data into W and process blocks as they get full
+   */
+  for (i = 0; i < len; i++) {
+    ctx->W[ctx->lenW / 4] <<= 8;
+    ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i];
+    if ((++ctx->lenW) % 64 == 0) {
+      shaHashBlock(ctx);
+      ctx->lenW = 0;
+    }
+    ctx->sizeLo += 8;
+    ctx->sizeHi += (ctx->sizeLo < 8);
+  }
+}
+
+
+void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx) {
+  unsigned char pad0x80 = 0x80;
+  unsigned char pad0x00 = 0x00;
+  unsigned char padlen[8];
+  int i;
+
+  /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+   */
+  padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
+  padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
+  padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
+  padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
+  padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
+  padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
+  padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
+  padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
+  SHA1_Update(ctx, &pad0x80, 1);
+  while (ctx->lenW != 56)
+    SHA1_Update(ctx, &pad0x00, 1);
+  SHA1_Update(ctx, padlen, 8);
+
+  /* Output hash
+   */
+  for (i = 0; i < 20; i++) {
+    hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
+    ctx->H[i / 4] <<= 8;
+  }
+
+  /*
+   *  Re-initialize the context (also zeroizes contents)
+   */
+  SHA1_Init(ctx);
+}
+
+
+#define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n))))
+
+static void shaHashBlock(SHA_CTX *ctx) {
+  int t;
+  unsigned int A,B,C,D,E,TEMP;
+
+  for (t = 16; t <= 79; t++)
+    ctx->W[t] =
+      SHA_ROT(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
+
+  A = ctx->H[0];
+  B = ctx->H[1];
+  C = ctx->H[2];
+  D = ctx->H[3];
+  E = ctx->H[4];
+
+  for (t = 0; t <= 19; t++) {
+    TEMP = SHA_ROT(A,5) + (((C^D)&B)^D)     + E + ctx->W[t] + 0x5a827999;
+    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
+  }
+  for (t = 20; t <= 39; t++) {
+    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0x6ed9eba1;
+    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
+  }
+  for (t = 40; t <= 59; t++) {
+    TEMP = SHA_ROT(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdc;
+    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
+  }
+  for (t = 60; t <= 79; t++) {
+    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0xca62c1d6;
+    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
+  }
+
+  ctx->H[0] += A;
+  ctx->H[1] += B;
+  ctx->H[2] += C;
+  ctx->H[3] += D;
+  ctx->H[4] += E;
+}
+
diff -ruN git-0.04-orig/sha1.h git-0.04/sha1.h
--- git-0.04-orig/sha1.h	Thu Jan  1 01:00:00 1970
+++ git-0.04/sha1.h	Mon Apr 18 05:40:25 2005
@@ -0,0 +1,45 @@
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is SHA 180-1 Header File
+ * 
+ * The Initial Developer of the Original Code is Paul Kocher of
+ * Cryptography Research.  Portions created by Paul Kocher are 
+ * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ *
+ *     Paul Kocher
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+typedef struct {
+  unsigned int H[5];
+  unsigned int W[80];
+  int lenW;
+  unsigned int sizeHi,sizeLo;
+} SHA_CTX;
+
+void SHA1_Init(SHA_CTX *ctx);
+void SHA1_Update(SHA_CTX *ctx, void *dataIn, int len);
+void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx);


Ciao, ET.

^ permalink raw reply	[relevance 19%]

* [PATCH 4/8] init-db.c: add INDEX_FILE_DIRECTORY support
@ 2005-04-19  9:09 24% Zach Welch
  0 siblings, 0 replies; 200+ results
From: Zach Welch @ 2005-04-19  9:09 UTC (permalink / raw)
  To: git

This patch give init-db the ability for the index directory to be 
overridden by the INDEX_FILE_DIRECTORY environment variable.

This patch applies on top of:
        [PATCH 0/8] init-db.c cleanup, add INDEX_FILE_DIRECTORY support
        [PATCH 1/8] init-db.c: [RESEND] remove redundant getenv call
        [PATCH 2/8] init-db.c: [RESEND] make init-db work with common objects
        [PATCH 3/8] init-db.c: refactor directory creation
 cache.h   |    3 +++
 init-db.c |    5 +----
 2 files changed, 4 insertions(+), 4 deletions(-)
Signed-Off-By: Zach Welch <zw@superlucidity.net>


--- a/cache.h	2005-04-18 21:13:36.000000000 -0700
+++ b/cache.h	2005-04-18 21:13:44.000000000 -0700
@@ -81,6 +81,9 @@
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc;
 
+#define INDEX_ENVIRONMENT "INDEX_FILE_DIRECTORY"
+#define DEFAULT_INDEX_ENVIRONMENT ".git"
+
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
 
--- a/init-db.c	2005-04-18 21:21:02.000000000 -0700
+++ b/init-db.c	2005-04-18 21:15:14.000000000 -0700
@@ -42,10 +42,7 @@
 	char *sha1_dir, *path;
 	int len, i;
 
-	if (mkdir(".git", 0755) < 0) {
-		perror("unable to create .git directory");
-		exit(1);
-	}
+	(void) init_dir(INDEX_ENVIRONMENT, DEFAULT_INDEX_ENVIRONMENT, "index", NULL);
 	sha1_dir = init_dir(DB_ENVIRONMENT, DEFAULT_DB_ENVIRONMENT, "storage", &len);
 	
 	path = malloc(len + 40);

^ permalink raw reply	[relevance 24%]

* [PATCH 1/3] add GIT_CACHE_DIRECTORY support
@ 2005-04-20  4:32 18% Zach Welch
  0 siblings, 0 replies; 200+ results
From: Zach Welch @ 2005-04-20  4:32 UTC (permalink / raw)
  To: git; +Cc: torvalds

 cache.h        |    3 +++
 init-db.c      |    9 +++++++--
 read-cache.c   |   15 +++++++++++++--
 read-tree.c    |   35 ++++++++++++++++++++++++++---------
 update-cache.c |   33 ++++++++++++++++++++++++---------
 5 files changed, 73 insertions(+), 22 deletions(-)

Signed-Off-By: Zach Welch <zw@superlucidity.net>

This patch introduces the GIT_CACHE_DIRECTORY to the C plumbing.
Without this patch, the index file and its lock are always placed
in './.git'.  Scripts wishing to run these commands from a different 
working directory can use this support to override the cache directory.

This require my latest init-db cleanups be applied first, otherwise
you will get a rejection in init-db.c.

cache.h: 5948db759b3f6fb5ade3b027f202330f71a8cb6a
--- a/cache.h
+++ b/cache.h
@@ -81,6 +81,9 @@ const char *sha1_file_directory;
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc;
 
+#define GIT_CACHE_ENVIRONMENT "GIT_CACHE_DIRECTORY"
+#define DEFAULT_GIT_CACHE_ENVIRONMENT ".git"
+
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
 
init-db.c: 14beb35657de229a61673198bfc4e009daafca15
--- a/init-db.c
+++ b/init-db.c
@@ -23,10 +23,15 @@ void safe_create_dir(char *dir)
  */
 int main(int argc, char **argv)
 {
-	char *sha1_dir, *path;
+	char *sha1_dir, *path, *git_dir;
 	int len, i;
 
-	safe_create_dir(".git");
+	git_dir = getenv(GIT_CACHE_ENVIRONMENT);
+	if (!git_dir) {
+		git_dir = DEFAULT_GIT_CACHE_ENVIRONMENT;
+		fprintf(stderr, "defaulting to local cache area\n");
+	}	
+	safe_create_dir(git_dir);
 
 	sha1_dir = getenv(DB_ENVIRONMENT);
 	if (!sha1_dir) {
read-cache.c: edaadf3e1c0714735ca8d80301dd644aa0f9cd2a
--- a/read-cache.c
+++ b/read-cache.c
@@ -174,22 +174,33 @@ static int verify_hdr(struct cache_heade
 
 int read_cache(void)
 {
-	int fd, i;
+	int fd, i, len;
 	struct stat st;
 	unsigned long size, offset;
 	void *map;
 	struct cache_header *hdr;
+	char *index_path, *index_file;
 
 	errno = EBUSY;
 	if (active_cache)
 		return error("more than one cachefile");
 	errno = ENOENT;
+
 	sha1_file_directory = getenv(DB_ENVIRONMENT);
 	if (!sha1_file_directory)
 		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
 	if (access(sha1_file_directory, X_OK) < 0)
 		return error("no access to SHA1 file directory");
-	fd = open(".git/index", O_RDONLY);
+
+	index_path = getenv(GIT_CACHE_ENVIRONMENT);
+	if (!index_path)
+		index_path = DEFAULT_GIT_CACHE_ENVIRONMENT;
+	len = strlen(index_path);
+	index_file = malloc(len + 7);
+	if (!index_file) error("out of memory");
+	sprintf(index_file, "%s/index", index_path);
+
+	fd = open(index_file, O_RDONLY);
 	if (fd < 0)
 		return (errno == ENOENT) ? 0 : error("open failed");
 
read-tree.c: 9bcba2d567e1c86ae967d383cc081e6947d00a13
--- a/read-tree.c
+++ b/read-tree.c
@@ -65,12 +65,12 @@ static int read_tree(unsigned char *sha1
 	return 0;
 }
 
-static int remove_lock = 0;
+static char *index_lock = NULL;
 
 static void remove_lock_file(void)
 {
-	if (remove_lock)
-		unlink(".git/index.lock");
+	if (index_lock)
+		unlink(index_lock);
 }
 
 static int path_matches(struct cache_entry *a, struct cache_entry *b)
@@ -205,14 +205,27 @@ static void merge_stat_info(struct cache
 
 int main(int argc, char **argv)
 {
-	int i, newfd, merge;
+	int i, newfd, len, merge;
 	unsigned char sha1[20];
-
-	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
+ 	char *index_file, *index_path;
+  
+ 	index_path = getenv(GIT_CACHE_ENVIRONMENT);
+ 	if (!index_path)
+ 		index_path = DEFAULT_GIT_CACHE_ENVIRONMENT;
+ 
+ 	len = strlen(index_path);
+ 	index_file = malloc(len + 7);
+ 	if (!index_file) error("out of memory");
+ 	sprintf(index_file, "%s/index", index_path);
+ 
+ 	index_lock = malloc(len + 12);
+ 	if (!index_lock) error("out of memory");
+ 	sprintf(index_lock, "%s/index.lock", index_path);
+ 
+ 	newfd = open(index_lock, O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
 		die("unable to create new cachefile");
 	atexit(remove_lock_file);
-	remove_lock = 1;
 
 	merge = 0;
 	for (i = 1; i < argc; i++) {
@@ -253,8 +266,12 @@ int main(int argc, char **argv)
 		}
 	}
 	if (write_cache(newfd, active_cache, active_nr) ||
-	    rename(".git/index.lock", ".git/index"))
+	    rename(index_lock, index_file))
 		die("unable to write new index file");
-	remove_lock = 0;
+
+	free(index_file);
+	free(index_lock);
+	index_lock = NULL;
+
 	return 0;
 }
update-cache.c: 0d16b36d7d074e9f0a2811a40e16e9823a628ec9
--- a/update-cache.c
+++ b/update-cache.c
@@ -270,25 +270,37 @@ static int add_cacheinfo(char *arg1, cha
 	return add_cache_entry(ce, allow_add);
 }
 
-static int remove_lock = 0;
+static char *index_lock = NULL;
 
 static void remove_lock_file(void)
 {
-	if (remove_lock)
-		unlink(".git/index.lock");
+	if (index_lock)
+		unlink(index_lock);
 }
 
 int main(int argc, char **argv)
 {
-	int i, newfd, entries;
+	int i, newfd, entries, len;
 	int allow_options = 1;
+	char *index_file, *index_path;
 
-	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
+	index_path = getenv(GIT_CACHE_ENVIRONMENT);
+	if (!index_path)
+		index_path = DEFAULT_GIT_CACHE_ENVIRONMENT;
+
+	len = strlen(index_path);
+	index_file = malloc(len + 7);
+	if (!index_file) error("out of memory");
+	sprintf(index_file, "%s/index", index_path);
+
+	index_lock = malloc(len + 12);
+	if (!index_lock) error("out of memory");
+	sprintf(index_lock, "%s/index.lock", index_path);
+
+	newfd = open(index_lock, O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
 		die("unable to create new cachefile");
-
 	atexit(remove_lock_file);
-	remove_lock = 1;
 
 	entries = read_cache();
 	if (entries < 0)
@@ -330,9 +342,12 @@ int main(int argc, char **argv)
 			die("Unable to add %s to database", path);
 	}
 	if (write_cache(newfd, active_cache, active_nr) ||
-	    rename(".git/index.lock", ".git/index"))
+	    rename(index_lock, index_file))
 		die("Unable to write new cachefile");
 
-	remove_lock = 0;
+	free(index_file);
+	free(index_lock);
+	index_lock = NULL;
+
 	return 0;
 }

^ permalink raw reply	[relevance 18%]

* [PATCH 2/3] rename object directory symbols
@ 2005-04-20  4:32 22% Zach Welch
  0 siblings, 0 replies; 200+ results
From: Zach Welch @ 2005-04-20  4:32 UTC (permalink / raw)
  To: git; +Cc: torvalds

This patch applies on top of:
        [PATCH 1/3] add GIT_CACHE_DIRECTORY support

 cache.h      |    4 ++--
 fsck-cache.c |    2 +-
 init-db.c    |    4 ++--
 ls-tree.c    |    4 ++--
 read-cache.c |    4 ++--
 sha1_file.c  |    2 +-
 6 files changed, 10 insertions(+), 10 deletions(-)

Signed-Off-By: Zach Welch <zw@superlucidity.net>

Rename the DB_ENVIRONMENT symbols to match the newly introduced
GIT_CACHE_ENVIROMENT symbols.

cache.h: 1fca894f485471d51c6a72c16e02df6d56d0052f
--- a/cache.h
+++ b/cache.h
@@ -84,8 +84,8 @@ unsigned int active_nr, active_alloc;
 #define GIT_CACHE_ENVIRONMENT "GIT_CACHE_DIRECTORY"
 #define DEFAULT_GIT_CACHE_ENVIRONMENT ".git"
 
-#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
-#define DEFAULT_DB_ENVIRONMENT ".git/objects"
+#define GIT_OBJECT_ENVIRONMENT "SHA1_FILE_DIRECTORY"
+#define DEFAULT_GIT_OBJECT_ENVIRONMENT ".git/objects"
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
fsck-cache.c: cf39b7e054d9685fde7004ec767cd098b97e8ce7
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -135,7 +135,7 @@ int main(int argc, char **argv)
 	int i, heads;
 	char *sha1_dir;
 
-	sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+	sha1_dir = getenv(GIT_OBJECT_ENVIRONMENT) ? : DEFAULT_GIT_OBJECT_ENVIRONMENT;
 	for (i = 0; i < 256; i++) {
 		static char dir[4096];
 		sprintf(dir, "%s/%02x", sha1_dir, i);
init-db.c: 9e693a0a914512c5574f394222cfc75496e3453a
--- a/init-db.c
+++ b/init-db.c
@@ -33,9 +33,9 @@ int main(int argc, char **argv)
 	}	
 	safe_create_dir(git_dir);
 
-	sha1_dir = getenv(DB_ENVIRONMENT);
+	sha1_dir = getenv(GIT_OBJECT_ENVIRONMENT);
 	if (!sha1_dir) {
-		sha1_dir = DEFAULT_DB_ENVIRONMENT;
+		sha1_dir = DEFAULT_GIT_OBJECT_ENVIRONMENT;
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
 	len = strlen(sha1_dir);
ls-tree.c: 936bb19a5525046a5a784d5f14c3ea7da406cc62
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -105,9 +105,9 @@ int main(int argc, char **argv)
 		usage(ls_tree_usage);
 	if (get_sha1_hex(argv[1], sha1) < 0)
 		usage(ls_tree_usage);
-	sha1_file_directory = getenv(DB_ENVIRONMENT);
+	sha1_file_directory = getenv(GIT_OBJECT_ENVIRONMENT);
 	if (!sha1_file_directory)
-		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
+		sha1_file_directory = DEFAULT_GIT_OBJECT_ENVIRONMENT;
 	if (list(sha1) < 0)
 		die("list failed");
 	return 0;
read-cache.c: 9eee23097b9406548765ec6fc77e61788317df19
--- a/read-cache.c
+++ b/read-cache.c
@@ -186,9 +186,9 @@ int read_cache(void)
 		return error("more than one cachefile");
 	errno = ENOENT;
 
-	sha1_file_directory = getenv(DB_ENVIRONMENT);
+	sha1_file_directory = getenv(GIT_OBJECT_ENVIRONMENT);
 	if (!sha1_file_directory)
-		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
+		sha1_file_directory = DEFAULT_GIT_OBJECT_ENVIRONMENT;
 	if (access(sha1_file_directory, X_OK) < 0)
 		return error("no access to SHA1 file directory");
 
sha1_file.c: c4591cd2168ae2e42c1fc9878be8befbfa1a8afa
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -61,7 +61,7 @@ char *sha1_file_name(const unsigned char
 	static char *name, *base;
 
 	if (!base) {
-		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+		char *sha1_file_directory = getenv(GIT_OBJECT_ENVIRONMENT) ? : DEFAULT_GIT_OBJECT_ENVIRONMENT;
 		int len = strlen(sha1_file_directory);
 		base = malloc(len + 60);
 		memcpy(base, sha1_file_directory, len);

^ permalink raw reply	[relevance 22%]

* [PATCH 3/3] rename SHA1_FILE_DIRECTORY
@ 2005-04-20  4:32 19% Zach Welch
  0 siblings, 0 replies; 200+ results
From: Zach Welch @ 2005-04-20  4:32 UTC (permalink / raw)
  To: git; +Cc: torvalds

This patch applies on top of:
        [PATCH 1/3] add GIT_CACHE_DIRECTORY support
        [PATCH 2/3] rename object directory symbols

 cache.h |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

Signed-Off-By: Zach Welch <zw@superlucidity.net>

Rename SHA1_FILE_DIRECTORY to GIT_OBJECT_DIRECTORY.  Scripts that
used to pass this setting will need to be updated.

cache.h: 218bec12fab3fb57ad03fafccedd4398c64c3646
--- a/cache.h
+++ b/cache.h
@@ -84,7 +84,7 @@ unsigned int active_nr, active_alloc;
 #define GIT_CACHE_ENVIRONMENT "GIT_CACHE_DIRECTORY"
 #define DEFAULT_GIT_CACHE_ENVIRONMENT ".git"
 
-#define GIT_OBJECT_ENVIRONMENT "SHA1_FILE_DIRECTORY"
+#define GIT_OBJECT_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define DEFAULT_GIT_OBJECT_ENVIRONMENT ".git/objects"
 
 #define alloc_nr(x) (((x)+16)*3/2)

^ permalink raw reply	[relevance 19%]

* [PATCH 1/4] Accept commit in some places when tree is needed.
@ 2005-04-20  6:08 19% Junio C Hamano
  2005-04-20  6:35 19% ` (fixed) " Junio C Hamano
    0 siblings, 2 replies; 200+ results
From: Junio C Hamano @ 2005-04-20  6:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Similar to the diff-cache command, we should accept commit ID
when tree ID is required but the end-user intent is unambiguous.

This patch lifts the tree-from-tree-or-commit logic from
diff-cache.c and moves it to sha1_file.c, which is a common
library source for the SHA1 storage part.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h      |    1 +
 diff-cache.c |   18 ++----------------
 sha1_file.c  |   28 ++++++++++++++++++++++++++++
 3 files changed, 31 insertions(+), 16 deletions(-)

Makefile: needs update
--- a/cache.h
+++ b/cache.h
@@ -124,5 +124,6 @@ extern void die(const char *err, ...);
 extern int error(const char *err, ...);
 
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern void *tree_from_tree_or_commit(unsigned char *sha1, char *type, unsigned long *size);
 
 #endif /* CACHE_H */
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -245,23 +245,9 @@ int main(int argc, char **argv)
 	if (argc != 2 || get_sha1_hex(argv[1], tree_sha1))
 		usage("diff-cache [-r] [-z] <tree sha1>");
 
+	tree = tree_from_tree_or_commit(tree_sha1, type, &size);
 	tree = read_sha1_file(tree_sha1, type, &size);
 	if (!tree)
-		die("bad tree object %s", argv[1]);
-
-	/* We allow people to feed us a commit object, just because we're nice */
-	if (!strcmp(type, "commit")) {
-		/* tree sha1 is always at offset 5 ("tree ") */
-		if (get_sha1_hex(tree + 5, tree_sha1))
-			die("bad commit object %s", argv[1]);
-		free(tree);
-		tree = read_sha1_file(tree_sha1, type, &size);       
-		if (!tree)
-			die("unable to read tree object %s", sha1_to_hex(tree_sha1));
-	}
-
-	if (strcmp(type, "tree"))
-		die("bad tree object %s (%s)", sha1_to_hex(tree_sha1), type);
-
+		die("cannot get tree object from %s", argv[1]);
 	return diff_cache(tree, size, active_cache, active_nr, "");
 }
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -245,3 +245,31 @@ int write_sha1_buffer(const unsigned cha
 	close(fd);
 	return 0;
 }
+
+void *tree_from_tree_or_commit(unsigned char *sha1, char *type,
+			       unsigned long *size)
+{
+	void *tree = read_sha1_file(sha1, type, size);
+	if (!tree)
+		return tree;
+
+	/* We allow people to feed us a commit object,
+	 * just because we're nice.
+	 */
+	if (!strcmp(type, "commit")) {
+		/* tree sha1 is always at offset 5 ("tree ") */
+		if (get_sha1_hex(tree + 5, sha1)) {
+			free(tree);
+			return NULL;
+		}
+		free(tree);
+		tree = read_sha1_file(sha1, type, size);
+		if (!tree)
+			return NULL;
+	}
+	if (strcmp(type , "tree")) {
+		free(tree);
+		return NULL;
+	}
+	return tree;
+}


^ permalink raw reply	[relevance 19%]

* (fixed) [PATCH 1/4] Accept commit in some places when tree is needed.
  2005-04-20  6:08 19% [PATCH 1/4] Accept commit in some places when tree is needed Junio C Hamano
@ 2005-04-20  6:35 19% ` Junio C Hamano
    1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-04-20  6:35 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

<cover-paragraph>
_BLUSH_  

The 1/4 in the series was a buggy one I sent by mistake.  Please
replace it with this fixed one.  The other three are OK.

BTW, do you have a preferred patch-mail convention to mark the
cover paragraph like this to be excluded from the commit log,
like the three-dash one you mentioned to exclude the tail of
the message?
</cover-paragraph>

Similar to diff-cache which was introduced recently, when the
intent is obvious we should accept commit ID when tree ID is
required.  This patch lifts the tree-from-tree-or-commit logic
from diff-cache.c and moves it to sha1_file.c, which is a common
library source for the SHA1 storage part.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h      |    1 +
 diff-cache.c |   19 ++-----------------
 sha1_file.c  |   29 +++++++++++++++++++++++++++++
 3 files changed, 32 insertions(+), 17 deletions(-)

--- a/cache.h
+++ b/cache.h
@@ -124,5 +124,6 @@ extern void die(const char *err, ...);
 extern int error(const char *err, ...);
 
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern void *tree_from_tree_or_commit(const unsigned char *sha1, char *type, unsigned long *size);
 
 #endif /* CACHE_H */
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -245,23 +245,8 @@ int main(int argc, char **argv)
 	if (argc != 2 || get_sha1_hex(argv[1], tree_sha1))
 		usage("diff-cache [-r] [-z] <tree sha1>");
 
-	tree = read_sha1_file(tree_sha1, type, &size);
+	tree = tree_from_tree_or_commit(tree_sha1, type, &size);
 	if (!tree)
-		die("bad tree object %s", argv[1]);
-
-	/* We allow people to feed us a commit object, just because we're nice */
-	if (!strcmp(type, "commit")) {
-		/* tree sha1 is always at offset 5 ("tree ") */
-		if (get_sha1_hex(tree + 5, tree_sha1))
-			die("bad commit object %s", argv[1]);
-		free(tree);
-		tree = read_sha1_file(tree_sha1, type, &size);       
-		if (!tree)
-			die("unable to read tree object %s", sha1_to_hex(tree_sha1));
-	}
-
-	if (strcmp(type, "tree"))
-		die("bad tree object %s (%s)", sha1_to_hex(tree_sha1), type);
-
+		die("cannot get tree object from %s", argv[1]);
 	return diff_cache(tree, size, active_cache, active_nr, "");
 }
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -245,3 +245,32 @@ int write_sha1_buffer(const unsigned cha
 	close(fd);
 	return 0;
 }
+
+void *tree_from_tree_or_commit(const unsigned char *sha1, char *type,
+			       unsigned long *size)
+{
+	void *tree = read_sha1_file(sha1, type, size);
+	if (!tree)
+		return tree;
+
+	/* We allow people to feed us a commit object,
+	 * just because we're nice.
+	 */
+	if (!strcmp(type, "commit")) {
+		/* tree sha1 is always at offset 5 ("tree ") */
+		char tree_sha1[20];
+		if (get_sha1_hex(tree + 5, tree_sha1)) {
+			free(tree);
+			return NULL;
+		}
+		free(tree);
+		tree = read_sha1_file(tree_sha1, type, size);
+		if (!tree)
+			return NULL;
+	}
+	if (strcmp(type , "tree")) {
+		free(tree);
+		return NULL;
+	}
+	return tree;
+}


^ permalink raw reply	[relevance 19%]

* Re: [PATCH] write-tree performance problems
  @ 2005-04-20 15:22 20%     ` Chris Mason
  0 siblings, 0 replies; 200+ results
From: Chris Mason @ 2005-04-20 15:22 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 1279 bytes --]

On Wednesday 20 April 2005 02:43, Linus Torvalds wrote:
> On Tue, 19 Apr 2005, Chris Mason wrote:
> > I'll finish off the patch once you ok the basics below.  My current code
> > works like this:
>
> Chris, before you do anything further, let me re-consider.
>
> Assuming that the real cost of write-tree is the compression (and I think
> it is), I really suspect that this ends up being the death-knell to my
> "use the sha1 of the _compressed_ object" approach. 

Thanks for looking at this.  Your new tree is faster, it gets the commit 100 
patches time down from 1m5s to 50s.  I've attached my patch from last night, 
which is mostly a rough guess of the changes we would need, I haven't 
validated or cleaned things up.

With the basic changes I described before, the  100 patch time only goes down 
to 40s.  Certainly not fast enough to justify the changes.  In this case, the 
bulk of the extra time comes from write-tree writing the index file, so I 
split write-tree.c up into libwrite-tree.c, and created update-cache 
--write-tree.

This gets our time back down to 21s.

The attached patch is not against your latest revs.  After updating I would 
need to sprinkle a few S_ISDIR checks into diff-cache.c and checkout-cache.c, 
but the changes should be small.

-chris

[-- Attachment #2: fast-dirs-3.diff --]
[-- Type: text/x-diff, Size: 15962 bytes --]

Index: Makefile
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/Makefile  (mode:100644 sha1:6a04941a337ec50da06cf4cf52aa58f3b1435776)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/Makefile  (mode:100644 sha1:2ba6d49196e8a2335cfcd77ec0dbe9cda3e402dd)
@@ -29,7 +29,7 @@
 
 VERSION= VERSION
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o libwrite-tree.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h
 
Index: cache.h
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/cache.h  (mode:100644 sha1:c182ea0c5c1def37d899f9a05f8884ebe17c9d92)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/cache.h  (mode:100644 sha1:0882b713222b71e67c9dab5d58ab6f15c3c49ed6)
@@ -74,7 +74,7 @@
 #define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
 
 #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
-#define create_ce_mode(mode) htonl(S_IFREG | ce_permissions(mode))
+#define create_ce_mode(mode) htonl((mode & (S_IFREG|S_IFDIR)) | ce_permissions(mode))
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
Index: libwrite-tree.c
===================================================================
--- /dev/null  (tree:dbeacafeb442bcfd39dfdc90c360d47d4215c185)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/libwrite-tree.c  (mode:100644 sha1:52202930d02b3721f5a388ae1178c5a4d99ec1b4)
@@ -0,0 +1,174 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+
+struct new_ce {
+	struct new_ce *next;
+	struct cache_entry ce;
+};
+
+static struct new_ce *add_list = NULL;
+
+static int check_valid_sha1(unsigned char *sha1)
+{
+	char *filename = sha1_file_name(sha1);
+	int ret;
+
+	/* If we were anal, we'd check that the sha1 of the contents actually matches */
+	ret = access(filename, R_OK);
+	if (ret)
+		perror(filename);
+	return ret;
+}
+
+static int prepend_integer(char *buffer, unsigned val, int i)
+{
+	buffer[--i] = '\0';
+	do {
+		buffer[--i] = '0' + (val % 10);
+		val /= 10;
+	} while (val);
+	return i;
+}
+
+#define ORIG_OFFSET (40)	/* Enough space to add the header of "tree <size>\0" */
+
+static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+{
+	unsigned char subdir_sha1[20];
+	unsigned long size, offset;
+	char *buffer;
+	int i, nr;
+
+	/* Guess at some random initial size */
+	size = 8192;
+	buffer = malloc(size);
+	offset = ORIG_OFFSET;
+
+	nr = 0;
+	do {
+		struct cache_entry *ce = cachep[nr];
+		const char *pathname = ce->name, *filename, *dirname;
+		int pathlen = ce_namelen(ce), entrylen;
+		unsigned char *sha1;
+		unsigned int mode;
+
+		/* Did we hit the end of the directory? Return how many we wrote */
+		if (baselen >= pathlen || memcmp(base, pathname, baselen))
+			break;
+
+		sha1 = ce->sha1;
+		mode = ntohl(ce->ce_mode);
+
+		/* Do we have _further_ subdirectories? */
+		filename = pathname + baselen;
+		dirname = strchr(filename, '/');
+		if (dirname) {
+			int subdir_written;
+			int len = dirname - pathname;
+			unsigned int size = cache_entry_size(len);
+			struct new_ce *new_ce = malloc(size + sizeof(struct new_ce *));
+			struct cache_entry *c = &new_ce->ce;
+			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			nr += subdir_written - 1;
+
+			/* Now we need to write out the directory entry into this tree.. */
+			mode = S_IFDIR;
+			pathlen = dirname - pathname;
+
+			sha1 = subdir_sha1;
+
+			memset(c, 0, size);
+
+			/* create a new cache entry for what we just calculated.
+			 * place the new entry on a list for adding later so we
+			 * don't change the size of the cache right now.
+			 */
+			c->ce_mode = create_ce_mode(mode);
+			c->ce_flags = create_ce_flags(len, 0);
+			memcpy(c->name, pathname, len);
+			c->name[len] = '\0';
+			memcpy(c->sha1, sha1, 20);
+			new_ce->next = add_list;
+			add_list = new_ce;
+		} else if (mode & S_IFDIR) {
+			/* eat all the entries below this directory */
+			while(++nr < maxentries) {
+				struct cache_entry *c = cachep[nr];
+				
+				if (strlen(c->name) < pathlen)
+					break;
+				if (memcmp(c->name, pathname, pathlen) ||
+				    c->name[pathlen] != '/')
+					break;
+			}
+			/* our loop went too far by 1 */
+			nr--;
+			mode = S_IFDIR;
+		}
+
+		if (check_valid_sha1(sha1) < 0)
+			exit(1);
+
+		entrylen = pathlen - baselen;
+		if (offset + entrylen + 100 > size) {
+			size = alloc_nr(offset + entrylen + 100);
+			buffer = realloc(buffer, size);
+		}
+		offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
+		buffer[offset++] = 0;
+		memcpy(buffer + offset, sha1, 20);
+		offset += 20;
+		nr++;
+	} while (nr < maxentries);
+
+	i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
+	i -= 5;
+	memcpy(buffer+i, "tree ", 5);
+
+	write_sha1_file(buffer + i, offset - i, returnsha1);
+	free(buffer);
+	return nr;
+}
+
+void write_full_tree(int entries) {
+	unsigned char sha1[20];
+	int i, unmerged;
+
+	if (entries <= 0)
+		die("write-tree: no cache contents to write");
+
+	/* Verify that the tree is merged */
+	unmerged = 0;
+	for (i = 0; i < entries; i++) {
+		struct cache_entry *ce = active_cache[i];
+		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
+			if (++unmerged > 10) {
+				fprintf(stderr, "...\n");
+				break;
+			}
+			fprintf(stderr, "%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1));
+		}
+	}
+	if (unmerged)
+		die("write-tree: not able to write tree");
+
+	/* Ok, write it out */
+	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+		die("write-tree: internal error");
+	printf("%s\n", sha1_to_hex(sha1));
+	if (add_list) {
+		struct new_ce *nc = add_list;
+		while(nc) {
+			add_cache_entry(&nc->ce, 1);
+			nc = nc->next;
+		}
+	}
+}
+
+int write_tree_updated_cache(void) {
+	return add_list != NULL;
+}
Index: merge-cache.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/merge-cache.c  (mode:100644 sha1:96c86c26d06837bf604a70caf9dd2133884a63bc)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/merge-cache.c  (mode:100644 sha1:1b45bfc8cf5b4c610a4b149f3a4295081bc0e00f)
@@ -63,8 +63,16 @@
 	 * If it already exists in the cache as stage0, it's
 	 * already merged and there is nothing to do.
 	 */
-	if (pos < 0)
-		merge_entry(-pos-1, path);
+	if (pos < 0) {
+		pos = -pos-1;
+		while(pos > 0) {
+			int mode = htonl(active_cache[pos]->ce_mode);
+			if (S_ISREG(mode))
+				break;
+			pos--;
+		}
+		merge_entry(pos, path);
+	}
 }
 
 static void merge_all(void)
@@ -74,7 +82,8 @@
 		struct cache_entry *ce = active_cache[i];
 		if (!ce_stage(ce))
 			continue;
-		i += merge_entry(i, ce->name)-1;
+		if (S_ISREG(htonl(ce->ce_mode)))
+			i += merge_entry(i, ce->name)-1;
 	}
 }
 
Index: read-cache.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/read-cache.c  (mode:100644 sha1:17d4d2284e79d3f1070b51200d797115f2d09d6a)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/read-cache.c  (mode:100644 sha1:d2fc8e35f5ef602f7baa1a4c83c74dbf373fc3e0)
@@ -96,11 +96,30 @@
 	return 1;
 }
 
+static void invalidate_trees(char *path) {
+	char *p;
+	int len = strlen(path);
+	int pos;
+	extern void *memrchr(__const void *, int, size_t);
+	while(1) {
+		p = memrchr(path, '/', len);
+		if (!p || p == path)
+			return;
+		len = p-path;
+		pos = cache_name_pos(path, len);
+		if (pos < 0)
+			return;
+		remove_entry_at(pos);
+	}	
+}
+
 int remove_file_from_cache(char *path)
 {
 	int pos = cache_name_pos(path, strlen(path));
-	if (pos >= 0)
+	if (pos >= 0) {
 		remove_entry_at(pos);
+		invalidate_trees(path);
+	}
 	return 0;
 }
 
@@ -113,12 +132,16 @@
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 {
 	int pos;
+	int invalidate = S_ISREG(htonl(ce->ce_mode));
 
 	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
 		active_cache[pos] = ce;
+		if (invalidate) {
+			invalidate_trees(ce->name);
+		}
 		return 0;
 	}
 	pos = -pos-1;
@@ -149,6 +172,9 @@
 	if (active_nr > pos)
 		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
 	active_cache[pos] = ce;
+	if (invalidate) {
+		invalidate_trees(ce->name);
+	}
 	return 0;
 }
 
Index: read-tree.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/read-tree.c  (mode:100644 sha1:a573a3155e532081a8be0dab60f1ec35ea159ddf)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/read-tree.c  (mode:100644 sha1:fa497650937a62caadd043897032cf5f9e07dea2)
@@ -63,7 +63,6 @@
 				free(buffer);
 				return -1;
 			}
-			continue;
 		}
 		if (read_one_entry(sha1, base, baselen, path, mode) < 0) {
 			free(buffer);
Index: show-diff.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/show-diff.c  (mode:100644 sha1:007dabd2978de4c58f49050d3969ca353278dbb6)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/show-diff.c  (mode:100644 sha1:a7b0a0bca00c173f591a0d8ef0dfbcbdd96ef8a9)
@@ -163,6 +163,8 @@
 		if (1 < argc &&
 		    ! matches_pathspec(ce, argv+1, argc-1))
 			continue;
+		if (S_ISDIR(htonl(ce->ce_mode)))
+			continue;
 		matched++;
 
 		if (ce_stage(ce)) {
Index: update-cache.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/update-cache.c  (mode:100644 sha1:11388582a830a6161d1c769aa8616bed6f593b8a)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/update-cache.c  (mode:100644 sha1:cab4e8e1fa7aceff287cfb3464710b1dd52f3a5f)
@@ -4,6 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
+#include "write-tree.h"
 
 /*
  * Default to not allowing changes to the list of files. The
@@ -12,7 +13,7 @@
  * like "update-cache *" and suddenly having all the object
  * files be revision controlled.
  */
-static int allow_add = 0, allow_remove = 0;
+static int allow_add = 0, allow_remove = 0, write_tree = 0;
 
 static int index_fd(unsigned char *sha1, int fd, struct stat *st)
 {
@@ -182,7 +183,6 @@
 
 	if (stat(ce->name, &st) < 0)
 		return NULL;
-
 	changed = cache_match_stat(ce, &st);
 	if (!changed)
 		return ce;
@@ -191,12 +191,11 @@
 	 * If the mode has changed, there's no point in trying
 	 * to refresh the entry - it's not going to match
 	 */
-	if (changed & MODE_CHANGED)
+	if (changed & MODE_CHANGED) {
 		return NULL;
-
+	}
 	if (compare_data(ce, st.st_size))
 		return NULL;
-
 	size = ce_size(ce);
 	updated = malloc(size);
 	memcpy(updated, ce, size);
@@ -222,7 +221,8 @@
 
 		new = refresh_entry(ce);
 		if (!new) {
-			printf("%s: needs update\n", ce->name);
+			if (S_ISREG(ntohl(ce->ce_mode)))
+				printf("%s: needs update\n", ce->name);
 			continue;
 		}
 		/* You can NOT just free active_cache[i] here, since it
@@ -336,6 +336,10 @@
 				i += 3;
 				continue;
 			}
+			if (!strcmp(path, "--write-tree")) {
+				write_tree = 1;
+				continue;
+			}
 			die("unknown option %s", path);
 		}
 		if (!verify_path(path)) {
@@ -345,6 +349,9 @@
 		if (add_file_to_cache(path))
 			die("Unable to add %s to database", path);
 	}
+	if (write_tree) {
+		write_full_tree(active_nr);
+	}
 	if (write_cache(newfd, active_cache, active_nr) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("Unable to write new cachefile");
Index: write-tree.c
===================================================================
--- dbeacafeb442bcfd39dfdc90c360d47d4215c185/write-tree.c  (mode:100644 sha1:fb046aa6ce6b9fce6a523a1e36ff43adab9bdd93)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/write-tree.c  (mode:100644 sha1:c3d62242f0d5fff0c245cd46ac8a5b72d4aef4cd)
@@ -4,127 +4,28 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
-
-static int check_valid_sha1(unsigned char *sha1)
-{
-	char *filename = sha1_file_name(sha1);
-	int ret;
-
-	/* If we were anal, we'd check that the sha1 of the contents actually matches */
-	ret = access(filename, R_OK);
-	if (ret)
-		perror(filename);
-	return ret;
-}
-
-static int prepend_integer(char *buffer, unsigned val, int i)
-{
-	buffer[--i] = '\0';
-	do {
-		buffer[--i] = '0' + (val % 10);
-		val /= 10;
-	} while (val);
-	return i;
-}
-
-#define ORIG_OFFSET (40)	/* Enough space to add the header of "tree <size>\0" */
-
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
-{
-	unsigned char subdir_sha1[20];
-	unsigned long size, offset;
-	char *buffer;
-	int i, nr;
-
-	/* Guess at some random initial size */
-	size = 8192;
-	buffer = malloc(size);
-	offset = ORIG_OFFSET;
-
-	nr = 0;
-	do {
-		struct cache_entry *ce = cachep[nr];
-		const char *pathname = ce->name, *filename, *dirname;
-		int pathlen = ce_namelen(ce), entrylen;
-		unsigned char *sha1;
-		unsigned int mode;
-
-		/* Did we hit the end of the directory? Return how many we wrote */
-		if (baselen >= pathlen || memcmp(base, pathname, baselen))
-			break;
-
-		sha1 = ce->sha1;
-		mode = ntohl(ce->ce_mode);
-
-		/* Do we have _further_ subdirectories? */
-		filename = pathname + baselen;
-		dirname = strchr(filename, '/');
-		if (dirname) {
-			int subdir_written;
-
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
-			nr += subdir_written;
-
-			/* Now we need to write out the directory entry into this tree.. */
-			mode = S_IFDIR;
-			pathlen = dirname - pathname;
-
-			/* ..but the directory entry doesn't count towards the total count */
-			nr--;
-			sha1 = subdir_sha1;
-		}
-
-		if (check_valid_sha1(sha1) < 0)
-			exit(1);
-
-		entrylen = pathlen - baselen;
-		if (offset + entrylen + 100 > size) {
-			size = alloc_nr(offset + entrylen + 100);
-			buffer = realloc(buffer, size);
-		}
-		offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
-		buffer[offset++] = 0;
-		memcpy(buffer + offset, sha1, 20);
-		offset += 20;
-		nr++;
-	} while (nr < maxentries);
-
-	i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
-	i -= 5;
-	memcpy(buffer+i, "tree ", 5);
-
-	write_sha1_file(buffer + i, offset - i, returnsha1);
-	free(buffer);
-	return nr;
-}
+#include "write-tree.h"
 
 int main(int argc, char **argv)
 {
-	int i, unmerged;
 	int entries = read_cache();
-	unsigned char sha1[20];
+	int newfd;
+	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
+	if (newfd < 0)
+		die("unable to create new cachefile");
+
 
 	if (entries <= 0)
 		die("write-tree: no cache contents to write");
 
-	/* Verify that the tree is merged */
-	unmerged = 0;
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = active_cache[i];
-		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
-			if (++unmerged > 10) {
-				fprintf(stderr, "...\n");
-				break;
-			}
-			fprintf(stderr, "%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1));
-		}
+	write_full_tree(entries);
+	if (write_tree_updated_cache()) {
+		if (write_cache(newfd, active_cache, active_nr) ||
+		    rename(".git/index.lock", ".git/index"))
+			die("Unable to write new cachefile");
+	} else {
+		close(newfd);
+		unlink(".git/index.lock");
 	}
-	if (unmerged)
-		die("write-tree: not able to write tree");
-
-	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
-		die("write-tree: internal error");
-	printf("%s\n", sha1_to_hex(sha1));
 	return 0;
 }
Index: write-tree.h
===================================================================
--- /dev/null  (tree:dbeacafeb442bcfd39dfdc90c360d47d4215c185)
+++ 27e71cd40ff1dccfbbd996427833fd7bac714dde/write-tree.h  (mode:100644 sha1:0ad5fe36126577e56544e08e0f4dfa766350e841)
@@ -0,0 +1,3 @@
+
+void write_full_tree(int);
+int write_tree_updated_cache(void);

^ permalink raw reply	[relevance 20%]

* (rework) [PATCH 1/5] Accept commit in some places when tree is needed.
  @ 2005-04-21  0:19 12%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-04-21  0:19 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus,

    sorry for bringing up an issue that is already 8 hours old.

LT> I don't think that's a good interface. It changes the sha1 passed into it: 
LT> that may actually be nice, since you may want to know what it changed to, 
LT> but I think you'd want to have that as an (optional) separate 
LT> "sha1_result" parameter. 

Point taken about "_changing_ _is_ _bad_" part.  It was a mistake.

LT> Also, the "type" or "size" things make no sense to have as a parameter 
LT> at all.

Well, the semantics is "I want to read the raw data of a tree
and I do not know nor care if this sha1 I got from my user is
for a commit or a tree."  So type does not matter (if it returns
a non NULL we know it is a tree), but the size matters.

And that semantics is not so hacky thing specific to diff-cache.
Rather, it applies in general if you structure the way those
recursive walkers do things.  The recursive walkers in ls-tree,
diff-cache, and diff-tree all expect the caller to supply the
buffer read by sha1_read_buffer, and when it calls itself it
does the same (read-tree's recursing convention is an oddball
that needs to be addressed, though).

When the recursion is structured this way, the only thing you
need to do to allow commit ID from the user when tree ID is
needed, without breaking the error checking done by the part
that recurses down (i.e. we must error on a commit object ID
when we are expecting a tree object ID stored in objects we read
from the tree downwards), is to change the top-level caller to
use "I want tree with this tree/commit ID" instead of "I want a
buffer with this ID and I'll make sure it is a tree myself".
Instead, you make the recursor "Give me a buffer and its type,
I'll barf if it is does not say a tree."  When the recursor
calls itself, it reads with read_sha1_file and feeds the result
to itself and have the called do the checking.

The commit_to_tree() thing you introduced in diff-tree.c is
simple to use.  IMHO it is however conceptually a wrong thing to
use in these contexts.  When the user supplies a tree ID, you
first read that object only to see if it is not a commit and
throw it away, then immediately read it again for your real
processing.  In these particular cases of four tree- related
files, "I want tree with this tree/commit ID" semantics is a
_far_ _better_ match for the problem.

Having said that, here is a reworked version.  This first one 
introduces read_tree_with_tree_or_commit_sha1() function.

<end-of-cover-letter>

This patch implements read_tree_with_tree_or_commit_sha1(),
which can be used when you are interested in reading an unpacked
raw tree data but you do not know nor care if the SHA1 you
obtained your user is a tree ID or a commit ID.  Before this
function's introduction, you would have called read_sha1_file(),
examined its type, parsed it to call read_sha1_file() again if
it is a commit, and verified that the resulting object is a
tree.  Instead, this function does that for you.  It returns
NULL if the given SHA1 is not either a tree or a commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h     |    4 ++++
 sha1_file.c |   40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

cache.h: eab355da5d2f6595053f28f0cca61181ac314ee9
--- a/cache.h
+++ b/cache.h
@@ -124,4 +124,8 @@ extern int error(const char *err, ...);
 
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 
+extern void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
+						unsigned long *size,
+						unsigned char *tree_sha1_ret);
+
 #endif /* CACHE_H */


sha1_file.c: eee3598bb75e2199045b823f007e7933c0fb9cfe
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -166,6 +166,46 @@ void * read_sha1_file(const unsigned cha
 	return NULL;
 }
 
+void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
+					 unsigned long *size,
+					 unsigned char *tree_sha1_return)
+{
+	char type[20];
+	void *buffer;
+	unsigned long isize;
+	int was_commit = 0;
+	char tree_sha1[20];
+
+	buffer = read_sha1_file(sha1, type, &isize);
+
+	/* 
+	 * We might have read a commit instead of a tree, in which case
+	 * we parse out the tree_sha1 and attempt to read from there.
+	 * (buffer + 5) is because the tree sha1 is always at offset 5
+	 * in a commit record ("tree ").
+	 */
+	if (buffer &&
+	    !strcmp(type, "commit") &&
+	    !get_sha1_hex(buffer + 5, tree_sha1)) {
+		free(buffer);
+		buffer = read_sha1_file(tree_sha1, type, &isize);
+		was_commit = 1;
+	}
+
+	/*
+	 * Now do we have something and if so is it a tree?
+	 */
+	if (!buffer || strcmp(type, "tree")) {
+		free(buffer);
+		return;
+	}
+
+	*size = isize;
+	if (tree_sha1_return)
+		memcpy(tree_sha1_return, was_commit ? tree_sha1 : sha1, 20);
+	return buffer;
+}
+
 int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
 {
 	int size;


^ permalink raw reply	[relevance 12%]

* [PATCH] experimental - Performance of various compressors
  @ 2005-04-21  5:22 22%   ` Mike Taht
  0 siblings, 0 replies; 200+ results
From: Mike Taht @ 2005-04-21  5:22 UTC (permalink / raw)
  To: Mike Taht; +Cc: git




Don't apply this patch and change GIT_COMPRESSION unless you know what 
you are doing and why you are doing it. You will break an older version 
of git. You may break a newer version of git. You have been warned.

I also note that there's a bzlib out there.

cache.h: 828d660ab82bb35a1ca632a2ba4620dc483889bd
--- a/cache.h
+++ b/cache.h
@@ -16,6 +16,8 @@
  #include <openssl/sha.h>
  #include <zlib.h>

+#define GIT_COMPRESSION Z_BEST_COMPRESSION
+
  /*
   * Basic data structures for the directory cache
   *
sha1_file.c: 754e8b4e9ea8104df48152f875d6b874304e2a62
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -199,7 +199,7 @@ int write_sha1_file(char *buf, unsigned

         /* Set it up */
         memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, Z_BEST_COMPRESSION);
+       deflateInit(&stream, GIT_COMPRESSION);
         size = deflateBound(&stream, len);
         compressed = malloc(size);

update-cache.c: a09883541c745c76413c62109a80f40df4b7a7fb
--- a/update-cache.c
+++ b/update-cache.c
@@ -40,7 +40,7 @@ static int index_fd(unsigned char *sha1,
         SHA1_Final(sha1, &c);

         memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, Z_BEST_COMPRESSION);
+       deflateInit(&stream, GIT_COMPRESSION);

         /*
          * ASCII size + nul byte



Mike Taht wrote:
> Just to clarify this was a git add of the linux-2.6.11.7 sources (sorry, 
> untimed) , and timing the git commit.
> 
> Mo betta data latah.
> 
> Mike Taht wrote:
> 
>> I started rolling a tool to measure various aspects of git 
>> performance. I will start looking at merge next, and at workloads 
>> different from the kernel (gcc4 anyone?) ...
>>
>> The only data points worth sharing a this point are:
>>
>> That doing the compression at a level of 3, rather than the max of 9, 
>> cuts the cpu time required for a big git commit by over half, and that 
>> that actually translates into a win on the I/O to disk. (these tests 
>> were performed on a dual opteron 842)
>>
>> The benefits of compression aren't very much for git right now.
>>
>> And: A big git commit is I/O bound. But we knew that. Maybe it's 
>> possible to make it less I/O bound.
>>
>> Git branch: 7a4c67965de68ae7bc7aa1fde33f8eb9d8114697
>> Tree: 2.6.11.7 source tree
>> Branch: N/a
>> Merge File: N/a
>> HW: dual opteron 242
>> Mem: 1GB
>> Disk: seagate barracuda
>> Filesystem: Reiser3
>> Git add: N/a
>> Cache: Hot
>> Git Commit: 44.97user 5.94system 1:45.24elapsed 48%CPU
>> Git Merge:
>> Options:
>> Feature: Test of compression=9 (std git)
>>
>> du -s .git/objects  110106  # du is probably not the right thing
>> du -s --apparent-size .git/objects 58979
>>
>> Git branch: 9e272677621c91784cf2533123a41745178f0701
>> Tree: 2.6.11.7 source tree
>> Branch: N/a
>> Merge File: N/a
>> HW: dual opteron 242
>> Mem: 1GB
>> Disk: seagate barracuda
>> Disk mode: udma5
>> Filesystem: Reiser3
>> Git add: N/a
>> Cache: Hot
>> Git Commit: 16.79user 6.15system 1:21.92elapsed 28%CPU
>> Git Merge:
>> Options:
>> Feature: Test of compression=3 (std git)
>>
>> du -s .git/objects  115218
>> du -s --apparent-size .git/objects 64274
>>
>> There's some variety in the best/worst case timings for I/O for the 
>> compressor=3 case...
>>
>> 16.79user 6.15system 1:21.92elapsed 28%CPU
>> 16.68user 5.71system 1:13.19elapsed 30%CPU
> 
> 
> 


-- 

Mike Taht


   ""His mind is like a steel trap -- full of mice."
	-- Foghorn Leghorn"

^ permalink raw reply	[relevance 22%]

* [PATCH] multi item packed files
@ 2005-04-21 15:13 22% Chris Mason
    0 siblings, 1 reply; 200+ results
From: Chris Mason @ 2005-04-21 15:13 UTC (permalink / raw)
  To: git, torvalds

[-- Attachment #1: Type: text/plain, Size: 1797 bytes --]

Hello,

There have been a few threads on making git more space efficient, and 
eventually someone mentions tiny files and space fragmentation.  Now that git 
object names are decoupled from their compression, it's easier to consider a 
a variety of compression algorithms.  I whipped up a really silly "pack files 
together" compression.

This would maintain the write once semantics but allow a simple mechanism 
where objects are combined together.  Choosing which objects to combine is 
easy, things put together into update-cache go together.  This gives us more 
space efficiency and no seeks when reading that packed file off disk.

A natural extension to this is to make update-cache --commit-tree, which 
includes the files produced by write-tree and commit-tree into the same 
packed file.  (I haven't coded this).

The layout works like this:

1) a new object type "packed" is added.
2) new objects are buffered into a packed object, until it gets to around 32k 
in size.  This is complete arbitrary but felt about right.
3) The packed object is writting to git storage and then hard links are made 
to the packed object from the sha1 filename of each object inside.
4) read_sha1_file is changed to recognize the packed object and search inside.

I did a simple test on the 2.6.11 tree with my 100 patches applied.  Without 
packing, .git is 99MB.  With packing it only needs 62MB:

read speeds don't suffer with this, time to read-tree ; checkout-cache -a -f 
from a cold cache were the same.  I could get the times lower with the patch 
by caching the uncompressed data, since in theory I should be faster here.

Using this on data you care about would be a really bad idea right now.  I'm 
only posting the patch to get the basic idea across for benchmarking and 
discussion.

-chris

[-- Attachment #2: comp-tree.diff --]
[-- Type: text/x-diff, Size: 9944 bytes --]

diff -ur linus.back/cache.h linus/cache.h
--- linus.back/cache.h	2005-04-21 11:05:27.971607944 -0400
+++ linus/cache.h	2005-04-21 09:35:47.173613576 -0400
@@ -109,7 +109,7 @@
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
+extern void * unpack_sha1_file(const unsigned char *sha1, 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);
@@ -117,6 +117,10 @@
 /* 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! */
+extern int pack_sha1_buffer(void *buf, unsigned long buf_len, 
+		     unsigned char *returnsha1, char **dest, 
+		     unsigned long *dest_size);
+int write_packed_buffer(void *buf, unsigned long len);
 
 /* General helper functions */
 extern void usage(const char *err);
diff -ur linus.back/cat-file.c linus/cat-file.c
--- linus.back/cat-file.c	2005-04-21 11:05:27.971607944 -0400
+++ linus/cat-file.c	2005-04-21 10:04:29.871723656 -0400
@@ -23,7 +23,7 @@
 		type[size] = '\n';
 		size++;
 	} else if (strcmp(type, argv[1])) {
-		die("cat-file %s: bad tag", argv[2]);
+		die("cat-file %s: bad tag (%s: %s)", argv[2], type, argv[1]);
 	}
 
 	while (size > 0) {
diff -ur linus.back/fsck-cache.c linus/fsck-cache.c
--- linus.back/fsck-cache.c	2005-04-21 11:05:27.974607488 -0400
+++ linus/fsck-cache.c	2005-04-21 09:14:03.139856840 -0400
@@ -85,7 +85,7 @@
 		if (map) {
 			char type[100];
 			unsigned long size;
-			void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+			void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size);
 			if (!buffer)
 				return -1;
 			if (check_sha1_signature(sha1, buffer, size, type) < 0)
diff -ur linus.back/sha1_file.c linus/sha1_file.c
--- linus.back/sha1_file.c	2005-04-21 11:05:27.978606880 -0400
+++ linus/sha1_file.c	2005-04-21 10:41:51.280977656 -0400
@@ -116,7 +116,8 @@
 	return map;
 }
 
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+void * unpack_sha1_file(const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size)
 {
 	int ret, bytes;
 	z_stream stream;
@@ -134,12 +135,12 @@
 	ret = inflate(&stream, 0);
 	if (sscanf(buffer, "%10s %lu", type, size) != 2)
 		return NULL;
-
 	bytes = strlen(buffer) + 1;
 	buf = malloc(*size);
-	if (!buf)
+	if (!buf) {
+		perror("malloc");
 		return NULL;
-
+	}
 	memcpy(buf, buffer + bytes, stream.total_out - bytes);
 	bytes = stream.total_out - bytes;
 	if (bytes < *size && ret == Z_OK) {
@@ -149,6 +150,36 @@
 			/* nothing */;
 	}
 	inflateEnd(&stream);
+
+	/* we've found a packed object */
+	if (strcmp(type, "packed") == 0) {
+		char *p = buf;
+		if (!sha1)
+			return NULL;
+		while(p < buf + *size) {
+			unsigned long item_len;
+			unsigned char sha1_hex[50];
+			unsigned char item_sha[20];
+			sscanf(p, "%50s %lu", sha1_hex, &item_len);
+			if (get_sha1_hex(sha1_hex, item_sha))
+				die("packed file corruption");
+			if (memcmp(item_sha, sha1, 20) == 0) {
+				char *temp;
+				char *r;
+				temp = p + strlen(p) + 1;
+				if (sscanf(temp, "%10s %lu", type, size) != 2)
+					return NULL;
+				r = malloc(*size);
+				if (!r)
+					return NULL;
+				memcpy(r, temp + strlen(temp) + 1, *size);
+				free(buf);
+				return r;
+			}
+			p += strlen(p) + 1 + item_len;
+		}
+		return NULL;
+	}
 	return buf;
 }
 
@@ -159,7 +190,7 @@
 
 	map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size);
 		munmap(map, mapsize);
 		return buf;
 	}
@@ -305,3 +336,111 @@
 	close(fd);
 	return 0;
 }
+
+int pack_sha1_buffer(void *buf, unsigned long buf_len, 
+		     unsigned char *returnsha1, char **dest, 
+		     unsigned long *dest_size)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	struct stat st;
+	void *p;
+	int metadata_size;
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, buf, buf_len);
+	SHA1_Final(sha1, &c);
+
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+
+	filename = sha1_file_name(sha1);
+	if (stat(filename, &st) == 0)
+		return 0;
+
+	p = realloc(*dest, *dest_size + buf_len + 250);
+	if (!p)
+		return -1;
+	*dest = p;
+	p += *dest_size;
+	metadata_size = 1 + sprintf(p, "%s %lu", sha1_to_hex(sha1), buf_len);
+	p += metadata_size;
+	memcpy(p, buf, buf_len);
+	*dest_size += buf_len + metadata_size;
+	return 0;
+}
+
+int write_packed_buffer(void *buf, unsigned long len)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	char *p;
+	char *metadata = malloc(200);
+	unsigned char sha1_hex[50];
+	int metadata_size;
+	int fd;
+	int ret = 0;
+
+	metadata_size = 1+sprintf(metadata, "packed %lu", len);
+
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, buf, len);
+	SHA1_Final(sha1, &c);
+
+	filename = strdup(sha1_file_name(sha1));
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		if (errno != EEXIST)
+			return -1;
+		/* add collision check! */
+	} else {
+		char *compressed;
+		z_stream stream;
+		unsigned long size;
+		/* Set it up */
+		memset(&stream, 0, sizeof(stream));
+		deflateInit(&stream, Z_BEST_COMPRESSION);
+		size = deflateBound(&stream, len + metadata_size);
+		compressed = malloc(size);
+
+		/* Compress it */
+		stream.next_in = metadata;
+		stream.avail_in = metadata_size;
+		stream.next_out = compressed;
+		stream.avail_out = size;
+		while (deflate(&stream, 0) == Z_OK)
+			/* nothing */;
+		stream.next_in = buf;
+		stream.avail_in = len;
+		while (deflate(&stream, Z_FINISH) == Z_OK)
+			/* nothing */;
+		deflateEnd(&stream);
+		write(fd, compressed, stream.total_out);
+		close(fd);
+	}
+	free(metadata);
+	/* now we have the packed blob on disk, lets link to it */
+	p = buf;
+	while(p < (char *)buf + len) {
+		unsigned long item_len;
+		char *item_file;
+		sscanf(p, "%50s %lu\n", sha1_hex, &item_len);
+		/* + 1 for the null at the end of p */
+		p += strlen(p) + item_len + 1;
+
+		if (get_sha1_hex(sha1_hex, sha1))
+			die("packed file corruption");
+		
+		item_file = sha1_file_name(sha1);
+		if (link(filename, item_file) && errno != EEXIST) {
+			ret = -errno;
+			break;
+		}
+	}
+	free(filename);
+	return ret;
+}
diff -ur linus.back/update-cache.c linus/update-cache.c
--- linus.back/update-cache.c	2005-04-21 11:05:27.979606728 -0400
+++ linus/update-cache.c	2005-04-21 10:42:08.109419344 -0400
@@ -14,55 +14,33 @@
  */
 static int allow_add = 0, allow_remove = 0;
 
-static int index_fd(unsigned char *sha1, int fd, struct stat *st)
+static int index_fd(unsigned char *sha1, int fd, struct stat *st, char **packed_buffer, unsigned long *packed_len)
 {
-	z_stream stream;
 	unsigned long size = st->st_size;
-	int max_out_bytes = size + 200;
-	void *out = malloc(max_out_bytes);
 	void *metadata = malloc(200);
 	int metadata_size;
 	void *in;
-	SHA_CTX c;
+	char *copy;
+	int ret;
 
 	in = "";
 	if (size)
 		in = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (!out || (int)(long)in == -1)
+	if (!metadata || (int)(long)in == -1)
 		return -1;
 
 	metadata_size = 1+sprintf(metadata, "blob %lu", size);
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, metadata, metadata_size);
-	SHA1_Update(&c, in, size);
-	SHA1_Final(sha1, &c);
-
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
-
-	/*
-	 * ASCII size + nul byte
-	 */	
-	stream.next_in = metadata;
-	stream.avail_in = metadata_size;
-	stream.next_out = out;
-	stream.avail_out = max_out_bytes;
-	while (deflate(&stream, 0) == Z_OK)
-		/* nothing */;
-
-	/*
-	 * File content
-	 */
-	stream.next_in = in;
-	stream.avail_in = size;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/*nothing */;
-
-	deflateEnd(&stream);
-	
-	return write_sha1_buffer(sha1, out, stream.total_out);
+	copy = malloc(metadata_size + size);
+	if (!copy)
+		return -1;
+	memcpy(copy, metadata, metadata_size);
+	memcpy(copy + metadata_size, in, size);
+	ret = pack_sha1_buffer(copy, metadata_size + size,
+			       sha1, packed_buffer, packed_len);
+	munmap(in, size);
+	free(copy);
+	return ret;
 }
 
 /*
@@ -85,7 +63,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(char *path, char **packed_buffer, unsigned long *packed_len)
 {
 	int size, namelen;
 	struct cache_entry *ce;
@@ -113,9 +91,14 @@
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
 
-	if (index_fd(ce->sha1, fd, &st) < 0)
+	if (index_fd(ce->sha1, fd, &st, packed_buffer, packed_len) < 0)
 		return -1;
 
+	if (*packed_len > 32768) {
+		if (write_packed_buffer(*packed_buffer, *packed_len))
+			return -1;
+		*packed_len = 0;
+	}
 	return add_cache_entry(ce, allow_add);
 }
 
@@ -286,6 +269,8 @@
 {
 	int i, newfd, entries;
 	int allow_options = 1;
+	char *packed_buffer = NULL;
+	unsigned long packed_len = 0;
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
@@ -330,9 +315,14 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(path, &packed_buffer, &packed_len))
 			die("Unable to add %s to database", path);
 	}
+	if (packed_buffer) {
+		if (packed_len)
+	    		if (write_packed_buffer(packed_buffer, packed_len))
+		free(packed_buffer);
+	}
 	if (write_cache(newfd, active_cache, active_nr) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("Unable to write new cachefile");

^ permalink raw reply	[relevance 22%]

* [PATCH 01/19] write_cache api signature change, isolate active_cache and active_nr inside read-cache.c
@ 2005-04-21 18:34 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:34 UTC (permalink / raw)
  To: git

tree f45fd10b26bf98349b63427805a96bd0551cad74
parent 43fdf65356c50483233cb3d6e391b0849b2a2a50
parent cd1c034369b73da7503da365fa556aab27004814
author Brad Roberts <braddr@puremagic.com> 1114072582 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114072582 -0700

[PATCH] write_cache api signature change, isolate active_cache and active_nr inside read-cache.c


Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h        |    2 +-
 read-cache.c   |    8 ++++----
 read-tree.c    |    2 +-
 update-cache.c |    2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

Index: cache.h
===================================================================
--- cd1c034369b73da7503da365fa556aab27004814:1/cache.h  (mode:100644 sha1:828d660ab82bb35a1ca632a2ba4620dc483889bd)
+++ 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/cache.h  (mode:100644 sha1:a101870e4a002a2548d88544a77bedad21668203)
@@ -88,7 +88,7 @@
 
 /* Initialize and use the cache information */
 extern int read_cache(void);
-extern int write_cache(int newfd, struct cache_entry **cache, int entries);
+extern int write_cache(int newfd);
 extern int cache_name_pos(const char *name, int namelen);
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
Index: read-cache.c
===================================================================
--- cd1c034369b73da7503da365fa556aab27004814:1/read-cache.c  (mode:100644 sha1:2f6a4aa18d48865db80459a3459ac4384b0b16c8)
+++ 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/read-cache.c  (mode:100644 sha1:349ebd1f8a0a95bf462bb1dfd3d9dfb50628829c)
@@ -267,7 +267,7 @@
 	return 0;
 }
 
-int write_cache(int newfd, struct cache_entry **cache, int entries)
+int write_cache(int newfd)
 {
 	SHA_CTX c;
 	struct cache_header hdr;
@@ -275,14 +275,14 @@
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(entries);
+	hdr.hdr_entries = htonl(active_nr);
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
+	for (i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
Index: read-tree.c
===================================================================
--- cd1c034369b73da7503da365fa556aab27004814:1/read-tree.c  (mode:100644 sha1:620f3f74eb56366fca8be4d28d7b04875c0fa90c)
+++ 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/read-tree.c  (mode:100644 sha1:4ad48f5c409ead69407d2b5feab4466cdcb499f8)
@@ -261,7 +261,7 @@
 			die("just how do you expect me to merge %d trees?", stage-1);
 		}
 	}
-	if (write_cache(newfd, active_cache, active_nr) ||
+	if (write_cache(newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("unable to write new index file");
 	remove_lock = 0;
Index: update-cache.c
===================================================================
--- cd1c034369b73da7503da365fa556aab27004814:1/update-cache.c  (mode:100644 sha1:a09883541c745c76413c62109a80f40df4b7a7fb)
+++ 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/update-cache.c  (mode:100644 sha1:585951108c57a64bb774114d289d81fd7fd22768)
@@ -341,7 +341,7 @@
 		if (add_file_to_cache(path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) ||
+	if (write_cache(newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("Unable to write new cachefile");
 


^ permalink raw reply	[relevance 26%]

* [PATCH 02/19] Add new api's to front the active_cache and active_nr cache internals
@ 2005-04-21 18:34 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:34 UTC (permalink / raw)
  To: git

tree ebbf2c037e68116c4ff934f140ca12cdbe13311d
parent 77de9e0b7a81ddc22526c9415f0273171f631d3f
author Brad Roberts <braddr@puremagic.com> 1114073146 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114073146 -0700

[PATCH] Add new api's to front the active_cache and active_nr cache internals

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h      |    3 +++
 read-cache.c |   15 +++++++++++++++
 2 files changed, 18 insertions(+)

Index: cache.h
===================================================================
--- 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/cache.h  (mode:100644 sha1:a101870e4a002a2548d88544a77bedad21668203)
+++ 27fc41dcd4aecafdaf583f3962697a2fa3fb6480:1/cache.h  (mode:100644 sha1:9ad6e805eafcb213c6bb4b1f8ff4d4e053fa6067)
@@ -93,6 +93,9 @@
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
 extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
+extern int get_num_cache_entries();
+extern struct cache_entry * get_cache_entry(int pos);
+extern void set_cache_entry(struct cache_entry *ce, int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
Index: read-cache.c
===================================================================
--- 77de9e0b7a81ddc22526c9415f0273171f631d3f:1/read-cache.c  (mode:100644 sha1:349ebd1f8a0a95bf462bb1dfd3d9dfb50628829c)
+++ 27fc41dcd4aecafdaf583f3962697a2fa3fb6480:1/read-cache.c  (mode:100644 sha1:6689df59d5a93e0503d7c80c114efbd16de826f3)
@@ -110,6 +110,21 @@
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
+int get_num_cache_entries()
+{
+	return active_nr;
+}
+
+struct cache_entry * get_cache_entry(int pos)
+{
+	return active_cache[pos];
+}
+
+void set_cache_entry(struct cache_entry *ce, int pos)
+{
+	active_cache[pos] = ce;
+}
+
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 {
 	int pos;


^ permalink raw reply	[relevance 26%]

* [PATCH 08/19] rename remove_entry_at to remove_cache_entry_at and expose as a public api
@ 2005-04-21 18:36 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:36 UTC (permalink / raw)
  To: git

tree 68af3fb1d46759f437d15f310a9aea2931708601
parent e2acfff5e544a8c6769a9e665927092b3edd7579
author Brad Roberts <braddr@puremagic.com> 1114075605 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114075605 -0700

[PATCH] rename remove_entry_at to remove_cache_entry_at and expose as a public api

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h      |    1 +
 read-cache.c |    6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

Index: cache.h
===================================================================
--- e2acfff5e544a8c6769a9e665927092b3edd7579:1/cache.h  (mode:100644 sha1:9ad6e805eafcb213c6bb4b1f8ff4d4e053fa6067)
+++ 099367f98cc063c33733d15c7a2d9737bea853d9:1/cache.h  (mode:100644 sha1:74d816c34245e0dde41643188f38cf99ca75e75f)
@@ -96,6 +96,7 @@
 extern int get_num_cache_entries();
 extern struct cache_entry * get_cache_entry(int pos);
 extern void set_cache_entry(struct cache_entry *ce, int pos);
+extern int remove_cache_entry_at(int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
Index: read-cache.c
===================================================================
--- e2acfff5e544a8c6769a9e665927092b3edd7579:1/read-cache.c  (mode:100644 sha1:8eaa05957a481b09116c37e43e16c5ef4e219a1e)
+++ 099367f98cc063c33733d15c7a2d9737bea853d9:1/read-cache.c  (mode:100644 sha1:286f7136bc164f3a2317bb492138d9221efb4025)
@@ -87,7 +87,7 @@
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-static int remove_entry_at(int pos)
+int remove_cache_entry_at(int pos)
 {
 	active_nr--;
 	if (pos >= active_nr)
@@ -100,7 +100,7 @@
 {
 	int pos = cache_name_pos(path, strlen(path));
 	if (pos >= 0)
-		remove_entry_at(pos);
+		remove_cache_entry_at(pos);
 	return 0;
 }
 
@@ -148,7 +148,7 @@
 	if (pos < active_nr && ce_stage(ce) == 0) {
 		while (same_name(active_cache[pos], ce)) {
 			ok_to_add = 1;
-			if (!remove_entry_at(pos))
+			if (!remove_cache_entry_at(pos))
 				break;
 		}
 	}


^ permalink raw reply	[relevance 26%]

* [PATCH 13/19] Remove active_cache, active_nr, and active_alloc from public view
@ 2005-04-21 18:37 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:37 UTC (permalink / raw)
  To: git

tree 9198385d73b718a2fd016362a9d93ccce1e7423c
parent cc414a188c0e8fefa7bea4f969cc7adfe4265d6f
author Brad Roberts <braddr@puremagic.com> 1114083132 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114083132 -0700

[PATCH] Remove active_cache, active_nr, and active_alloc from public view

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h      |    2 --
 read-cache.c |    4 ++--
 2 files changed, 2 insertions(+), 4 deletions(-)

Index: cache.h
===================================================================
--- cc414a188c0e8fefa7bea4f969cc7adfe4265d6f:1/cache.h  (mode:100644 sha1:74d816c34245e0dde41643188f38cf99ca75e75f)
+++ ff3667537379d5b0680e8c4f9a14d82dc9835430:1/cache.h  (mode:100644 sha1:b29bb0ca5e7be15c0b423101f5cf381ee68f139e)
@@ -78,8 +78,6 @@
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
 const char *sha1_file_directory;
-struct cache_entry **active_cache;
-unsigned int active_nr, active_alloc;
 
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
Index: read-cache.c
===================================================================
--- cc414a188c0e8fefa7bea4f969cc7adfe4265d6f:1/read-cache.c  (mode:100644 sha1:286f7136bc164f3a2317bb492138d9221efb4025)
+++ ff3667537379d5b0680e8c4f9a14d82dc9835430:1/read-cache.c  (mode:100644 sha1:0e972a80fa19eb77fd547fb579354af784be3ac4)
@@ -6,8 +6,8 @@
 #include <stdarg.h>
 #include "cache.h"
 
-struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0;
+static struct cache_entry **active_cache = NULL;
+static unsigned int active_nr = 0, active_alloc = 0;
 
 int cache_match_stat(struct cache_entry *ce, struct stat *st)
 {


^ permalink raw reply	[relevance 26%]

* [PATCH 14/19] move cache_header out of the public view
@ 2005-04-21 18:38 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:38 UTC (permalink / raw)
  To: git

tree a2c82ce3512904f82f78d87d86709a471f67ef9f
parent ff3667537379d5b0680e8c4f9a14d82dc9835430
author Brad Roberts <braddr@puremagic.com> 1114083477 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114083477 -0700

[PATCH] move cache_header out of the public view

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h      |   15 ---------------
 read-cache.c |   11 +++++++++++
 2 files changed, 11 insertions(+), 15 deletions(-)

Index: cache.h
===================================================================
--- ff3667537379d5b0680e8c4f9a14d82dc9835430:1/cache.h  (mode:100644 sha1:b29bb0ca5e7be15c0b423101f5cf381ee68f139e)
+++ b7d4fa53d4ee449b4b9b4f3c9dd40d6c99db4bc1:1/cache.h  (mode:100644 sha1:74d6c4d25c564e08eadc04aaef31a711d0645a43)
@@ -17,21 +17,6 @@
 #include <zlib.h>
 
 /*
- * Basic data structures for the directory cache
- *
- * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
- * not even trying to be portable. It's trying to be efficient. It's
- * just a cache, after all.
- */
-
-#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
-struct cache_header {
-	unsigned int hdr_signature;
-	unsigned int hdr_version;
-	unsigned int hdr_entries;
-};
-
-/*
  * The "cache_time" is just the low 32 bits of the
  * time. It doesn't matter if it overflows - we only
  * check it for equality in the 32 bits we save.
Index: read-cache.c
===================================================================
--- ff3667537379d5b0680e8c4f9a14d82dc9835430:1/read-cache.c  (mode:100644 sha1:0e972a80fa19eb77fd547fb579354af784be3ac4)
+++ b7d4fa53d4ee449b4b9b4f3c9dd40d6c99db4bc1:1/read-cache.c  (mode:100644 sha1:b16a72dc4e4525a7df060b3a43722217db7869c2)
@@ -6,6 +6,17 @@
 #include <stdarg.h>
 #include "cache.h"
 
+/*
+ * Basic data structures for the directory cache
+ */
+
+#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
+struct cache_header {
+	unsigned int hdr_signature;
+	unsigned int hdr_version;
+	unsigned int hdr_entries;
+};
+
 static struct cache_entry **active_cache = NULL;
 static unsigned int active_nr = 0, active_alloc = 0;
 


^ permalink raw reply	[relevance 26%]

* [PATCH 15/19] introduce a cache struct and move the various cache globals into it.
@ 2005-04-21 18:38 20% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:38 UTC (permalink / raw)
  To: git

tree c806c7328a6c9297df108ab00ebe1c4014496cb0
parent b7d4fa53d4ee449b4b9b4f3c9dd40d6c99db4bc1
author Brad Roberts <braddr@puremagic.com> 1114086327 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114086327 -0700

[PATCH] introduce a cache struct and move the various cache globals into it.

New elements in the cache struct that previously were discarded:
  - the cache headers
  - the mmap info so we can cleanup later

For this stage, the cache itself is still a global variable.  That will change.

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h      |    1 
 read-cache.c |  127 ++++++++++++++++++++++++++++++++++-------------------------
 2 files changed, 76 insertions(+), 52 deletions(-)

Index: cache.h
===================================================================
--- b7d4fa53d4ee449b4b9b4f3c9dd40d6c99db4bc1:1/cache.h  (mode:100644 sha1:74d6c4d25c564e08eadc04aaef31a711d0645a43)
+++ f07f7073f45a7f81e5b6cf26f5181e14fd051d81:1/cache.h  (mode:100644 sha1:a3018f9e12bfdd1a5273b20fcab5062667c6caec)
@@ -72,6 +72,7 @@
 /* Initialize and use the cache information */
 extern int read_cache(void);
 extern int write_cache(int newfd);
+extern void free_cache();
 extern int cache_name_pos(const char *name, int namelen);
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
Index: read-cache.c
===================================================================
--- b7d4fa53d4ee449b4b9b4f3c9dd40d6c99db4bc1:1/read-cache.c  (mode:100644 sha1:b16a72dc4e4525a7df060b3a43722217db7869c2)
+++ f07f7073f45a7f81e5b6cf26f5181e14fd051d81:1/read-cache.c  (mode:100644 sha1:c399f8e497441147afe630ca080558a8c6c79c78)
@@ -17,8 +17,20 @@
 	unsigned int hdr_entries;
 };
 
-static struct cache_entry **active_cache = NULL;
-static unsigned int active_nr = 0, active_alloc = 0;
+struct mmap_holder {
+	void * ptr;
+	size_t size;
+};
+
+struct cache {
+	struct mmap_holder   map;
+	struct cache_header *header;
+	struct cache_entry **entries;
+	unsigned int num_entries;
+	unsigned int allocated_entries;
+};
+
+static struct cache * cache = NULL;
 
 int cache_match_stat(struct cache_entry *ce, struct stat *st)
 {
@@ -81,10 +93,10 @@
 	int first, last;
 
 	first = 0;
-	last = active_nr;
+	last = cache->num_entries;
 	while (last > first) {
 		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
+		struct cache_entry *ce = cache->entries[next];
 		int cmp = cache_name_compare(name, namelen, ce->name, htons(ce->ce_flags));
 		if (!cmp)
 			return next;
@@ -100,10 +112,10 @@
 /* Remove entry, return true if there are more entries to go.. */
 int remove_cache_entry_at(int pos)
 {
-	active_nr--;
-	if (pos >= active_nr)
+	cache->num_entries--;
+	if (pos >= cache->num_entries)
 		return 0;
-	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
+	memmove(cache->entries + pos, cache->entries + pos + 1, (cache->num_entries - pos) * sizeof(struct cache_entry *));
 	return 1;
 }
 
@@ -123,20 +135,20 @@
 
 int get_num_cache_entries()
 {
-	return active_nr;
+	return cache->num_entries;
 }
 
 struct cache_entry * get_cache_entry(int pos)
 {
-	return active_cache[pos];
+	return cache->entries[pos];
 }
 
 void set_cache_entry(struct cache_entry *ce, int pos)
 {
-	/* You can NOT just free active_cache[i] here, since it
+	/* You can NOT just free cache->entries[i] here, since it
 	 * might not be necessarily malloc()ed but can also come
 	 * from mmap(). */
-	active_cache[pos] = ce;
+	cache->entries[pos] = ce;
 }
 
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
@@ -147,7 +159,7 @@
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
-		active_cache[pos] = ce;
+		cache->entries[pos] = ce;
 		return 0;
 	}
 	pos = -pos-1;
@@ -156,8 +168,8 @@
 	 * Inserting a merged entry ("stage 0") into the index
 	 * will always replace all non-merged entries..
 	 */
-	if (pos < active_nr && ce_stage(ce) == 0) {
-		while (same_name(active_cache[pos], ce)) {
+	if (pos < cache->num_entries && ce_stage(ce) == 0) {
+		while (same_name(cache->entries[pos], ce)) {
 			ok_to_add = 1;
 			if (!remove_cache_entry_at(pos))
 				break;
@@ -168,16 +180,16 @@
 		return -1;
 
 	/* Make sure the array is big enough .. */
-	if (active_nr == active_alloc) {
-		active_alloc = alloc_nr(active_alloc);
-		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+	if (cache->num_entries == cache->allocated_entries) {
+		cache->allocated_entries = alloc_nr(cache->allocated_entries);
+		cache->entries = realloc(cache->entries, cache->allocated_entries * sizeof(struct cache_entry *));
 	}
 
 	/* Add it in.. */
-	active_nr++;
-	if (active_nr > pos)
-		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
+	cache->num_entries++;
+	if (cache->num_entries > pos)
+		memmove(cache->entries + pos + 1, cache->entries + pos, (cache->num_entries - pos - 1) * sizeof(ce));
+	cache->entries[pos] = ce;
 	return 0;
 }
 
@@ -202,12 +214,10 @@
 {
 	int fd, i;
 	struct stat st;
-	unsigned long size, offset;
-	void *map;
-	struct cache_header *hdr;
+	unsigned long offset;
 
 	errno = EBUSY;
-	if (active_cache)
+	if (cache)
 		return error("more than one cachefile");
 	errno = ENOENT;
 	sha1_file_directory = getenv(DB_ENVIRONMENT);
@@ -219,38 +229,44 @@
 	if (fd < 0)
 		return (errno == ENOENT) ? 0 : error("open failed");
 
-	size = 0; /* avoid gcc warning */
-	map = (void *)-1;
+	errno = ENOMEM;
+	cache = (struct cache*)malloc(sizeof(struct cache));
+	if (!cache)
+		return error("unable to allocate cache");
+
+	cache->map.size = 0; /* avoid gcc warning */
+	cache->map.ptr = (void *)-1;
 	if (!fstat(fd, &st)) {
-		size = st.st_size;
+		cache->map.size = st.st_size;
 		errno = EINVAL;
-		if (size >= sizeof(struct cache_header) + 20)
-			map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+		if (cache->map.size >= sizeof(struct cache_header) + 20)
+			cache->map.ptr = mmap(NULL, cache->map.size, PROT_READ, MAP_PRIVATE, fd, 0);
 	}
 	close(fd);
-	if (-1 == (int)(long)map)
+	if (-1 == (int)(long)cache->map.ptr) {
+		free(cache);
+		cache = NULL;
 		return error("mmap failed");
+	}
 
-	hdr = map;
-	if (verify_hdr(hdr, size) < 0)
-		goto unmap;
-
-	active_nr = ntohl(hdr->hdr_entries);
-	active_alloc = alloc_nr(active_nr);
-	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
-
-	offset = sizeof(*hdr);
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = map + offset;
-		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
+	cache->header = cache->map.ptr;
+	if (verify_hdr(cache->header, cache->map.size) < 0) {
+		free_cache();
+		errno = EINVAL;
+		return error("verify header failed");
 	}
-	return active_nr;
 
-unmap:
-	munmap(map, size);
-	errno = EINVAL;
-	return error("verify header failed");
+	cache->num_entries = ntohl(cache->header->hdr_entries);
+	cache->allocated_entries = alloc_nr(cache->num_entries);
+	cache->entries = calloc(cache->allocated_entries, sizeof(struct cache_entry *));
+
+	offset = sizeof(*cache->header);
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->map.ptr + offset;
+		offset = offset + ce_size(ce);
+		cache->entries[i] = ce;
+	}
+	return cache->num_entries;
 }
 
 #define WRITE_BUFFER_SIZE 8192
@@ -304,16 +320,23 @@
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(active_nr);
+	hdr.hdr_entries = htonl(cache->num_entries);
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->entries[i];
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
 	return ce_flush(&c, newfd);
 }
+
+void free_cache()
+{
+	munmap(cache->map.ptr, cache->map.size);
+	free(cache);
+	cache = NULL;
+}


^ permalink raw reply	[relevance 20%]

* [PATCH 18/19] rename cache_match_stat to ce_match_stat to match other cache_entry related functions/macros
@ 2005-04-21 18:39 26% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:39 UTC (permalink / raw)
  To: git

tree f8dd454f774d42526149193970b612a46f3ddd26
parent 058c25fd81e5949354d96f2aad222ae73a6c1dee
author Brad Roberts <braddr@puremagic.com> 1114088345 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114088345 -0700

[PATCH] rename cache_match_stat to ce_match_stat to match other cache_entry related functions/macros

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h          |    3 ++-
 check-files.c    |    2 +-
 checkout-cache.c |    2 +-
 diff-cache.c     |    2 +-
 read-cache.c     |    2 +-
 show-diff.c      |    2 +-
 update-cache.c   |    2 +-
 7 files changed, 8 insertions(+), 7 deletions(-)

Index: cache.h
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/cache.h  (mode:100644 sha1:a3018f9e12bfdd1a5273b20fcab5062667c6caec)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/cache.h  (mode:100644 sha1:c64969602d80a0e9d7137b2716fb808c912b075c)
@@ -52,6 +52,8 @@
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
 
+extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
+
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
 #define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
@@ -76,7 +78,6 @@
 extern int cache_name_pos(const char *name, int namelen);
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
-extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
 extern int get_num_cache_entries();
 extern struct cache_entry * get_cache_entry(int pos);
 extern void set_cache_entry(struct cache_entry *ce, int pos);
Index: check-files.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/check-files.c  (mode:100644 sha1:919e418b5f0f85220445c876a37bf4cf61d26525)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/check-files.c  (mode:100644 sha1:0973e81fbbc0f9f98031fb249254bd89d8088889)
@@ -31,7 +31,7 @@
 	if (fstat(fd, &st) < 0)
 		die("fstat(%s): %s", path, strerror(errno));
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (changed)
 		die("preparing to update file '%s' not uptodate in cache", path);
 }
Index: checkout-cache.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/checkout-cache.c  (mode:100644 sha1:bf9cd0572c883219d37f2788ec5f5553a136df2b)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/checkout-cache.c  (mode:100644 sha1:27b559d5bcc5831eda441bcd1fd88d687f2567b8)
@@ -100,7 +100,7 @@
 	struct stat st;
 
 	if (!stat(ce->name, &st)) {
-		unsigned changed = cache_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st);
 		if (!changed)
 			return 0;
 		if (!force) {
Index: diff-cache.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/diff-cache.c  (mode:100644 sha1:548211944fc00594bfc06b9ab90f0cb476688285)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/diff-cache.c  (mode:100644 sha1:5ae6d5de5ed5ad34f72267904ff8eb6288855fc5)
@@ -125,7 +125,7 @@
 			show_file("-", path1, mode1, sha1, base);
 			return -1;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		close(fd);
 		if (changed) {
 			mode2 = st.st_mode;
Index: read-cache.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/read-cache.c  (mode:100644 sha1:31e293a3686622c9ec180d41aa37d85ce49325e8)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/read-cache.c  (mode:100644 sha1:8837d27ab683bf07d38aee33c62a90f5a7221588)
@@ -44,7 +44,7 @@
 	cache = NULL;
 }
 
-int cache_match_stat(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
 
Index: show-diff.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/show-diff.c  (mode:100644 sha1:6e04e9182667cbb79afa4c878a31b685fdea3229)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/show-diff.c  (mode:100644 sha1:4a0902f50b3120b7791a4d4627a9a4f729afdcf7)
@@ -193,7 +193,7 @@
 			}
 			continue;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (!changed)
 			continue;
 		if (!machine_readable)
Index: update-cache.c
===================================================================
--- 058c25fd81e5949354d96f2aad222ae73a6c1dee:1/update-cache.c  (mode:100644 sha1:8328975cb726f5e06a413a9f0099bfa2f81d3381)
+++ 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/update-cache.c  (mode:100644 sha1:3f251552283667c42797835088a4922ef865fe4a)
@@ -179,7 +179,7 @@
 	if (stat(ce->name, &st) < 0)
 		return NULL;
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (!changed)
 		return ce;
 


^ permalink raw reply	[relevance 26%]

* [PATCH 19/19] the end goal of the last dozen or so commits, there's no longer a global cache variable
@ 2005-04-21 18:39 17% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:39 UTC (permalink / raw)
  To: git

tree 38adb888a4c1adfe083f24d4ec51018e0b5a8335
parent 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac
author Brad Roberts <braddr@puremagic.com> 1114093024 -0700
committer Brad Roberts <braddr@gameboy2.puremagic.com> 1114093024 -0700

[PATCH] the end goal of the last dozen or so commits, there's no longer a global cache variable

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---

 cache.h          |   21 +++++++-------
 check-files.c    |   10 +++---
 checkout-cache.c |   20 ++++++-------
 diff-cache.c     |   20 ++++++-------
 merge-cache.c    |   29 ++++++++++---------
 read-cache.c     |   82 ++++++++++++++++++++++++++++---------------------------
 read-tree.c      |   51 ++++++++++++++++++----------------
 show-diff.c      |    8 ++---
 show-files.c     |   27 +++++++++---------
 update-cache.c   |   35 ++++++++++++-----------
 write-tree.c     |   20 ++++++-------
 11 files changed, 167 insertions(+), 156 deletions(-)

Index: cache.h
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/cache.h  (mode:100644 sha1:c64969602d80a0e9d7137b2716fb808c912b075c)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/cache.h  (mode:100644 sha1:d8ade9f4b9bd9b6045f97b4df5bef8356c767d46)
@@ -72,16 +72,17 @@
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
-extern int read_cache(void);
-extern int write_cache(int newfd);
-extern void free_cache();
-extern int cache_name_pos(const char *name, int namelen);
-extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
-extern int remove_file_from_cache(char *path);
-extern int get_num_cache_entries();
-extern struct cache_entry * get_cache_entry(int pos);
-extern void set_cache_entry(struct cache_entry *ce, int pos);
-extern int remove_cache_entry_at(int pos);
+extern struct cache *new_cache(void);
+extern struct cache *read_cache(void);
+extern int write_cache(struct cache *cache, int newfd);
+extern void free_cache(struct cache *cache);
+extern int cache_name_pos(struct cache *cache, const char *name, int namelen);
+extern int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add);
+extern int remove_file_from_cache(struct cache *cache, char *path);
+extern int get_num_cache_entries(struct cache *cache);
+extern struct cache_entry * get_cache_entry(struct cache *cache, int pos);
+extern void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos);
+extern int remove_cache_entry_at(struct cache *cache, int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
Index: check-files.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/check-files.c  (mode:100644 sha1:0973e81fbbc0f9f98031fb249254bd89d8088889)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/check-files.c  (mode:100644 sha1:4de6d39e4997d29f13261c21eeb378f74b3f8a8f)
@@ -8,7 +8,7 @@
  */
 #include "cache.h"
 
-static void check_file(const char *path)
+static void check_file(struct cache *cache, const char *path)
 {
 	int fd = open(path, O_RDONLY);
 	struct cache_entry *ce;
@@ -23,10 +23,10 @@
 	}
 
 	/* Exists but is not in the cache is not fine */
-	pos = cache_name_pos(path, strlen(path));
+	pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		die("preparing to update existing file '%s' not in cache", path);
-	ce = get_cache_entry(pos);
+	ce = get_cache_entry(cache, pos);
 
 	if (fstat(fd, &st) < 0)
 		die("fstat(%s): %s", path, strerror(errno));
@@ -39,9 +39,9 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache = read_cache();
 
-	read_cache();
 	for (i = 1; i < argc ; i++)
-		check_file(argv[i]);
+		check_file(cache, argv[i]);
 	return 0;
 }
Index: checkout-cache.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/checkout-cache.c  (mode:100644 sha1:27b559d5bcc5831eda441bcd1fd88d687f2567b8)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/checkout-cache.c  (mode:100644 sha1:2e8c61323a72f6052d8c9ef76a4eef05aa5ac0f9)
@@ -120,23 +120,23 @@
 	return write_entry(ce);
 }
 
-static int checkout_file(const char *name)
+static int checkout_file(struct cache *cache, const char *name)
 {
-	int pos = cache_name_pos(name, strlen(name));
+	int pos = cache_name_pos(cache, name, strlen(name));
 	if (pos < 0) {
 		if (!quiet)
 			fprintf(stderr, "checkout-cache: %s is not in the cache\n", name);
 		return -1;
 	}
-	return checkout_entry(get_cache_entry(pos));
+	return checkout_entry(get_cache_entry(cache, pos));
 }
 
-static int checkout_all(void)
+static int checkout_all(struct cache *cache)
 {
 	int i;
 
-	for (i = 0; i < get_num_cache_entries() ; i++) {
-		struct cache_entry *ce = get_cache_entry(i);
+	for (i = 0; i < get_num_cache_entries(cache) ; i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_stage(ce))
 			continue;
 		if (checkout_entry(ce) < 0)
@@ -149,15 +149,15 @@
 {
 	int i, force_filename = 0;
 
-	if (read_cache() < 0) {
+	struct cache * cache = read_cache();
+	if (!cache)
 		die("invalid cache");
-	}
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!force_filename) {
 			if (!strcmp(arg, "-a")) {
-				checkout_all();
+				checkout_all(cache);
 				continue;
 			}
 			if (!strcmp(arg, "--")) {
@@ -173,7 +173,7 @@
 				continue;
 			}
 		}
-		checkout_file(arg);
+		checkout_file(cache, arg);
 	}
 	return 0;
 }
Index: diff-cache.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/diff-cache.c  (mode:100644 sha1:5ae6d5de5ed5ad34f72267904ff8eb6288855fc5)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/diff-cache.c  (mode:100644 sha1:1d39ca1f79d841e363a4be57871a5c1282d441e1)
@@ -4,7 +4,7 @@
 static int recursive = 0;
 static int line_termination = '\n';
 
-static int diff_cache(void *tree, unsigned long size, int pos, const char *base);
+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base);
 
 static void update_tree_entry(void **bufp, unsigned long *sizep)
 {
@@ -82,10 +82,10 @@
 }
 
 static int compare_tree_entry(const char *path1, unsigned int mode1, const unsigned char *sha1,
-			      int *pos, const char *base)
+			      struct cache *cache, int *pos, const char *base)
 {
 	int baselen = strlen(base);
-	struct cache_entry *ce = get_cache_entry(*pos);
+	struct cache_entry *ce = get_cache_entry(cache, *pos);
 	const char *path2 = ce->name + baselen;
 	unsigned int mode2 = ntohl(ce->ce_mode);
 	const unsigned char *sha2 = ce->sha1;
@@ -107,7 +107,7 @@
 			memcpy(newbase + baselen + pathlen1, "/", 2);
 			if (!tree || strcmp(type, "tree"))
 				die("unable to read tree object %s", sha1_to_hex(sha1));
-			*pos = diff_cache(tree, size, *pos, newbase);
+			*pos = diff_cache(tree, size, cache, *pos, newbase);
 			free(newbase);
 			free(tree);
 			return -1;
@@ -158,7 +158,7 @@
 	return 0;
 }
 
-static int diff_cache(void *tree, unsigned long size, int pos, const char *base)
+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base)
 {
 	int baselen = strlen(base);
 
@@ -172,8 +172,8 @@
 		 * No entries in the cache (with this base)?
 		 * Output the tree contents.
 		 */
-		if ((pos == get_num_cache_entries()) ||
-		    ce_namelen(ce = get_cache_entry(pos)) < baselen ||
+		if ((pos == get_num_cache_entries(cache)) ||
+		    ce_namelen(ce = get_cache_entry(cache, pos)) < baselen ||
 		    memcmp(ce->name, base, baselen)) {
 			if (!size)
 				return pos;
@@ -193,7 +193,7 @@
 		}
 
 		sha1 = extract(tree, size, &path, &mode);
-		switch (compare_tree_entry(path, mode, sha1, &pos, base)) {
+		switch (compare_tree_entry(path, mode, sha1, cache, &pos, base)) {
 		case -1:
 			update_tree_entry(&tree, &size);
 			continue;
@@ -215,8 +215,8 @@
 	void *tree;
 	unsigned long size;
 	char type[20];
+	struct cache *cache = read_cache();
 
-	read_cache();
 	while (argc > 2) {
 		char *arg = argv[1];
 		argv++;
@@ -257,5 +257,5 @@
 	if (strcmp(type, "tree"))
 		die("bad tree object %s (%s)", sha1_to_hex(tree_sha1), type);
 
-	return diff_cache(tree, size, 0, "");
+	return diff_cache(tree, size, cache, 0, "");
 }
Index: merge-cache.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/merge-cache.c  (mode:100644 sha1:c2f96e7652a2aea9417c3790bfe9ab14ffcdb12f)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/merge-cache.c  (mode:100644 sha1:440d4d6e98d1387c5055ba5539b829e7557d9d4a)
@@ -26,11 +26,11 @@
 		err = 1;
 }
 
-static int merge_entry(int pos, const char *path)
+static int merge_entry(struct cache *cache, int pos, const char *path)
 {
 	int found;
 	
-	if (pos >= get_num_cache_entries())
+	if (pos >= get_num_cache_entries(cache))
 		die("merge-cache: %s not in the cache", path);
 	arguments[0] = pgm;
 	arguments[1] = "";
@@ -40,7 +40,7 @@
 	found = 0;
 	do {
 		static char hexbuf[4][60];
-		struct cache_entry *ce = get_cache_entry(pos);
+		struct cache_entry *ce = get_cache_entry(cache, pos);
 		int stage = ce_stage(ce);
 
 		if (strcmp(ce->name, path))
@@ -48,44 +48,45 @@
 		found++;
 		strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
 		arguments[stage] = hexbuf[stage];
-	} while (++pos < get_num_cache_entries());
+	} while (++pos < get_num_cache_entries(cache));
 	if (!found)
 		die("merge-cache: %s not in the cache", path);
 	run_program();
 	return found;
 }
 
-static void merge_file(const char *path)
+static void merge_file(struct cache *cache, const char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 
 	/*
 	 * If it already exists in the cache as stage0, it's
 	 * already merged and there is nothing to do.
 	 */
 	if (pos < 0)
-		merge_entry(-pos-1, path);
+		merge_entry(cache, -pos-1, path);
 }
 
-static void merge_all(void)
+static void merge_all(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < get_num_cache_entries(); i++) {
-		struct cache_entry *ce = get_cache_entry(i);
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
-		i += merge_entry(i, ce->name)-1;
+		i += merge_entry(cache, i, ce->name)-1;
 	}
 }
 
 int main(int argc, char **argv)
 {
 	int i, force_file = 0;
+	struct cache *cache;
 
 	if (argc < 3)
 		usage("merge-cache <merge-program> (-a | <filename>*)");
 
-	read_cache();
+	cache = read_cache();
 
 	pgm = argv[1];
 	for (i = 2; i < argc; i++) {
@@ -96,12 +97,12 @@
 				continue;
 			}
 			if (!strcmp(arg, "-a")) {
-				merge_all();
+				merge_all(cache);
 				continue;
 			}
 			die("merge-cache: unknown option %s", arg);
 		}
-		merge_file(arg);
+		merge_file(cache, arg);
 	}
 	if (err)
 		die("merge program failed");
Index: read-cache.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/read-cache.c  (mode:100644 sha1:8837d27ab683bf07d38aee33c62a90f5a7221588)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/read-cache.c  (mode:100644 sha1:7084fcdf771ddc5bfac38b8778a5904d779de3a4)
@@ -30,18 +30,15 @@
 	unsigned int allocated_entries;
 };
 
-static struct cache * cache = NULL;
-
 struct cache * new_cache()
 {
 	return (struct cache*)calloc(1, sizeof(struct cache));
 }
 
-void free_cache()
+void free_cache(struct cache *cache)
 {
 	munmap(cache->map.ptr, cache->map.size);
 	free(cache);
-	cache = NULL;
 }
 
 int ce_match_stat(struct cache_entry *ce, struct stat *st)
@@ -100,7 +97,7 @@
 	return 0;
 }
 
-int cache_name_pos(const char *name, int namelen)
+int cache_name_pos(struct cache *cache, const char *name, int namelen)
 {
 	int first, last;
 
@@ -122,7 +119,7 @@
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-int remove_cache_entry_at(int pos)
+int remove_cache_entry_at(struct cache *cache, int pos)
 {
 	cache->num_entries--;
 	if (pos >= cache->num_entries)
@@ -131,11 +128,11 @@
 	return 1;
 }
 
-int remove_file_from_cache(char *path)
+int remove_file_from_cache(struct cache *cache, char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 	if (pos >= 0)
-		remove_cache_entry_at(pos);
+		remove_cache_entry_at(cache, pos);
 	return 0;
 }
 
@@ -145,17 +142,17 @@
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
-int get_num_cache_entries()
+int get_num_cache_entries(struct cache *cache)
 {
 	return cache->num_entries;
 }
 
-struct cache_entry * get_cache_entry(int pos)
+struct cache_entry * get_cache_entry(struct cache *cache, int pos)
 {
 	return cache->entries[pos];
 }
 
-void set_cache_entry(struct cache_entry *ce, int pos)
+void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos)
 {
 	/* You can NOT just free cache->entries[i] here, since it
 	 * might not be necessarily malloc()ed but can also come
@@ -163,16 +160,11 @@
 	cache->entries[pos] = ce;
 }
 
-int add_cache_entry(struct cache_entry *ce, int ok_to_add)
+int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add)
 {
 	int pos;
 
-	/* temporary, read-tree.c expects the cache to always exist, even
-	 * without a read_cache being called */
-	if (!cache)
-		cache = new_cache();
-
-	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+	pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
@@ -188,7 +180,7 @@
 	if (pos < cache->num_entries && ce_stage(ce) == 0) {
 		while (same_name(cache->entries[pos], ce)) {
 			ok_to_add = 1;
-			if (!remove_cache_entry_at(pos))
+			if (!remove_cache_entry_at(cache, pos))
 				break;
 		}
 	}
@@ -227,29 +219,40 @@
 	return 0;
 }
 
-int read_cache(void)
+struct cache *read_cache(void)
 {
 	int fd, i;
 	struct stat st;
 	unsigned long offset;
+	struct cache *cache;
+
+	cache = new_cache();
+	if (!cache) {
+		errno = ENOMEM;
+		error("unable to allocate cache");
+		return NULL;
+	}
 
-	errno = EBUSY;
-	if (cache)
-		return error("more than one cachefile");
 	errno = ENOENT;
 	sha1_file_directory = getenv(DB_ENVIRONMENT);
 	if (!sha1_file_directory)
 		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
-	if (access(sha1_file_directory, X_OK) < 0)
-		return error("no access to SHA1 file directory");
+	if (access(sha1_file_directory, X_OK) < 0) {
+		error("no access to SHA1 file directory");
+		free(cache);
+		return NULL;
+	}
 	fd = open(".git/index", O_RDONLY);
-	if (fd < 0)
-		return (errno == ENOENT) ? 0 : error("open failed");
-
-	errno = ENOMEM;
-	cache = new_cache();
-	if (!cache)
-		return error("unable to allocate cache");
+	if (fd < 0) {
+		/* TODO: Why special case this?  If we can't get to the data, what's the point? */
+		if (errno == ENOENT)
+			return cache;
+		else {
+			error("open failed");
+			free(cache);
+			return NULL;
+		}
+	}
 
 	cache->map.size = 0; /* avoid gcc warning */
 	cache->map.ptr = (void *)-1;
@@ -261,16 +264,17 @@
 	}
 	close(fd);
 	if (-1 == (int)(long)cache->map.ptr) {
+		error("mmap failed");
 		free(cache);
-		cache = NULL;
-		return error("mmap failed");
+		return NULL;
 	}
 
 	cache->header = cache->map.ptr;
 	if (verify_hdr(cache->header, cache->map.size) < 0) {
-		free_cache();
+		free_cache(cache);
 		errno = EINVAL;
-		return error("verify header failed");
+		error("verify header failed");
+		return NULL;
 	}
 
 	cache->num_entries = ntohl(cache->header->hdr_entries);
@@ -283,7 +287,7 @@
 		offset = offset + ce_size(ce);
 		cache->entries[i] = ce;
 	}
-	return cache->num_entries;
+	return cache;
 }
 
 #define WRITE_BUFFER_SIZE 8192
@@ -329,7 +333,7 @@
 	return 0;
 }
 
-int write_cache(int newfd)
+int write_cache(struct cache *cache, int newfd)
 {
 	SHA_CTX c;
 	struct cache_header hdr;
Index: read-tree.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/read-tree.c  (mode:100644 sha1:ad9128f26613a82361475516dd0f2b470f4ce4b3)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/read-tree.c  (mode:100644 sha1:a683b7f60e58514d36218a7b2c2ace2d3ec9f984)
@@ -7,7 +7,7 @@
 
 static int stage = 0;
 
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
+static int read_one_entry(struct cache *cache, unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
@@ -20,10 +20,10 @@
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, 1);
+	return add_cache_entry(cache, ce, 1);
 }
 
-static int read_tree(unsigned char *sha1, const char *base, int baselen)
+static int read_tree(struct cache *cache, unsigned char *sha1, const char *base, int baselen)
 {
 	void *buffer, *bufptr;
 	unsigned long size;
@@ -57,7 +57,7 @@
 			memcpy(newbase, base, baselen);
 			memcpy(newbase + baselen, path, pathlen);
 			newbase[baselen + pathlen] = '/';
-			retval = read_tree(sha1, newbase, baselen + pathlen + 1);
+			retval = read_tree(cache, sha1, newbase, baselen + pathlen + 1);
 			free(newbase);
 			if (retval) {
 				free(buffer);
@@ -65,7 +65,7 @@
 			}
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode) < 0) {
+		if (read_one_entry(cache, sha1, base, baselen, path, mode) < 0) {
 			free(buffer);
 			return -1;
 		}
@@ -149,16 +149,16 @@
 /* rather than doing the 'right' thing of deleting entries as we merge,
  * walk dst through the cache, overwriting entries as we go and at the
  * end truncate the size of the cache */
-static void trivially_merge_cache()
+static void trivially_merge_cache(struct cache *cache)
 {
 	static struct cache_entry null_entry;
 	struct cache_entry *old = &null_entry;
-	int src = 0, dst = 0, nr = get_num_cache_entries();
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
 	while (src < nr) {
 		struct cache_entry *ce, *result;
 
-		ce = get_cache_entry(src);
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
@@ -168,8 +168,8 @@
 		}
 		if ((src < (nr - 2)) &&
 		    (result = merge_entries(ce,
-					    get_cache_entry(src + 1),
-					    get_cache_entry(src + 2))) != NULL) {
+					    get_cache_entry(cache, src + 1),
+					    get_cache_entry(cache, src + 2))) != NULL) {
 			/*
 			 * See if we can re-use the old CE directly?
 			 * That way we get the uptodate stat info.
@@ -180,27 +180,27 @@
 			ce->ce_flags &= ~htons(CE_STAGEMASK);
 			src += 2;
 		}
-		set_cache_entry(ce, dst);
+		set_cache_entry(cache, ce, dst);
 		dst++;
 		src++;
 	}
 	/* this could be replaced by a truncate api */
 	while (nr > dst) {
 		nr--;
-		remove_cache_entry_at(nr);
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
-static void merge_stat_info()
+static void merge_stat_info(struct cache *cache)
 {
 	static struct cache_entry null_entry;
 	struct cache_entry *old = &null_entry;
-	int src = 0, dst = 0, nr = get_num_cache_entries();
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
 	while (src < nr) {
 		struct cache_entry *ce;
 
-		ce = get_cache_entry(src);
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
@@ -211,14 +211,14 @@
 		if (path_matches(ce, old) && same(ce, old))
 			*ce = *old;
 		ce->ce_flags &= ~htons(CE_STAGEMASK);
-		set_cache_entry(ce, dst);
+		set_cache_entry(cache, ce, dst);
 		dst++;
 		src++;
 	}
 	/* this could be replaced by a truncate api */
 	while (nr > dst) {
 		nr--;
-		remove_cache_entry_at(nr);
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
@@ -226,6 +226,7 @@
 {
 	int i, newfd, merge;
 	unsigned char sha1[20];
+	struct cache *cache = NULL;
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
@@ -242,9 +243,9 @@
 			int i;
 			if (stage)
 				usage("-m needs to come first");
-			read_cache();
-			for (i = 0; i < get_num_cache_entries(); i++) {
-				if (ce_stage(get_cache_entry(i)))
+			cache = read_cache();
+			for (i = 0; i < get_num_cache_entries(cache); i++) {
+				if (ce_stage(get_cache_entry(cache, i)))
 					usage("you need to resolve your current index first");
 			}
 			stage = 1;
@@ -255,23 +256,25 @@
 			usage("read-tree [-m] <sha1>");
 		if (stage > 3)
 			usage("can't merge more than two trees");
-		if (read_tree(sha1, "", 0) < 0)
+		if (!cache)
+			cache = new_cache();
+		if (read_tree(cache, sha1, "", 0) < 0)
 			die("failed to unpack tree object %s", arg);
 		stage++;
 	}
 	if (merge) {
 		switch (stage) {
 		case 4:	/* Three-way merge */
-			trivially_merge_cache();
+			trivially_merge_cache(cache);
 			break;
 		case 2:	/* Just read a tree, merge with old cache contents */
-			merge_stat_info();
+			merge_stat_info(cache);
 			break;
 		default:
 			die("just how do you expect me to merge %d trees?", stage-1);
 		}
 	}
-	if (write_cache(newfd) ||
+	if (write_cache(cache, newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("unable to write new index file");
 	remove_lock = 0;
Index: show-diff.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/show-diff.c  (mode:100644 sha1:4a0902f50b3120b7791a4d4627a9a4f729afdcf7)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/show-diff.c  (mode:100644 sha1:d61bf6dea8106599c25ac5071743b351f6e000ce)
@@ -129,9 +129,9 @@
 	int entries;
 	int matched = 0;
 	int i;
+	struct cache *cache = read_cache();
 
-	read_cache();
-	entries = get_num_cache_entries();
+	entries = get_num_cache_entries(cache);
 	if (entries < 0) {
 		perror("read_cache");
 		exit(1);
@@ -157,7 +157,7 @@
 	prepare_diff_cmd();
 	for (i = 0; i < entries; i++) {
 		struct stat st;
-		struct cache_entry *ce = get_cache_entry(i);
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		int changed;
 		unsigned long size;
 		char type[20];
@@ -175,7 +175,7 @@
 				printf("%s: Unmerged\n",
 				       ce->name);
 			while (i < entries &&
-			       !strcmp(ce->name, get_cache_entry(i)->name))
+			       !strcmp(ce->name, get_cache_entry(cache, i)->name))
 				i++;
 			i--; /* compensate for loop control increments */
 			continue;
Index: show-files.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/show-files.c  (mode:100644 sha1:11fbbccef2df50d528105ceb48b15275f2a5693e)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/show-files.c  (mode:100644 sha1:c8dc21d0dd3f5db3f7016323859c58449968d800)
@@ -27,11 +27,11 @@
 static int nr_dir;
 static int dir_alloc;
 
-static void add_name(const char *pathname, int len)
+static void add_name(struct cache *cache, const char *pathname, int len)
 {
 	char *name;
 
-	if (cache_name_pos(pathname, len) >= 0)
+	if (cache_name_pos(cache, pathname, len) >= 0)
 		return;
 
 	if (nr_dir == dir_alloc) {
@@ -51,7 +51,7 @@
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
  */
-static void read_directory(const char *path, const char *base, int baselen)
+static void read_directory(struct cache *cache, const char *path, const char *base, int baselen)
 {
 	DIR *dir = opendir(path);
 
@@ -82,12 +82,12 @@
 				/* fallthrough */
 			case DT_DIR:
 				memcpy(fullname + baselen + len, "/", 2);
-				read_directory(fullname, fullname, baselen + len + 1);
+				read_directory(cache, fullname, fullname, baselen + len + 1);
 				continue;
 			case DT_REG:
 				break;
 			}
-			add_name(fullname, baselen + len);
+			add_name(cache, fullname, baselen + len);
 		}
 		closedir(dir);
 	}
@@ -102,13 +102,13 @@
 	return cache_name_compare(n1, l1, n2, l2);
 }
 
-static void show_files(void)
+static void show_files(struct cache *cache)
 {
 	int i;
 
 	/* For cached/deleted files we don't need to even do the readdir */
 	if (show_others | show_ignored) {
-		read_directory(".", "", 0);
+		read_directory(cache, ".", "", 0);
 		qsort(dir, nr_dir, sizeof(char *), cmp_name);
 	}
 	if (show_others) {
@@ -116,8 +116,8 @@
 			printf("%s%s%c", tag_other, dir[i], line_terminator);
 	}
 	if (show_cached | show_stage) {
-		for (i = 0; i < get_num_cache_entries(); i++) {
-			struct cache_entry *ce = get_cache_entry(i);
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			if (show_unmerged && !ce_stage(ce))
 				continue;
 			if (!show_stage)
@@ -136,8 +136,8 @@
 		}
 	}
 	if (show_deleted) {
-		for (i = 0; i < get_num_cache_entries(); i++) {
-			struct cache_entry *ce = get_cache_entry(i);
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			struct stat st;
 			if (!stat(ce->name, &st))
 				continue;
@@ -152,6 +152,7 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache;
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
@@ -202,7 +203,7 @@
 	if (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))
 		show_cached = 1;
 
-	read_cache();
-	show_files();
+	cache = read_cache();
+	show_files(cache);
 	return 0;
 }
Index: update-cache.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/update-cache.c  (mode:100644 sha1:3f251552283667c42797835088a4922ef865fe4a)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/update-cache.c  (mode:100644 sha1:565638acd2380023ea69e82316a7ab77d95d8ee7)
@@ -85,7 +85,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(struct cache *cache, char *path)
 {
 	int size, namelen;
 	struct cache_entry *ce;
@@ -96,7 +96,7 @@
 	if (fd < 0) {
 		if (errno == ENOENT) {
 			if (allow_remove)
-				return remove_file_from_cache(path);
+				return remove_file_from_cache(cache, path);
 		}
 		return -1;
 	}
@@ -117,7 +117,7 @@
 		free(ce);
 		return -1;
 	}
-	if (add_cache_entry(ce, allow_add)) {
+	if (add_cache_entry(cache, ce, allow_add)) {
 		free(ce);
 		return -1;
 	}
@@ -200,17 +200,17 @@
 	return updated;
 }
 
-static void refresh_cache(void)
+static void refresh_cache(struct cache *cache)
 {
 	int i;
 
-	for (i = 0; i < get_num_cache_entries(); i++) {
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
 		struct cache_entry *ce, *new;
-		ce = get_cache_entry(i);
+		ce = get_cache_entry(cache, i);
 		if (ce_stage(ce)) {
 			printf("%s: needs merge\n", ce->name);
-			while ((i < get_num_cache_entries()) &&
-			       ! strcmp(get_cache_entry(i)->name, ce->name))
+			while ((i < get_num_cache_entries(cache)) &&
+			       ! strcmp(get_cache_entry(cache, i)->name, ce->name))
 				i++;
 			i--;
 			continue;
@@ -221,7 +221,7 @@
 			printf("%s: needs update\n", ce->name);
 			continue;
 		}
-		set_cache_entry(new, i);
+		set_cache_entry(cache, new, i);
 	}
 }
 
@@ -253,7 +253,7 @@
 	}
 }
 
-static int add_cacheinfo(char *arg1, char *arg2, char *arg3)
+static int add_cacheinfo(struct cache *cache, char *arg1, char *arg2, char *arg3)
 {
 	int size, len;
 	unsigned int mode;
@@ -276,7 +276,7 @@
 	memcpy(ce->name, arg3, len);
 	ce->ce_flags = htons(len);
 	ce->ce_mode = create_ce_mode(mode);
-	return add_cache_entry(ce, allow_add);
+	return add_cache_entry(cache, ce, allow_add);
 }
 
 static int remove_lock = 0;
@@ -291,6 +291,7 @@
 {
 	int i, newfd, entries;
 	int allow_options = 1;
+	struct cache *cache = NULL;
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
@@ -299,8 +300,8 @@
 	atexit(remove_lock_file);
 	remove_lock = 1;
 
-	read_cache();
-	entries = get_num_cache_entries();
+	cache = read_cache();
+	entries = get_num_cache_entries(cache);
 	if (entries < 0)
 		die("cache corrupted");
 
@@ -321,11 +322,11 @@
 				continue;
 			}
 			if (!strcmp(path, "--refresh")) {
-				refresh_cache();
+				refresh_cache(cache);
 				continue;
 			}
 			if (!strcmp(path, "--cacheinfo")) {
-				if (i+3 >= argc || add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))
+				if (i+3 >= argc || add_cacheinfo(cache, argv[i+1], argv[i+2], argv[i+3]))
 					die("update-cache: --cacheinfo <mode> <sha1> <path>");
 				i += 3;
 				continue;
@@ -336,10 +337,10 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(cache, path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd) ||
+	if (write_cache(cache, newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("Unable to write new cachefile");
 
Index: write-tree.c
===================================================================
--- 0a556dc01b8e48f684ce6e0c26f8c00b5e39c4ac:1/write-tree.c  (mode:100644 sha1:92e707fd4780805da160ce6fa282e75111ea67b9)
+++ 7e396358c12c0129bcb4945e3e35a4fa76890a0c:1/write-tree.c  (mode:100644 sha1:ad148b422ffa85d7ecf515e55538c1afa13f17d6)
@@ -29,7 +29,7 @@
 
 #define ORIG_OFFSET (40)	/* Enough space to add the header of "tree <size>\0" */
 
-static int write_tree(int start_pos, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache *cache, int start_pos, const char *base, int baselen, unsigned char *returnsha1)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
@@ -43,7 +43,7 @@
 
 	nr = 0;
 	do {
-		struct cache_entry *ce = get_cache_entry(start_pos + nr);
+		struct cache_entry *ce = get_cache_entry(cache, start_pos + nr);
 		const char *pathname = ce->name, *filename, *dirname;
 		int pathlen = ce_namelen(ce), entrylen;
 		unsigned char *sha1;
@@ -59,7 +59,7 @@
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cache, start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -87,7 +87,7 @@
 		memcpy(buffer + offset, sha1, 20);
 		offset += 20;
 		nr++;
-	} while ((start_pos + nr) < get_num_cache_entries());
+	} while ((start_pos + nr) < get_num_cache_entries(cache));
 
 	i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
 	i -= 5;
@@ -101,18 +101,18 @@
 int main(int argc, char **argv)
 {
 	int i, unmerged;
-	int entries;
 	unsigned char sha1[20];
+	struct cache *cache = read_cache();
+	int entries;
 
-	read_cache();
-	entries = get_num_cache_entries();
-	if (entries <= 0)
+	if (!cache)
 		die("write-tree: no cache contents to write");
+	entries = get_num_cache_entries(cache);
 
 	/* Verify that the tree is merged */
 	unmerged = 0;
 	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = get_cache_entry(i);
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
 			if (++unmerged > 10) {
 				fprintf(stderr, "...\n");
@@ -125,7 +125,7 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(0, "", 0, sha1) != entries)
+	if (write_tree(cache, 0, "", 0, sha1) != entries)
 		die("write-tree: internal error");
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;


^ permalink raw reply	[relevance 17%]

* [PATCH 01-19/19] All of the above combined
@ 2005-04-21 18:39 15% Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-04-21 18:39 UTC (permalink / raw)
  To: git

Make the cache management code behave more like a library.  There are no
longer any global variables in read-cache.c.  Nothing ever uses more than
one cache yet, but I can see how it might simplify some of the merge code.

Signed-off-by: Brad Roberts <braddr@puremagic.com>
---
 
 cache.h          |   36 +++------
 check-files.c    |   12 +--
 checkout-cache.c |   22 +++---
 diff-cache.c     |   36 ++++-----
 merge-cache.c    |   29 ++++---
 read-cache.c     |  200 ++++++++++++++++++++++++++++++++++++-------------------
 read-tree.c      |   71 +++++++++++--------
 show-diff.c      |   19 +++--
 show-files.c     |   27 +++----
 update-cache.c   |   39 +++++-----
 write-tree.c     |   24 +++---
11 files changed, 292 insertions(+), 223 deletions(-)

Index: cache.h
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/cache.h  (mode:100644 sha1:828d660ab82bb35a1ca632a2ba4620dc483889bd)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/cache.h  (mode:100644 sha1:d8ade9f4b9bd9b6045f97b4df5bef8356c767d46)
@@ -17,21 +17,6 @@
 #include <zlib.h>
 
 /*
- * Basic data structures for the directory cache
- *
- * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
- * not even trying to be portable. It's trying to be efficient. It's
- * just a cache, after all.
- */
-
-#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
-struct cache_header {
-	unsigned int hdr_signature;
-	unsigned int hdr_version;
-	unsigned int hdr_entries;
-};
-
-/*
  * The "cache_time" is just the low 32 bits of the
  * time. It doesn't matter if it overflows - we only
  * check it for equality in the 32 bits we save.
@@ -67,6 +52,8 @@
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
 
+extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
+
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
 #define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
@@ -78,8 +65,6 @@
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
 const char *sha1_file_directory;
-struct cache_entry **active_cache;
-unsigned int active_nr, active_alloc;
 
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
@@ -87,12 +72,17 @@
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
-extern int read_cache(void);
-extern int write_cache(int newfd, struct cache_entry **cache, int entries);
-extern int cache_name_pos(const char *name, int namelen);
-extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
-extern int remove_file_from_cache(char *path);
-extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
+extern struct cache *new_cache(void);
+extern struct cache *read_cache(void);
+extern int write_cache(struct cache *cache, int newfd);
+extern void free_cache(struct cache *cache);
+extern int cache_name_pos(struct cache *cache, const char *name, int namelen);
+extern int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add);
+extern int remove_file_from_cache(struct cache *cache, char *path);
+extern int get_num_cache_entries(struct cache *cache);
+extern struct cache_entry * get_cache_entry(struct cache *cache, int pos);
+extern void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos);
+extern int remove_cache_entry_at(struct cache *cache, int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
Index: check-files.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/check-files.c  (mode:100644 sha1:7d16691aa9d51b5b4670d5837b3527ee7c7da79c)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/check-files.c  (mode:100644 sha1:4de6d39e4997d29f13261c21eeb378f74b3f8a8f)
@@ -8,7 +8,7 @@
  */
 #include "cache.h"
 
-static void check_file(const char *path)
+static void check_file(struct cache *cache, const char *path)
 {
 	int fd = open(path, O_RDONLY);
 	struct cache_entry *ce;
@@ -23,15 +23,15 @@
 	}
 
 	/* Exists but is not in the cache is not fine */
-	pos = cache_name_pos(path, strlen(path));
+	pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		die("preparing to update existing file '%s' not in cache", path);
-	ce = active_cache[pos];
+	ce = get_cache_entry(cache, pos);
 
 	if (fstat(fd, &st) < 0)
 		die("fstat(%s): %s", path, strerror(errno));
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (changed)
 		die("preparing to update file '%s' not uptodate in cache", path);
 }
@@ -39,9 +39,9 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache = read_cache();
 
-	read_cache();
 	for (i = 1; i < argc ; i++)
-		check_file(argv[i]);
+		check_file(cache, argv[i]);
 	return 0;
 }
Index: checkout-cache.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/checkout-cache.c  (mode:100644 sha1:8bf86016b5d5fd88a52ce694fc59bb9ecb550d22)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/checkout-cache.c  (mode:100644 sha1:2e8c61323a72f6052d8c9ef76a4eef05aa5ac0f9)
@@ -100,7 +100,7 @@
 	struct stat st;
 
 	if (!stat(ce->name, &st)) {
-		unsigned changed = cache_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st);
 		if (!changed)
 			return 0;
 		if (!force) {
@@ -120,23 +120,23 @@
 	return write_entry(ce);
 }
 
-static int checkout_file(const char *name)
+static int checkout_file(struct cache *cache, const char *name)
 {
-	int pos = cache_name_pos(name, strlen(name));
+	int pos = cache_name_pos(cache, name, strlen(name));
 	if (pos < 0) {
 		if (!quiet)
 			fprintf(stderr, "checkout-cache: %s is not in the cache\n", name);
 		return -1;
 	}
-	return checkout_entry(active_cache[pos]);
+	return checkout_entry(get_cache_entry(cache, pos));
 }
 
-static int checkout_all(void)
+static int checkout_all(struct cache *cache)
 {
 	int i;
 
-	for (i = 0; i < active_nr ; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache) ; i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_stage(ce))
 			continue;
 		if (checkout_entry(ce) < 0)
@@ -149,15 +149,15 @@
 {
 	int i, force_filename = 0;
 
-	if (read_cache() < 0) {
+	struct cache * cache = read_cache();
+	if (!cache)
 		die("invalid cache");
-	}
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!force_filename) {
 			if (!strcmp(arg, "-a")) {
-				checkout_all();
+				checkout_all(cache);
 				continue;
 			}
 			if (!strcmp(arg, "--")) {
@@ -173,7 +173,7 @@
 				continue;
 			}
 		}
-		checkout_file(arg);
+		checkout_file(cache, arg);
 	}
 	return 0;
 }
Index: diff-cache.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/diff-cache.c  (mode:100644 sha1:fcbc4900d32f4ca24f67bb8f0fe344c6c5642ac9)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/diff-cache.c  (mode:100644 sha1:1d39ca1f79d841e363a4be57871a5c1282d441e1)
@@ -4,7 +4,7 @@
 static int recursive = 0;
 static int line_termination = '\n';
 
-static int diff_cache(void *tree, unsigned long size, struct cache_entry **ac, int entries, const char *base);
+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base);
 
 static void update_tree_entry(void **bufp, unsigned long *sizep)
 {
@@ -82,10 +82,10 @@
 }
 
 static int compare_tree_entry(const char *path1, unsigned int mode1, const unsigned char *sha1,
-			      struct cache_entry **ac, int *entries, const char *base)
+			      struct cache *cache, int *pos, const char *base)
 {
 	int baselen = strlen(base);
-	struct cache_entry *ce = *ac;
+	struct cache_entry *ce = get_cache_entry(cache, *pos);
 	const char *path2 = ce->name + baselen;
 	unsigned int mode2 = ntohl(ce->ce_mode);
 	const unsigned char *sha2 = ce->sha1;
@@ -107,7 +107,7 @@
 			memcpy(newbase + baselen + pathlen1, "/", 2);
 			if (!tree || strcmp(type, "tree"))
 				die("unable to read tree object %s", sha1_to_hex(sha1));
-			*entries = diff_cache(tree, size, ac, *entries, newbase);
+			*pos = diff_cache(tree, size, cache, *pos, newbase);
 			free(newbase);
 			free(tree);
 			return -1;
@@ -125,7 +125,7 @@
 			show_file("-", path1, mode1, sha1, base);
 			return -1;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		close(fd);
 		if (changed) {
 			mode2 = st.st_mode;
@@ -158,7 +158,7 @@
 	return 0;
 }
 
-static int diff_cache(void *tree, unsigned long size, struct cache_entry **ac, int entries, const char *base)
+static int diff_cache(void *tree, unsigned long size, struct cache *cache, int pos, const char *base)
 {
 	int baselen = strlen(base);
 
@@ -167,15 +167,16 @@
 		unsigned int mode;
 		const char *path;
 		const unsigned char *sha1;
-		int left;
 
 		/*
 		 * No entries in the cache (with this base)?
 		 * Output the tree contents.
 		 */
-		if (!entries || ce_namelen(ce = *ac) < baselen || memcmp(ce->name, base, baselen)) {
+		if ((pos == get_num_cache_entries(cache)) ||
+		    ce_namelen(ce = get_cache_entry(cache, pos)) < baselen ||
+		    memcmp(ce->name, base, baselen)) {
 			if (!size)
-				return entries;
+				return pos;
 			sha1 = extract(tree, size, &path, &mode);
 			show_file("-", path, mode, sha1, base);
 			update_tree_entry(&tree, &size);
@@ -187,27 +188,20 @@
 		 */
 		if (!size) {
 			show_file("+", ce->name, ntohl(ce->ce_mode), ce->sha1, "");
-			ac++;
-			entries--;
+			pos++;
 			continue;
 		}
 
 		sha1 = extract(tree, size, &path, &mode);
-		left = entries;
-		switch (compare_tree_entry(path, mode, sha1, ac, &left, base)) {
+		switch (compare_tree_entry(path, mode, sha1, cache, &pos, base)) {
 		case -1:
 			update_tree_entry(&tree, &size);
-			if (left < entries) {
-				ac += (entries - left);
-				entries = left;
-			}
 			continue;
 		case 0:
 			update_tree_entry(&tree, &size);
 			/* Fallthrough */
 		case 1:
-			ac++;
-			entries--;
+			pos++;
 			continue;
 		}
 		die("diff-cache: internal error");
@@ -221,8 +215,8 @@
 	void *tree;
 	unsigned long size;
 	char type[20];
+	struct cache *cache = read_cache();
 
-	read_cache();
 	while (argc > 2) {
 		char *arg = argv[1];
 		argv++;
@@ -263,5 +257,5 @@
 	if (strcmp(type, "tree"))
 		die("bad tree object %s (%s)", sha1_to_hex(tree_sha1), type);
 
-	return diff_cache(tree, size, active_cache, active_nr, "");
+	return diff_cache(tree, size, cache, 0, "");
 }
Index: merge-cache.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/merge-cache.c  (mode:100644 sha1:35a0d588178aa5371399458b1a15519cffd645b8)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/merge-cache.c  (mode:100644 sha1:440d4d6e98d1387c5055ba5539b829e7557d9d4a)
@@ -26,11 +26,11 @@
 		err = 1;
 }
 
-static int merge_entry(int pos, const char *path)
+static int merge_entry(struct cache *cache, int pos, const char *path)
 {
 	int found;
 	
-	if (pos >= active_nr)
+	if (pos >= get_num_cache_entries(cache))
 		die("merge-cache: %s not in the cache", path);
 	arguments[0] = pgm;
 	arguments[1] = "";
@@ -40,7 +40,7 @@
 	found = 0;
 	do {
 		static char hexbuf[4][60];
-		struct cache_entry *ce = active_cache[pos];
+		struct cache_entry *ce = get_cache_entry(cache, pos);
 		int stage = ce_stage(ce);
 
 		if (strcmp(ce->name, path))
@@ -48,44 +48,45 @@
 		found++;
 		strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
 		arguments[stage] = hexbuf[stage];
-	} while (++pos < active_nr);
+	} while (++pos < get_num_cache_entries(cache));
 	if (!found)
 		die("merge-cache: %s not in the cache", path);
 	run_program();
 	return found;
 }
 
-static void merge_file(const char *path)
+static void merge_file(struct cache *cache, const char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 
 	/*
 	 * If it already exists in the cache as stage0, it's
 	 * already merged and there is nothing to do.
 	 */
 	if (pos < 0)
-		merge_entry(-pos-1, path);
+		merge_entry(cache, -pos-1, path);
 }
 
-static void merge_all(void)
+static void merge_all(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
-		i += merge_entry(i, ce->name)-1;
+		i += merge_entry(cache, i, ce->name)-1;
 	}
 }
 
 int main(int argc, char **argv)
 {
 	int i, force_file = 0;
+	struct cache *cache;
 
 	if (argc < 3)
 		usage("merge-cache <merge-program> (-a | <filename>*)");
 
-	read_cache();
+	cache = read_cache();
 
 	pgm = argv[1];
 	for (i = 2; i < argc; i++) {
@@ -96,12 +97,12 @@
 				continue;
 			}
 			if (!strcmp(arg, "-a")) {
-				merge_all();
+				merge_all(cache);
 				continue;
 			}
 			die("merge-cache: unknown option %s", arg);
 		}
-		merge_file(arg);
+		merge_file(cache, arg);
 	}
 	if (err)
 		die("merge program failed");
Index: read-cache.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/read-cache.c  (mode:100644 sha1:2f6a4aa18d48865db80459a3459ac4384b0b16c8)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/read-cache.c  (mode:100644 sha1:7084fcdf771ddc5bfac38b8778a5904d779de3a4)
@@ -6,10 +6,42 @@
 #include <stdarg.h>
 #include "cache.h"
 
-struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0;
+/*
+ * Basic data structures for the directory cache
+ */
 
-int cache_match_stat(struct cache_entry *ce, struct stat *st)
+#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
+struct cache_header {
+	unsigned int hdr_signature;
+	unsigned int hdr_version;
+	unsigned int hdr_entries;
+};
+
+struct mmap_holder {
+	void * ptr;
+	size_t size;
+};
+
+struct cache {
+	struct mmap_holder   map;
+	struct cache_header *header;
+	struct cache_entry **entries;
+	unsigned int num_entries;
+	unsigned int allocated_entries;
+};
+
+struct cache * new_cache()
+{
+	return (struct cache*)calloc(1, sizeof(struct cache));
+}
+
+void free_cache(struct cache *cache)
+{
+	munmap(cache->map.ptr, cache->map.size);
+	free(cache);
+}
+
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
 
@@ -65,15 +97,15 @@
 	return 0;
 }
 
-int cache_name_pos(const char *name, int namelen)
+int cache_name_pos(struct cache *cache, const char *name, int namelen)
 {
 	int first, last;
 
 	first = 0;
-	last = active_nr;
+	last = cache->num_entries;
 	while (last > first) {
 		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
+		struct cache_entry *ce = cache->entries[next];
 		int cmp = cache_name_compare(name, namelen, ce->name, htons(ce->ce_flags));
 		if (!cmp)
 			return next;
@@ -87,20 +119,20 @@
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-static int remove_entry_at(int pos)
+int remove_cache_entry_at(struct cache *cache, int pos)
 {
-	active_nr--;
-	if (pos >= active_nr)
+	cache->num_entries--;
+	if (pos >= cache->num_entries)
 		return 0;
-	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
+	memmove(cache->entries + pos, cache->entries + pos + 1, (cache->num_entries - pos) * sizeof(struct cache_entry *));
 	return 1;
 }
 
-int remove_file_from_cache(char *path)
+int remove_file_from_cache(struct cache *cache, char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 	if (pos >= 0)
-		remove_entry_at(pos);
+		remove_cache_entry_at(cache, pos);
 	return 0;
 }
 
@@ -110,15 +142,33 @@
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
-int add_cache_entry(struct cache_entry *ce, int ok_to_add)
+int get_num_cache_entries(struct cache *cache)
+{
+	return cache->num_entries;
+}
+
+struct cache_entry * get_cache_entry(struct cache *cache, int pos)
+{
+	return cache->entries[pos];
+}
+
+void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos)
+{
+	/* You can NOT just free cache->entries[i] here, since it
+	 * might not be necessarily malloc()ed but can also come
+	 * from mmap(). */
+	cache->entries[pos] = ce;
+}
+
+int add_cache_entry(struct cache *cache, struct cache_entry *ce, int ok_to_add)
 {
 	int pos;
 
-	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+	pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
-		active_cache[pos] = ce;
+		cache->entries[pos] = ce;
 		return 0;
 	}
 	pos = -pos-1;
@@ -127,10 +177,10 @@
 	 * Inserting a merged entry ("stage 0") into the index
 	 * will always replace all non-merged entries..
 	 */
-	if (pos < active_nr && ce_stage(ce) == 0) {
-		while (same_name(active_cache[pos], ce)) {
+	if (pos < cache->num_entries && ce_stage(ce) == 0) {
+		while (same_name(cache->entries[pos], ce)) {
 			ok_to_add = 1;
-			if (!remove_entry_at(pos))
+			if (!remove_cache_entry_at(cache, pos))
 				break;
 		}
 	}
@@ -139,16 +189,16 @@
 		return -1;
 
 	/* Make sure the array is big enough .. */
-	if (active_nr == active_alloc) {
-		active_alloc = alloc_nr(active_alloc);
-		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+	if (cache->num_entries == cache->allocated_entries) {
+		cache->allocated_entries = alloc_nr(cache->allocated_entries);
+		cache->entries = realloc(cache->entries, cache->allocated_entries * sizeof(struct cache_entry *));
 	}
 
 	/* Add it in.. */
-	active_nr++;
-	if (active_nr > pos)
-		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
+	cache->num_entries++;
+	if (cache->num_entries > pos)
+		memmove(cache->entries + pos + 1, cache->entries + pos, (cache->num_entries - pos - 1) * sizeof(ce));
+	cache->entries[pos] = ce;
 	return 0;
 }
 
@@ -169,59 +219,75 @@
 	return 0;
 }
 
-int read_cache(void)
+struct cache *read_cache(void)
 {
 	int fd, i;
 	struct stat st;
-	unsigned long size, offset;
-	void *map;
-	struct cache_header *hdr;
-
-	errno = EBUSY;
-	if (active_cache)
-		return error("more than one cachefile");
+	unsigned long offset;
+	struct cache *cache;
+
+	cache = new_cache();
+	if (!cache) {
+		errno = ENOMEM;
+		error("unable to allocate cache");
+		return NULL;
+	}
+
 	errno = ENOENT;
 	sha1_file_directory = getenv(DB_ENVIRONMENT);
 	if (!sha1_file_directory)
 		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
-	if (access(sha1_file_directory, X_OK) < 0)
-		return error("no access to SHA1 file directory");
+	if (access(sha1_file_directory, X_OK) < 0) {
+		error("no access to SHA1 file directory");
+		free(cache);
+		return NULL;
+	}
 	fd = open(".git/index", O_RDONLY);
-	if (fd < 0)
-		return (errno == ENOENT) ? 0 : error("open failed");
+	if (fd < 0) {
+		/* TODO: Why special case this?  If we can't get to the data, what's the point? */
+		if (errno == ENOENT)
+			return cache;
+		else {
+			error("open failed");
+			free(cache);
+			return NULL;
+		}
+	}
 
-	size = 0; /* avoid gcc warning */
-	map = (void *)-1;
+	cache->map.size = 0; /* avoid gcc warning */
+	cache->map.ptr = (void *)-1;
 	if (!fstat(fd, &st)) {
-		size = st.st_size;
+		cache->map.size = st.st_size;
 		errno = EINVAL;
-		if (size >= sizeof(struct cache_header) + 20)
-			map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+		if (cache->map.size >= sizeof(struct cache_header) + 20)
+			cache->map.ptr = mmap(NULL, cache->map.size, PROT_READ, MAP_PRIVATE, fd, 0);
 	}
 	close(fd);
-	if (-1 == (int)(long)map)
-		return error("mmap failed");
+	if (-1 == (int)(long)cache->map.ptr) {
+		error("mmap failed");
+		free(cache);
+		return NULL;
+	}
 
-	hdr = map;
-	if (verify_hdr(hdr, size) < 0)
-		goto unmap;
-
-	active_nr = ntohl(hdr->hdr_entries);
-	active_alloc = alloc_nr(active_nr);
-	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
-
-	offset = sizeof(*hdr);
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = map + offset;
-		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
+	cache->header = cache->map.ptr;
+	if (verify_hdr(cache->header, cache->map.size) < 0) {
+		free_cache(cache);
+		errno = EINVAL;
+		error("verify header failed");
+		return NULL;
 	}
-	return active_nr;
 
-unmap:
-	munmap(map, size);
-	errno = EINVAL;
-	return error("verify header failed");
+	cache->num_entries = ntohl(cache->header->hdr_entries);
+	cache->allocated_entries = alloc_nr(cache->num_entries);
+	cache->entries = calloc(cache->allocated_entries, sizeof(struct cache_entry *));
+
+	offset = sizeof(*cache->header);
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->map.ptr + offset;
+		offset = offset + ce_size(ce);
+		cache->entries[i] = ce;
+	}
+	return cache;
 }
 
 #define WRITE_BUFFER_SIZE 8192
@@ -267,7 +333,7 @@
 	return 0;
 }
 
-int write_cache(int newfd, struct cache_entry **cache, int entries)
+int write_cache(struct cache *cache, int newfd)
 {
 	SHA_CTX c;
 	struct cache_header hdr;
@@ -275,14 +341,14 @@
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(entries);
+	hdr.hdr_entries = htonl(cache->num_entries);
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->entries[i];
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
Index: read-tree.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/read-tree.c  (mode:100644 sha1:620f3f74eb56366fca8be4d28d7b04875c0fa90c)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/read-tree.c  (mode:100644 sha1:a683b7f60e58514d36218a7b2c2ace2d3ec9f984)
@@ -7,7 +7,7 @@
 
 static int stage = 0;
 
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
+static int read_one_entry(struct cache *cache, unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
@@ -20,10 +20,10 @@
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, 1);
+	return add_cache_entry(cache, ce, 1);
 }
 
-static int read_tree(unsigned char *sha1, const char *base, int baselen)
+static int read_tree(struct cache *cache, unsigned char *sha1, const char *base, int baselen)
 {
 	void *buffer, *bufptr;
 	unsigned long size;
@@ -57,7 +57,7 @@
 			memcpy(newbase, base, baselen);
 			memcpy(newbase + baselen, path, pathlen);
 			newbase[baselen + pathlen] = '/';
-			retval = read_tree(sha1, newbase, baselen + pathlen + 1);
+			retval = read_tree(cache, sha1, newbase, baselen + pathlen + 1);
 			free(newbase);
 			if (retval) {
 				free(buffer);
@@ -65,7 +65,7 @@
 			}
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode) < 0) {
+		if (read_one_entry(cache, sha1, base, baselen, path, mode) < 0) {
 			free(buffer);
 			return -1;
 		}
@@ -146,26 +146,30 @@
 	return NULL;
 }
 
-static void trivially_merge_cache(struct cache_entry **src, int nr)
+/* rather than doing the 'right' thing of deleting entries as we merge,
+ * walk dst through the cache, overwriting entries as we go and at the
+ * end truncate the size of the cache */
+static void trivially_merge_cache(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce, *result;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
-		if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) {
+		if ((src < (nr - 2)) &&
+		    (result = merge_entries(ce,
+					    get_cache_entry(cache, src + 1),
+					    get_cache_entry(cache, src + 2))) != NULL) {
 			/*
 			 * See if we can re-use the old CE directly?
 			 * That way we get the uptodate stat info.
@@ -175,40 +179,46 @@
 			ce = result;
 			ce->ce_flags &= ~htons(CE_STAGEMASK);
 			src += 2;
-			nr -= 2;
-			active_nr -= 2;
 		}
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
-static void merge_stat_info(struct cache_entry **src, int nr)
+static void merge_stat_info(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
 		if (path_matches(ce, old) && same(ce, old))
 			*ce = *old;
 		ce->ce_flags &= ~htons(CE_STAGEMASK);
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
@@ -216,6 +226,7 @@
 {
 	int i, newfd, merge;
 	unsigned char sha1[20];
+	struct cache *cache = NULL;
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
@@ -232,9 +243,9 @@
 			int i;
 			if (stage)
 				usage("-m needs to come first");
-			read_cache();
-			for (i = 0; i < active_nr; i++) {
-				if (ce_stage(active_cache[i]))
+			cache = read_cache();
+			for (i = 0; i < get_num_cache_entries(cache); i++) {
+				if (ce_stage(get_cache_entry(cache, i)))
 					usage("you need to resolve your current index first");
 			}
 			stage = 1;
@@ -245,23 +256,25 @@
 			usage("read-tree [-m] <sha1>");
 		if (stage > 3)
 			usage("can't merge more than two trees");
-		if (read_tree(sha1, "", 0) < 0)
+		if (!cache)
+			cache = new_cache();
+		if (read_tree(cache, sha1, "", 0) < 0)
 			die("failed to unpack tree object %s", arg);
 		stage++;
 	}
 	if (merge) {
 		switch (stage) {
 		case 4:	/* Three-way merge */
-			trivially_merge_cache(active_cache, active_nr);
+			trivially_merge_cache(cache);
 			break;
 		case 2:	/* Just read a tree, merge with old cache contents */
-			merge_stat_info(active_cache, active_nr);
+			merge_stat_info(cache);
 			break;
 		default:
 			die("just how do you expect me to merge %d trees?", stage-1);
 		}
 	}
-	if (write_cache(newfd, active_cache, active_nr) ||
+	if (write_cache(cache, newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("unable to write new index file");
 	remove_lock = 0;
Index: show-diff.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/show-diff.c  (mode:100644 sha1:da364e26e28823f951a6be1b686a458575f28ea1)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/show-diff.c  (mode:100644 sha1:d61bf6dea8106599c25ac5071743b351f6e000ce)
@@ -126,9 +126,16 @@
 	int silent_on_nonexisting_files = 0;
 	int machine_readable = 0;
 	int reverse = 0;
-	int entries = read_cache();
+	int entries;
 	int matched = 0;
 	int i;
+	struct cache *cache = read_cache();
+
+	entries = get_num_cache_entries(cache);
+	if (entries < 0) {
+		perror("read_cache");
+		exit(1);
+	}
 
 	while (1 < argc && argv[1][0] == '-') {
 		if  (!strcmp(argv[1], "-R"))
@@ -147,14 +154,10 @@
 	/* At this point, if argc == 1, then we are doing everything.
 	 * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
 	 */
-	if (entries < 0) {
-		perror("read_cache");
-		exit(1);
-	}
 	prepare_diff_cmd();
 	for (i = 0; i < entries; i++) {
 		struct stat st;
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		int changed;
 		unsigned long size;
 		char type[20];
@@ -172,7 +175,7 @@
 				printf("%s: Unmerged\n",
 				       ce->name);
 			while (i < entries &&
-			       !strcmp(ce->name, active_cache[i]->name))
+			       !strcmp(ce->name, get_cache_entry(cache, i)->name))
 				i++;
 			i--; /* compensate for loop control increments */
 			continue;
@@ -190,7 +193,7 @@
 			}
 			continue;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (!changed)
 			continue;
 		if (!machine_readable)
Index: show-files.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/show-files.c  (mode:100644 sha1:0b49ca051de413e7182445dd8fb9144125716974)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/show-files.c  (mode:100644 sha1:c8dc21d0dd3f5db3f7016323859c58449968d800)
@@ -27,11 +27,11 @@
 static int nr_dir;
 static int dir_alloc;
 
-static void add_name(const char *pathname, int len)
+static void add_name(struct cache *cache, const char *pathname, int len)
 {
 	char *name;
 
-	if (cache_name_pos(pathname, len) >= 0)
+	if (cache_name_pos(cache, pathname, len) >= 0)
 		return;
 
 	if (nr_dir == dir_alloc) {
@@ -51,7 +51,7 @@
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
  */
-static void read_directory(const char *path, const char *base, int baselen)
+static void read_directory(struct cache *cache, const char *path, const char *base, int baselen)
 {
 	DIR *dir = opendir(path);
 
@@ -82,12 +82,12 @@
 				/* fallthrough */
 			case DT_DIR:
 				memcpy(fullname + baselen + len, "/", 2);
-				read_directory(fullname, fullname, baselen + len + 1);
+				read_directory(cache, fullname, fullname, baselen + len + 1);
 				continue;
 			case DT_REG:
 				break;
 			}
-			add_name(fullname, baselen + len);
+			add_name(cache, fullname, baselen + len);
 		}
 		closedir(dir);
 	}
@@ -102,13 +102,13 @@
 	return cache_name_compare(n1, l1, n2, l2);
 }
 
-static void show_files(void)
+static void show_files(struct cache *cache)
 {
 	int i;
 
 	/* For cached/deleted files we don't need to even do the readdir */
 	if (show_others | show_ignored) {
-		read_directory(".", "", 0);
+		read_directory(cache, ".", "", 0);
 		qsort(dir, nr_dir, sizeof(char *), cmp_name);
 	}
 	if (show_others) {
@@ -116,8 +116,8 @@
 			printf("%s%s%c", tag_other, dir[i], line_terminator);
 	}
 	if (show_cached | show_stage) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			if (show_unmerged && !ce_stage(ce))
 				continue;
 			if (!show_stage)
@@ -136,8 +136,8 @@
 		}
 	}
 	if (show_deleted) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			struct stat st;
 			if (!stat(ce->name, &st))
 				continue;
@@ -152,6 +152,7 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache;
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
@@ -202,7 +203,7 @@
 	if (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))
 		show_cached = 1;
 
-	read_cache();
-	show_files();
+	cache = read_cache();
+	show_files(cache);
 	return 0;
 }
Index: update-cache.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/update-cache.c  (mode:100644 sha1:a09883541c745c76413c62109a80f40df4b7a7fb)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/update-cache.c  (mode:100644 sha1:565638acd2380023ea69e82316a7ab77d95d8ee7)
@@ -85,7 +85,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(struct cache *cache, char *path)
 {
 	int size, namelen;
 	struct cache_entry *ce;
@@ -96,7 +96,7 @@
 	if (fd < 0) {
 		if (errno == ENOENT) {
 			if (allow_remove)
-				return remove_file_from_cache(path);
+				return remove_file_from_cache(cache, path);
 		}
 		return -1;
 	}
@@ -117,7 +117,7 @@
 		free(ce);
 		return -1;
 	}
-	if (add_cache_entry(ce, allow_add)) {
+	if (add_cache_entry(cache, ce, allow_add)) {
 		free(ce);
 		return -1;
 	}
@@ -179,7 +179,7 @@
 	if (stat(ce->name, &st) < 0)
 		return NULL;
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (!changed)
 		return ce;
 
@@ -200,17 +200,17 @@
 	return updated;
 }
 
-static void refresh_cache(void)
+static void refresh_cache(struct cache *cache)
 {
 	int i;
 
-	for (i = 0; i < active_nr; i++) {
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
 		struct cache_entry *ce, *new;
-		ce = active_cache[i];
+		ce = get_cache_entry(cache, i);
 		if (ce_stage(ce)) {
 			printf("%s: needs merge\n", ce->name);
-			while ((i < active_nr) &&
-			       ! strcmp(active_cache[i]->name, ce->name))
+			while ((i < get_num_cache_entries(cache)) &&
+			       ! strcmp(get_cache_entry(cache, i)->name, ce->name))
 				i++;
 			i--;
 			continue;
@@ -221,10 +221,7 @@
 			printf("%s: needs update\n", ce->name);
 			continue;
 		}
-		/* You can NOT just free active_cache[i] here, since it
-		 * might not be necessarily malloc()ed but can also come
-		 * from mmap(). */
-		active_cache[i] = new;
+		set_cache_entry(cache, new, i);
 	}
 }
 
@@ -256,7 +253,7 @@
 	}
 }
 
-static int add_cacheinfo(char *arg1, char *arg2, char *arg3)
+static int add_cacheinfo(struct cache *cache, char *arg1, char *arg2, char *arg3)
 {
 	int size, len;
 	unsigned int mode;
@@ -279,7 +276,7 @@
 	memcpy(ce->name, arg3, len);
 	ce->ce_flags = htons(len);
 	ce->ce_mode = create_ce_mode(mode);
-	return add_cache_entry(ce, allow_add);
+	return add_cache_entry(cache, ce, allow_add);
 }
 
 static int remove_lock = 0;
@@ -294,6 +291,7 @@
 {
 	int i, newfd, entries;
 	int allow_options = 1;
+	struct cache *cache = NULL;
 
 	newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
 	if (newfd < 0)
@@ -302,7 +300,8 @@
 	atexit(remove_lock_file);
 	remove_lock = 1;
 
-	entries = read_cache();
+	cache = read_cache();
+	entries = get_num_cache_entries(cache);
 	if (entries < 0)
 		die("cache corrupted");
 
@@ -323,11 +322,11 @@
 				continue;
 			}
 			if (!strcmp(path, "--refresh")) {
-				refresh_cache();
+				refresh_cache(cache);
 				continue;
 			}
 			if (!strcmp(path, "--cacheinfo")) {
-				if (i+3 >= argc || add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))
+				if (i+3 >= argc || add_cacheinfo(cache, argv[i+1], argv[i+2], argv[i+3]))
 					die("update-cache: --cacheinfo <mode> <sha1> <path>");
 				i += 3;
 				continue;
@@ -338,10 +337,10 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(cache, path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) ||
+	if (write_cache(cache, newfd) ||
 	    rename(".git/index.lock", ".git/index"))
 		die("Unable to write new cachefile");
 
Index: write-tree.c
===================================================================
--- c0260bfb82da04aeff4e598ced5295d6ae2e262d/write-tree.c  (mode:100644 sha1:827809dbddbff6dd8cf842641f6db5ad2f3ae07a)
+++ 38adb888a4c1adfe083f24d4ec51018e0b5a8335/write-tree.c  (mode:100644 sha1:ad148b422ffa85d7ecf515e55538c1afa13f17d6)
@@ -29,7 +29,7 @@
 
 #define ORIG_OFFSET (40)	/* Enough space to add the header of "tree <size>\0" */
 
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache *cache, int start_pos, const char *base, int baselen, unsigned char *returnsha1)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
@@ -43,7 +43,7 @@
 
 	nr = 0;
 	do {
-		struct cache_entry *ce = cachep[nr];
+		struct cache_entry *ce = get_cache_entry(cache, start_pos + nr);
 		const char *pathname = ce->name, *filename, *dirname;
 		int pathlen = ce_namelen(ce), entrylen;
 		unsigned char *sha1;
@@ -53,16 +53,13 @@
 		if (baselen >= pathlen || memcmp(base, pathname, baselen))
 			break;
 
-		sha1 = ce->sha1;
-		mode = ntohl(ce->ce_mode);
-
 		/* Do we have _further_ subdirectories? */
 		filename = pathname + baselen;
 		dirname = strchr(filename, '/');
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cache, start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -72,6 +69,9 @@
 			/* ..but the directory entry doesn't count towards the total count */
 			nr--;
 			sha1 = subdir_sha1;
+		} else {
+			sha1 = ce->sha1;
+			mode = ntohl(ce->ce_mode);
 		}
 
 		if (check_valid_sha1(sha1) < 0)
@@ -87,7 +87,7 @@
 		memcpy(buffer + offset, sha1, 20);
 		offset += 20;
 		nr++;
-	} while (nr < maxentries);
+	} while ((start_pos + nr) < get_num_cache_entries(cache));
 
 	i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
 	i -= 5;
@@ -101,16 +101,18 @@
 int main(int argc, char **argv)
 {
 	int i, unmerged;
-	int entries = read_cache();
 	unsigned char sha1[20];
+	struct cache *cache = read_cache();
+	int entries;
 
-	if (entries <= 0)
+	if (!cache)
 		die("write-tree: no cache contents to write");
+	entries = get_num_cache_entries(cache);
 
 	/* Verify that the tree is merged */
 	unmerged = 0;
 	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
 			if (++unmerged > 10) {
 				fprintf(stderr, "...\n");
@@ -123,7 +125,7 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(cache, 0, "", 0, sha1) != entries)
 		die("write-tree: internal error");
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;

^ permalink raw reply	[relevance 15%]

* [PATCH] optimized SHA1 for powerpc
@ 2005-04-22  5:52 20% Paul Mackerras
  0 siblings, 0 replies; 200+ results
From: Paul Mackerras @ 2005-04-22  5:52 UTC (permalink / raw)
  To: torvalds; +Cc: git, anton

Linus,

Just for fun, I wrote a ppc-assembly SHA1 routine.  It appears to be
about 2.5x faster than the generic version.  It reduces the time for a
fsck-cache on a linux-2.6 tree from ~6.8 seconds to ~6.0 seconds on my
G4 powerbook.

Paul.

diff -urN git.orig/Makefile git/Makefile
--- git.orig/Makefile	2005-04-22 15:21:10.000000000 +1000
+++ git/Makefile	2005-04-22 15:11:28.000000000 +1000
@@ -25,7 +25,12 @@
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o
 LIB_FILE=libgit.a
-LIB_H=cache.h object.h
+LIB_H=cache.h object.h sha1.h
+
+arch := $(shell uname -m | tr -d 0-9)
+ifeq ($(arch),ppc)
+LIB_OBJS += sha1.o sha1ppc.o
+endif
 
 $(LIB_FILE): $(LIB_OBJS)
 	$(AR) rcs $@ $(LIB_OBJS)
diff -urN git.orig/cache.h git/cache.h
--- git.orig/cache.h	2005-04-22 15:21:10.000000000 +1000
+++ git/cache.h	2005-04-22 13:57:36.000000000 +1000
@@ -12,7 +12,7 @@
 #include <sys/mman.h>
 #include <netinet/in.h>
 
-#include <openssl/sha.h>
+#include "sha1.h"
 #include <zlib.h>
 
 /*
diff -urN git.orig/sha1.c git/sha1.c
--- /dev/null	2005-04-04 12:56:19.000000000 +1000
+++ git/sha1.c	2005-04-22 15:17:27.000000000 +1000
@@ -0,0 +1,72 @@
+/*
+ * SHA-1 implementation.
+ *
+ * Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
+ *
+ * This version assumes we are running on a big-endian machine.
+ * It calls an external sha1_core() to process blocks of 64 bytes.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "sha1.h"
+
+extern void sha1_core(uint32_t *hash, const unsigned char *p,
+		      unsigned int nblocks);
+
+int SHA1_Init(SHA_CTX *c)
+{
+	c->hash[0] = 0x67452301;
+	c->hash[1] = 0xEFCDAB89;
+	c->hash[2] = 0x98BADCFE;
+	c->hash[3] = 0x10325476;
+	c->hash[4] = 0xC3D2E1F0;
+	c->len = 0;
+	c->cnt = 0;
+	return 0;
+}
+
+int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n)
+{
+	unsigned long nb;
+	const unsigned char *p = ptr;
+
+	c->len += n << 3;
+	while (n != 0) {
+		if (c->cnt || n < 64) {
+			nb = 64 - c->cnt;
+			if (nb > n)
+				nb = n;
+			memcpy(&c->buf.b[c->cnt], p, nb);
+			if ((c->cnt += nb) == 64) {
+				sha1_core(c->hash, c->buf.b, 1);
+				c->cnt = 0;
+			}
+		} else {
+			nb = n >> 6;
+			sha1_core(c->hash, p, nb);
+			nb <<= 6;
+		}
+		n -= nb;
+		p += nb;
+	}
+	return 0;
+}	
+
+int SHA1_Final(unsigned char *hash, SHA_CTX *c)
+{
+	unsigned int cnt = c->cnt;
+
+	c->buf.b[cnt++] = 0x80;
+	if (cnt > 56) {
+		if (cnt < 64)
+			memset(&c->buf.b[cnt], 0, 64 - cnt);
+		sha1_core(c->hash, c->buf.b, 1);
+		cnt = 0;
+	}
+	if (cnt < 56)
+		memset(&c->buf.b[cnt], 0, 56 - cnt);
+	c->buf.l[7] = c->len;
+	sha1_core(c->hash, c->buf.b, 1);
+	memcpy(hash, c->hash, 20);
+	return 0;
+}
diff -urN git.orig/sha1.h git/sha1.h
--- /dev/null	2005-04-04 12:56:19.000000000 +1000
+++ git/sha1.h	2005-04-22 15:06:53.000000000 +1000
@@ -0,0 +1,19 @@
+#ifndef __powerpc__
+#include <openssl/sha.h>
+#else
+#include <stdint.h>
+
+typedef struct sha_context {
+	uint32_t hash[5];
+	uint32_t cnt;
+	uint64_t len;
+	union {
+		unsigned char b[64];
+		uint64_t l[8];
+	} buf;
+} SHA_CTX;
+
+int SHA1_Init(SHA_CTX *c);
+int SHA1_Update(SHA_CTX *c, const void *p, unsigned long n);
+int SHA1_Final(unsigned char *hash, SHA_CTX *c);
+#endif
diff -urN git.orig/sha1ppc.S git/sha1ppc.S
--- /dev/null	2005-04-04 12:56:19.000000000 +1000
+++ git/sha1ppc.S	2005-04-22 15:18:19.000000000 +1000
@@ -0,0 +1,185 @@
+/*
+ * SHA-1 implementation for PowerPC.
+ *
+ * Copyright (C) 2005 Paul Mackerras.
+ */
+#define FS	80
+
+/*
+ * We roll the registers for T, A, B, C, D, E around on each
+ * iteration; T on iteration t is A on iteration t+1, and so on.
+ * We use registers 7 - 12 for this.
+ */
+#define RT(t)	((((t)+5)%6)+7)
+#define RA(t)	((((t)+4)%6)+7)
+#define RB(t)	((((t)+3)%6)+7)
+#define RC(t)	((((t)+2)%6)+7)
+#define RD(t)	((((t)+1)%6)+7)
+#define RE(t)	((((t)+0)%6)+7)
+
+/* We use registers 16 - 31 for the W values */
+#define W(t)	(((t)%16)+16)
+
+#define STEPD0(t)				\
+	and	%r6,RB(t),RC(t);		\
+	andc	%r0,RD(t),RB(t);		\
+	rotlwi	RT(t),RA(t),5;			\
+	rotlwi	RB(t),RB(t),30;			\
+	or	%r6,%r6,%r0;			\
+	add	%r0,RE(t),%r15;			\
+	add	RT(t),RT(t),%r6;		\
+	add	%r0,%r0,W(t);			\
+	add	RT(t),RT(t),%r0
+
+#define STEPD1(t)				\
+	xor	%r6,RB(t),RC(t);		\
+	rotlwi	RT(t),RA(t),5;			\
+	rotlwi	RB(t),RB(t),30;			\
+	xor	%r6,%r6,RD(t);			\
+	add	%r0,RE(t),%r15;			\
+	add	RT(t),RT(t),%r6;		\
+	add	%r0,%r0,W(t);			\
+	add	RT(t),RT(t),%r0
+
+#define STEPD2(t)				\
+	and	%r6,RB(t),RC(t);		\
+	and	%r0,RB(t),RD(t);		\
+	rotlwi	RT(t),RA(t),5;			\
+	rotlwi	RB(t),RB(t),30;			\
+	or	%r6,%r6,%r0;			\
+	and	%r0,RC(t),RD(t);		\
+	or	%r6,%r6,%r0;			\
+	add	%r0,RE(t),%r15;			\
+	add	RT(t),RT(t),%r6;		\
+	add	%r0,%r0,W(t);			\
+	add	RT(t),RT(t),%r0
+
+#define LOADW(t)				\
+	lwz	W(t),(t)*4(%r4)
+
+#define UPDATEW(t)				\
+	xor	%r0,W((t)-3),W((t)-8);		\
+	xor	W(t),W((t)-16),W((t)-14);	\
+	xor	W(t),W(t),%r0;			\
+	rotlwi	W(t),W(t),1
+
+#define STEP0LD4(t)				\
+	STEPD0(t);   LOADW((t)+4);		\
+	STEPD0((t)+1); LOADW((t)+5);		\
+	STEPD0((t)+2); LOADW((t)+6);		\
+	STEPD0((t)+3); LOADW((t)+7)
+
+#define STEPUP4(t, fn)				\
+	STEP##fn(t);   UPDATEW((t)+4);		\
+	STEP##fn((t)+1); UPDATEW((t)+5);	\
+	STEP##fn((t)+2); UPDATEW((t)+6);	\
+	STEP##fn((t)+3); UPDATEW((t)+7)
+
+#define STEPUP20(t, fn)				\
+	STEPUP4(t, fn);				\
+	STEPUP4((t)+4, fn);			\
+	STEPUP4((t)+8, fn);			\
+	STEPUP4((t)+12, fn);			\
+	STEPUP4((t)+16, fn)
+
+	.globl	sha1_core
+sha1_core:
+	stwu	%r1,-FS(%r1)
+	stw	%r15,FS-68(%r1)
+	stw	%r16,FS-64(%r1)
+	stw	%r17,FS-60(%r1)
+	stw	%r18,FS-56(%r1)
+	stw	%r19,FS-52(%r1)
+	stw	%r20,FS-48(%r1)
+	stw	%r21,FS-44(%r1)
+	stw	%r22,FS-40(%r1)
+	stw	%r23,FS-36(%r1)
+	stw	%r24,FS-32(%r1)
+	stw	%r25,FS-28(%r1)
+	stw	%r26,FS-24(%r1)
+	stw	%r27,FS-20(%r1)
+	stw	%r28,FS-16(%r1)
+	stw	%r29,FS-12(%r1)
+	stw	%r30,FS-8(%r1)
+	stw	%r31,FS-4(%r1)
+
+	/* Load up A - E */
+	lwz	RA(0),0(%r3)	/* A */
+	lwz	RB(0),4(%r3)	/* B */
+	lwz	RC(0),8(%r3)	/* C */
+	lwz	RD(0),12(%r3)	/* D */
+	lwz	RE(0),16(%r3)	/* E */
+
+	mtctr	%r5
+
+1:	LOADW(0)
+	LOADW(1)
+	LOADW(2)
+	LOADW(3)
+
+	lis	%r15,0x5a82	/* K0-19 */
+	ori	%r15,%r15,0x7999
+	STEP0LD4(0)
+	STEP0LD4(4)
+	STEP0LD4(8)
+	STEPUP4(12, D0)
+	STEPUP4(16, D0)
+
+	lis	%r15,0x6ed9	/* K20-39 */
+	ori	%r15,%r15,0xeba1
+	STEPUP20(20, D1)
+
+	lis	%r15,0x8f1b	/* K40-59 */
+	ori	%r15,%r15,0xbcdc
+	STEPUP20(40, D2)
+
+	lis	%r15,0xca62	/* K60-79 */
+	ori	%r15,%r15,0xc1d6
+	STEPUP4(60, D1)
+	STEPUP4(64, D1)
+	STEPUP4(68, D1)
+	STEPUP4(72, D1)
+	STEPD1(76)
+	STEPD1(77)
+	STEPD1(78)
+	STEPD1(79)
+
+	lwz	%r20,16(%r3)
+	lwz	%r19,12(%r3)
+	lwz	%r18,8(%r3)
+	lwz	%r17,4(%r3)
+	lwz	%r16,0(%r3)
+	add	%r20,RE(80),%r20
+	add	RD(0),RD(80),%r19
+	add	RC(0),RC(80),%r18
+	add	RB(0),RB(80),%r17
+	add	RA(0),RA(80),%r16
+	mr	RE(0),%r20
+	stw	RA(0),0(%r3)
+	stw	RB(0),4(%r3)
+	stw	RC(0),8(%r3)
+	stw	RD(0),12(%r3)
+	stw	RE(0),16(%r3)
+
+	addi	%r4,%r4,64
+	bdnz	1b
+
+	lwz	%r15,FS-68(%r1)
+	lwz	%r16,FS-64(%r1)
+	lwz	%r17,FS-60(%r1)
+	lwz	%r18,FS-56(%r1)
+	lwz	%r19,FS-52(%r1)
+	lwz	%r20,FS-48(%r1)
+	lwz	%r21,FS-44(%r1)
+	lwz	%r22,FS-40(%r1)
+	lwz	%r23,FS-36(%r1)
+	lwz	%r24,FS-32(%r1)
+	lwz	%r25,FS-28(%r1)
+	lwz	%r26,FS-24(%r1)
+	lwz	%r27,FS-20(%r1)
+	lwz	%r28,FS-16(%r1)
+	lwz	%r29,FS-12(%r1)
+	lwz	%r30,FS-8(%r1)
+	lwz	%r31,FS-4(%r1)
+	addi	%r1,%r1,FS
+	blr

^ permalink raw reply	[relevance 20%]

* [PATCH] Add -i option to cat-file to allow operation on displaced git object files
@ 2005-04-23 18:27 13% Jon Seymour
  2005-04-23 18:48 17% ` [resend] " Jon Seymour
  0 siblings, 1 reply; 200+ results
From: Jon Seymour @ 2005-04-23 18:27 UTC (permalink / raw)
  To: Git Mailing List

For the purposes of merging the contents of remote git object
repositories at the filesystem level, it would be helpful to be able
to verify the integrity of a remote git object file before it is
actually copied into the local repository.

To enable this, the option syntax for the usage of the cat-file tool
is extended with a -i option, per the modified usage string quoted
below:

    usage: cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]

If the -i option is specified, cat-file uses the filename specified on
the command line rather than the derived filename to locate and
process the git object file implied by the sha1 argument.

In addition, the -i option forces cat-file to check the SHA1 signature
of the specified input file against the SHA1 signature specified on
the command line and report an error if there is a mismatch.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
--
Index: cache.h
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cache.h  (mode:100644
sha1:bf30ac4741d2eeeb483079f566182505898082f3)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cache.h  (mode:100644
sha1:56eacfa0ab43c93a838efedca429e865c95f16bc)
@@ -121,8 +121,9 @@
  extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
  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 void * read_displaced_sha1_file(char *type, unsigned long
*size, const char *filename);
  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);
+extern int check_sha1_signature(const 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);
Index: cat-file.c
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cat-file.c  (mode:100644
sha1:3c47d79a16305d326a65768fe9f37ee25928510b)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cat-file.c  (mode:100644
sha1:c88df7287b6ce7d6d33d016ffb524cc5a793cad2)
@@ -5,16 +5,32 @@
  */
 #include "cache.h"
 
+static char _usage[]="cat-file [-t | tagname] <sha1> [ -i
displaced-git-object-file ]";
+
  int main(int argc, char **argv)
 {
  	unsigned char sha1[20];
 	char type[20];
-	void *buf;
+	void *buf = NULL;
 	unsigned long size;
 
-	if (argc != 3 || get_sha1_hex(argv[2], sha1))
-		usage("cat-file [-t | tagname] <sha1>");
-	buf = read_sha1_file(sha1, type, &size);
+	if (argc < 3 || get_sha1_hex(argv[2], sha1))
+		usage(_usage);
+
+        if (argc == 3) {
+	    buf = read_sha1_file(sha1, type, &size);
+        } else if (argc == 5 && !strcmp(argv[3], "-i")) {
+            buf = read_displaced_sha1_file(type, &size, argv[4]);
+            if (!buf) 
+                    die("bad file: %s", argv[4]);
+	    
+            if (check_sha1_signature(sha1, buf, size, type) < 0)
+                    die("signature mismatch for %s", argv[4]);
+
+        } else {
+	    usage(_usage);
+        }
+
  	if (!buf)
  		die("cat-file %s: bad file", argv[2]);
  	if (!strcmp("-t", argv[1])) {
Index: sha1_file.c
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/sha1_file.c  (mode:100644
sha1:6f7228e106d4e24b18f8416cc6adc2a6fd303eb7)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/sha1_file.c  (mode:100644
sha1:25e2e8b22cf9590a6df05f234ce88db8c2cd1030)
@@ -80,7 +80,7 @@
 	return base;
 }
 
-int check_sha1_signature(unsigned char *sha1, void *map, unsigned
long size, const char *type)
+int check_sha1_signature(const unsigned char *sha1, void *map,
unsigned long size, const char *type)
 {
 	char header[100];
 	unsigned char real_sha1[20];
@@ -93,13 +93,12 @@
  	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
 }
 
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_file(const char *filename, unsigned long *size)
 {
-	char *filename = sha1_file_name(sha1);
-	int fd = open(filename, O_RDONLY);
 	struct stat st;
 	void *map;
 
+	int fd = open(filename, O_RDONLY);
 	if (fd < 0) {
 		perror(filename);
 		return NULL;
@@ -116,6 +115,12 @@
 	return map;
 }
 
+void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+{
+        char *filename = sha1_file_name(sha1);
+        return map_file(filename, size);
+}
+
  void * unpack_sha1_file(void *map, unsigned long mapsize, char
*type, unsigned long *size)
 {
 	int ret, bytes;
@@ -166,6 +171,20 @@
 	return NULL;
 }
 
+void * read_displaced_sha1_file(char *type, unsigned long *size,
const char *filename)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map = map_file(filename, &mapsize);
+	if (map) {
+		buf = unpack_sha1_file(map, mapsize, type, size);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
  void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
 					 unsigned long *size,
 					 unsigned char *tree_sha1_return)

^ permalink raw reply	[relevance 13%]

* [resend] [PATCH] Add -i option to cat-file to allow operation on displaced git object files
  2005-04-23 18:27 13% Jon Seymour
@ 2005-04-23 18:48 17% ` Jon Seymour
  0 siblings, 0 replies; 200+ results
From: Jon Seymour @ 2005-04-23 18:48 UTC (permalink / raw)
  To: Git Mailing List

[-- Attachment #1: Type: text/plain, Size: 1215 bytes --]

[PATCH] Add -i option to cat-file to allow operation on displaced git
object files

For the purposes of merging the contents of remote git object
repositories at the filesystem level, it would  be helpful to be able
to verify the integrity of a remote git object file before it is
actually copied into the local repository.

To enable this, the option syntax for the usage of the cat-file tool
is extended with a -i option, per the modified usage string quoted
below:

    usage: cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]

If the -i option is specified, cat-file uses the filename specified on
the command line rather than the derived filename to locate and
process the git object file implied by the sha1 argument.

In addition, the -i option forces cat-file to check the SHA1 signature
of the specified input file against the SHA1 signature specified on
the command line and report an error if there is a mismatch.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
Sorry, I noticed after the fact that gmail had line-wrapped my patch,
so I am resending the patch as a text attachment. If it is not
acceptable to post patches in this form please let me know.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 5261 bytes --]

[PATCH] Add -i option to cat-file to allow operation on displaced git object files

For the purposes of merging the contents of remote git object repositories at the filesystem level, it would
be helpful to be able to verify the integrity of a remote git object file before it is actually
copied into the local repository.

To enable this, the option syntax for the usage of the cat-file tool is extended with a -i option, per the
modified usage string quoted below:

    usage: cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]

If the -i option is specified, cat-file uses the filename specified on the command line rather than the derived
filename to locate and process the git object file implied by the sha1 argument.

In addition, the -i option forces cat-file to check the SHA1 signature of the specified input file against
the SHA1 signature specified on the command line and report an error if there is a mismatch.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
--
Index: cache.h
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cache.h  (mode:100644 sha1:bf30ac4741d2eeeb483079f566182505898082f3)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cache.h  (mode:100644 sha1:56eacfa0ab43c93a838efedca429e865c95f16bc)
@@ -121,8 +121,9 @@
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 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 void * read_displaced_sha1_file(char *type, unsigned long *size, const char *filename);
 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);
+extern int check_sha1_signature(const 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);
Index: cat-file.c
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cat-file.c  (mode:100644 sha1:3c47d79a16305d326a65768fe9f37ee25928510b)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cat-file.c  (mode:100644 sha1:c88df7287b6ce7d6d33d016ffb524cc5a793cad2)
@@ -5,16 +5,32 @@
  */
 #include "cache.h"
 
+static char _usage[]="cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]";
+
 int main(int argc, char **argv)
 {
 	unsigned char sha1[20];
 	char type[20];
-	void *buf;
+	void *buf = NULL;
 	unsigned long size;
 
-	if (argc != 3 || get_sha1_hex(argv[2], sha1))
-		usage("cat-file [-t | tagname] <sha1>");
-	buf = read_sha1_file(sha1, type, &size);
+	if (argc < 3 || get_sha1_hex(argv[2], sha1))
+		usage(_usage);
+
+        if (argc == 3) {
+	    buf = read_sha1_file(sha1, type, &size);
+        } else if (argc == 5 && !strcmp(argv[3], "-i")) {
+            buf = read_displaced_sha1_file(type, &size, argv[4]);
+            if (!buf) 
+                    die("bad file: %s", argv[4]);
+	    
+            if (check_sha1_signature(sha1, buf, size, type) < 0)
+                    die("signature mismatch for %s", argv[4]);
+
+        } else {
+	    usage(_usage);
+        }
+
 	if (!buf)
 		die("cat-file %s: bad file", argv[2]);
 	if (!strcmp("-t", argv[1])) {
Index: sha1_file.c
===================================================================
--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/sha1_file.c  (mode:100644 sha1:6f7228e106d4e24b18f8416cc6adc2a6fd303eb7)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/sha1_file.c  (mode:100644 sha1:25e2e8b22cf9590a6df05f234ce88db8c2cd1030)
@@ -80,7 +80,7 @@
 	return base;
 }
 
-int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
+int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
 	char header[100];
 	unsigned char real_sha1[20];
@@ -93,13 +93,12 @@
 	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
 }
 
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_file(const char *filename, unsigned long *size)
 {
-	char *filename = sha1_file_name(sha1);
-	int fd = open(filename, O_RDONLY);
 	struct stat st;
 	void *map;
 
+	int fd = open(filename, O_RDONLY);
 	if (fd < 0) {
 		perror(filename);
 		return NULL;
@@ -116,6 +115,12 @@
 	return map;
 }
 
+void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+{
+        char *filename = sha1_file_name(sha1);
+        return map_file(filename, size);
+}
+
 void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
 {
 	int ret, bytes;
@@ -166,6 +171,20 @@
 	return NULL;
 }
 
+void * read_displaced_sha1_file(char *type, unsigned long *size, const char *filename)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map = map_file(filename, &mapsize);
+	if (map) {
+		buf = unpack_sha1_file(map, mapsize, type, size);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
 void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
 					 unsigned long *size,
 					 unsigned char *tree_sha1_return)

^ permalink raw reply	[relevance 17%]

* [resend#2] [PATCH] Add -i option to cat-file to allow operation on displaced git object files
@ 2005-04-23 18:27 13% Jon Seymour
  0 siblings, 0 replies; 200+ results
From: Jon Seymour @ 2005-04-23 18:27 UTC (permalink / raw)
  To: Git Mailing List; +Cc: torvalds, jon.seymour

[PATCH] Add -i option to cat-file to allow operation on displaced git object files

For the purposes of merging the contents of remote git object repositories at the filesystem level, it would
be helpful to be able to verify the integrity of a remote git object file before it is actually
copied into the local repository.

To enable this, the option syntax for the usage of the cat-file tool is extended with a -i option, per the
modified usage string quoted below:

    usage: cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]

If the -i option is specified, cat-file uses the filename specified on the command line rather than the derived
filename to locate and process the git object file implied by the sha1 argument.

In addition, the -i option forces cat-file to check the SHA1 signature of the specified input file against
the SHA1 signature specified on the command line and report an error if there is a mismatch.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>

Apologies for the repeated attempts to mail this patch. I'll use qmail in future!

---
Index: cache.h
=================================--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cache.h  (mode:100644 sha1:bf30ac4741d2eeeb483079f566182505898082f3)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cache.h  (mode:100644 sha1:56eacfa0ab43c93a838efedca429e865c95f16bc)
@@ -121,8 +121,9 @@
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 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 void * read_displaced_sha1_file(char *type, unsigned long *size, const char *filename);
 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);
+extern int check_sha1_signature(const 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);
Index: cat-file.c
=================================--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/cat-file.c  (mode:100644 sha1:3c47d79a16305d326a65768fe9f37ee25928510b)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/cat-file.c  (mode:100644 sha1:c88df7287b6ce7d6d33d016ffb524cc5a793cad2)
@@ -5,16 +5,32 @@
  */
 #include "cache.h"
 
+static char _usage[]"cat-file [-t | tagname] <sha1> [ -i displaced-git-object-file ]";
+
 int main(int argc, char **argv)
 {
 	unsigned char sha1[20];
 	char type[20];
-	void *buf;
+	void *buf NULL;
 	unsigned long size;
 
-	if (argc ! || get_sha1_hex(argv[2], sha1))
-		usage("cat-file [-t | tagname] <sha1>");
-	buf read_sha1_file(sha1, type, &size);
+	if (argc < 3 || get_sha1_hex(argv[2], sha1))
+		usage(_usage);
+
+        if (argc = 3) {
+	    buf read_sha1_file(sha1, type, &size);
+        } else if (argc = 5 && !strcmp(argv[3], "-i")) {
+            buf read_displaced_sha1_file(type, &size, argv[4]);
+            if (!buf) 
+                    die("bad file: %s", argv[4]);
+	    
+            if (check_sha1_signature(sha1, buf, size, type) < 0)
+                    die("signature mismatch for %s", argv[4]);
+
+        } else {
+	    usage(_usage);
+        }
+
 	if (!buf)
 		die("cat-file %s: bad file", argv[2]);
 	if (!strcmp("-t", argv[1])) {
Index: sha1_file.c
=================================--- e6d3a81c30ad237102e2ca82f3dfc57d0b9f0ddf/sha1_file.c  (mode:100644 sha1:6f7228e106d4e24b18f8416cc6adc2a6fd303eb7)
+++ 1b503f0571727a865b413e28641d2be09c8c3304/sha1_file.c  (mode:100644 sha1:25e2e8b22cf9590a6df05f234ce88db8c2cd1030)
@@ -80,7 +80,7 @@
 	return base;
 }
 
-int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
+int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
 	char header[100];
 	unsigned char real_sha1[20];
@@ -93,13 +93,12 @@
 	return memcmp(sha1, real_sha1, 20) ? -1 : 0;
 }
 
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_file(const char *filename, unsigned long *size)
 {
-	char *filename sha1_file_name(sha1);
-	int fd open(filename, O_RDONLY);
 	struct stat st;
 	void *map;
 
+	int fd open(filename, O_RDONLY);
 	if (fd < 0) {
 		perror(filename);
 		return NULL;
@@ -116,6 +115,12 @@
 	return map;
 }
 
+void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+{
+        char *filename sha1_file_name(sha1);
+        return map_file(filename, size);
+}
+
 void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
 {
 	int ret, bytes;
@@ -166,6 +171,20 @@
 	return NULL;
 }
 
+void * read_displaced_sha1_file(char *type, unsigned long *size, const char *filename)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map map_file(filename, &mapsize);
+	if (map) {
+		buf unpack_sha1_file(map, mapsize, type, size);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
 void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
 					 unsigned long *size,
 					 unsigned char *tree_sha1_return)

^ permalink raw reply	[relevance 13%]

* [PATCH 3/5] Additional functions for the objects database
  @ 2005-04-24  0:15 21% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
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	[relevance 21%]

* Re: [PATCH] multi item packed files
  @ 2005-04-25 22:20 16%     ` Chris Mason
  0 siblings, 0 replies; 200+ results
From: Chris Mason @ 2005-04-25 22:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Krzysztof Halasa, git

[-- Attachment #1: Type: text/plain, Size: 2897 bytes --]

On Friday 22 April 2005 19:55, Chris Mason wrote:
> On Friday 22 April 2005 16:32, Chris Mason wrote:
> > If I pack every 64k (uncompressed), the checkout-tree time goes down to
> > 3m14s. That's a very big difference considering how stupid my code is 
> > .git was only 20% smaller with 64k chunks.  I should be able to do
> > better...I'll do one more run.
>
> This run also packed tree files together (everything produced by write-tree
> went into a packed file), but not the commits.  I estimate I could save
> about another 168m by packing the tree files and commits into the same file
> with the blobs, but this wouldn't make any of the times below faster.
>
> git - original (28k commits)	                packed
> FS size                2,675,408k		1,723,820k
> read-tree            24.45s			18.9s
> checkout-cache   4m30s			3m5s
> patch time	   2h30m				1h55m
>

It was a rainy weekend, so I took a break from lawn care and hacked in some 
simple changes to the packed file format.  There's now a header listing the 
sha1 for each subfile and the offset where to find it in the main file.  Each 
subfile is compressed individually so you don't have to decompress the whole 
packed file to find one.  commits were added into the packed files as well.

Some results were about what I expected:

FS size              -- 1,614,376k
read-tree          -- 18s
checkout-cache -- 2m35s (cold cache)
checkout-cache -- 18s      (hot cache)
patch time        -- 96m

vanilla git needs 56s to checkout with a hot cache.  The hot cache numbers 
weren't done before because I hadn't expected my patch to help at all.  Even 
though we both do things entirely from cache, vanilla git is much slower at 
writing the checked out files back to the drive.  I've made no optimizations 
to that code, and the drive is only 30% full, so this seems to just be a bad 
interaction with filesystem layout.

I also expected vanilla git to perform pretty well when there were no commits 
in the tree.  My test was to put a copy of 2.6.11 under git.
                                              vanilla                   packed
update-cache (for all files)      2m1s                     48s
checkout-cache (cold)            1m23s                    28s
checkout-cache (hot)             12s                         15s

The difference in hot cache checkout time is userland cpu time.  It could be 
avoided with smarter caching of the packed file header.  Right now I'm 
decompressing it over and over again for each checkout.  Still, the 
performance hit is pretty small because I try to limit the number of subfiles 
that get packed together.

My current patch is attached for reference, it's against a git from late last 
week.  I wouldn't suggest using this for anything other than benchmarking, 
and since I don't think I can get much better numbers easily, I'll stop 
playing around with this for a while.

-chris

[-- Attachment #2: comp-tree-4.diff --]
[-- Type: text/x-diff, Size: 26388 bytes --]

diff -ur linus.back/cache.h linus/cache.h
--- linus.back/cache.h	2005-04-25 17:30:21.616654304 -0400
+++ linus/cache.h	2005-04-25 10:56:15.000000000 -0400
@@ -64,6 +64,16 @@
 	char name[0];
 };
 
+struct packed_item {
+	/* lenght of compressed data */
+	unsigned long len;
+	struct packed_item *next;
+	/* sha1 of uncompressed data */
+	char sha1[20];
+	/* compressed data */
+	char *data;
+};
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
@@ -117,7 +127,7 @@
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
+extern void * unpack_sha1_file(const unsigned char *sha1, 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);
@@ -125,6 +135,9 @@
 /* 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! */
+extern int pack_sha1_buffer(void *buf, unsigned long buf_len, 
+                            unsigned char *returnsha1, struct packed_item **);
+int write_packed_buffer(struct packed_item *head);
 
 /* General helper functions */
 extern void usage(const char *err);
@@ -137,4 +150,9 @@
 						unsigned long *size,
 						unsigned char *tree_sha1_ret);
 
+extern int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1, struct packed_item **head);
+
+#define MAXPARENT 16
+extern int commit_tree(char *tree_sha1_hex, unsigned char parent_sha1[MAXPARENT][20], int num_parents, struct packed_item **head);
+extern void check_valid_sha1_file(unsigned char *sha1, const char *expect);
 #endif /* CACHE_H */
diff -ur linus.back/commit-tree.c linus/commit-tree.c
--- linus.back/commit-tree.c	2005-04-25 17:30:21.626652784 -0400
+++ linus/commit-tree.c	2005-04-25 10:58:15.000000000 -0400
@@ -4,360 +4,32 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include "cache.h"
-
-#include <pwd.h>
-#include <time.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#define BLOCKING (1ul << 14)
-#define ORIG_OFFSET (40)
-
-/*
- * Leave space at the beginning to insert the tag
- * once we know how big things are.
- *
- * FIXME! Share the code with "write-tree.c"
- */
-static void init_buffer(char **bufp, unsigned int *sizep)
-{
-	char *buf = malloc(BLOCKING);
-	memset(buf, 0, ORIG_OFFSET);
-	*sizep = ORIG_OFFSET;
-	*bufp = buf;
-}
-
-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
-{
-	char one_line[2048];
-	va_list args;
-	int len;
-	unsigned long alloc, size, newsize;
-	char *buf;
-
-	va_start(args, fmt);
-	len = vsnprintf(one_line, sizeof(one_line), fmt, args);
-	va_end(args);
-	size = *sizep;
-	newsize = size + len;
-	alloc = (size + 32767) & ~32767;
-	buf = *bufp;
-	if (newsize > alloc) {
-		alloc = (newsize + 32767) & ~32767;
-		buf = realloc(buf, alloc);
-		*bufp = buf;
-	}
-	*sizep = newsize;
-	memcpy(buf + size, one_line, len);
-}
-
-static int prepend_integer(char *buffer, unsigned val, int i)
-{
-	buffer[--i] = '\0';
-	do {
-		buffer[--i] = '0' + (val % 10);
-		val /= 10;
-	} while (val);
-	return i;
-}
-
-static void finish_buffer(char *tag, char **bufp, unsigned int *sizep)
-{
-	int taglen;
-	int offset;
-	char *buf = *bufp;
-	unsigned int size = *sizep;
-
-	offset = prepend_integer(buf, size - ORIG_OFFSET, ORIG_OFFSET);
-	taglen = strlen(tag);
-	offset -= taglen;
-	buf += offset;
-	size -= offset;
-	memcpy(buf, tag, taglen);
-
-	*bufp = buf;
-	*sizep = size;
-}
-
-static void remove_special(char *p)
-{
-	char c;
-	char *dst = p, *src = p;
-
-	for (;;) {
-		c = *src;
-		src++;
-		switch(c) {
-		case '\n': case '<': case '>':
-			continue;
-		}
-		*dst++ = c;
-		if (!c)
-			break;
-	}
-
-	/*
-	 * Go back, and remove crud from the end: some people
-	 * have commas etc in their gecos field
-	 */
-	dst--;
-	while (--dst >= p) {
-		unsigned char c = *dst;
-		switch (c) {
-		case ',': case ';': case '.':
-			*dst = 0;
-			continue;
-		}
-		break;
-	}
-}
-
-static const char *month_names[] = {
-        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-static const char *weekday_names[] = {
-        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-
-static char *skipfws(char *str)
-{
-	while (isspace(*str))
-		str++;
-	return str;
-}
-
-	
-/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
-   (i.e. English) day/month names, and it doesn't work correctly with %z. */
-static void parse_rfc2822_date(char *date, char *result, int maxlen)
-{
-	struct tm tm;
-	char *p;
-	int i, offset;
-	time_t then;
-
-	memset(&tm, 0, sizeof(tm));
-
-	/* Skip day-name */
-	p = skipfws(date);
-	if (!isdigit(*p)) {
-		for (i=0; i<7; i++) {
-			if (!strncmp(p,weekday_names[i],3) && p[3] == ',') {
-				p = skipfws(p+4);
-				goto day;
-			}
-		}
-		return;
-	}					
-
-	/* day */
- day:
-	tm.tm_mday = strtoul(p, &p, 10);
-
-	if (tm.tm_mday < 1 || tm.tm_mday > 31)
-		return;
-
-	if (!isspace(*p))
-		return;
-
-	p = skipfws(p);
-
-	/* month */
-
-	for (i=0; i<12; i++) {
-		if (!strncmp(p, month_names[i], 3) && isspace(p[3])) {
-			tm.tm_mon = i;
-			p = skipfws(p+strlen(month_names[i]));
-			goto year;
-		}
-	}
-	return; /* Error -- bad month */
-
-	/* year */
- year:	
-	tm.tm_year = strtoul(p, &p, 10);
-
-	if (!tm.tm_year && !isspace(*p))
-		return;
-
-	if (tm.tm_year > 1900)
-		tm.tm_year -= 1900;
-		
-	p=skipfws(p);
-
-	/* hour */
-	if (!isdigit(*p))
-		return;
-	tm.tm_hour = strtoul(p, &p, 10);
-	
-	if (!tm.tm_hour > 23)
-		return;
-
-	if (*p != ':')
-		return; /* Error -- bad time */
-	p++;
-
-	/* minute */
-	if (!isdigit(*p))
-		return;
-	tm.tm_min = strtoul(p, &p, 10);
-	
-	if (!tm.tm_min > 59)
-		return;
-
-	if (isspace(*p))
-		goto zone;
-
-	if (*p != ':')
-		return; /* Error -- bad time */
-	p++;
-
-	/* second */
-	if (!isdigit(*p))
-		return;
-	tm.tm_sec = strtoul(p, &p, 10);
-	
-	if (!tm.tm_sec > 59)
-		return;
-
-	if (!isspace(*p))
-		return;
-
- zone:
-	p = skipfws(p);
-
-	if (*p == '-')
-		offset = -60;
-	else if (*p == '+')
-		offset = 60;
-	else
-	       return;
-
-	if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
-		return;
-
-	i = strtoul(p+1, NULL, 10);
-	offset *= ((i % 100) + ((i / 100) * 60));
-
-	if (*(skipfws(p + 5)))
-		return;
-
-	then = mktime(&tm); /* mktime appears to ignore the GMT offset, stupidly */
-	if (then == -1)
-		return;
-
-	then -= offset;
-
-	snprintf(result, maxlen, "%lu %5.5s", then, p);
-}
-
-static void check_valid(unsigned char *sha1, const char *expect)
-{
-	void *buf;
-	char type[20];
-	unsigned long size;
-
-	buf = read_sha1_file(sha1, type, &size);
-	if (!buf || strcmp(type, expect))
-		die("%s is not a valid '%s' object", sha1_to_hex(sha1), expect);
-	free(buf);
-}
-
 /*
  * Having more than two parents is not strange at all, and this is
  * how multi-way merges are represented.
  */
-#define MAXPARENT (16)
 
 static char *commit_tree_usage = "commit-tree <sha1> [-p <sha1>]* < changelog";
 
 int main(int argc, char **argv)
 {
-	int i, len;
+	int i;
 	int parents = 0;
 	unsigned char tree_sha1[20];
 	unsigned char parent_sha1[MAXPARENT][20];
-	unsigned char commit_sha1[20];
-	char *gecos, *realgecos, *commitgecos;
-	char *email, *commitemail, realemail[1000];
-	char date[20], realdate[20];
-	char *audate;
-	char comment[1000];
-	struct passwd *pw;
-	time_t now;
-	struct tm *tm;
-	char *buffer;
-	unsigned int size;
 
 	if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
 		usage(commit_tree_usage);
 
-	check_valid(tree_sha1, "tree");
+	check_valid_sha1_file(tree_sha1, "tree");
 	for (i = 2; i < argc; i += 2) {
 		char *a, *b;
 		a = argv[i]; b = argv[i+1];
 		if (!b || strcmp(a, "-p") || get_sha1_hex(b, parent_sha1[parents]))
 			usage(commit_tree_usage);
-		check_valid(parent_sha1[parents], "commit");
+		check_valid_sha1_file(parent_sha1[parents], "commit");
 		parents++;
 	}
-	if (!parents)
-		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
-	pw = getpwuid(getuid());
-	if (!pw)
-		die("You don't exist. Go away!");
-	realgecos = pw->pw_gecos;
-	len = strlen(pw->pw_name);
-	memcpy(realemail, pw->pw_name, len);
-	realemail[len] = '@';
-	gethostname(realemail+len+1, sizeof(realemail)-len-1);
-	if (!strchr(realemail+len+1, '.')) {
-		strcat(realemail, ".");
-		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
-	}
-	time(&now);
-	tm = localtime(&now);
-
-	strftime(realdate, sizeof(realdate), "%s %z", tm);
-	strcpy(date, realdate);
-
-	commitgecos = getenv("COMMIT_AUTHOR_NAME") ? : realgecos;
-	commitemail = getenv("COMMIT_AUTHOR_EMAIL") ? : realemail;
-	gecos = getenv("AUTHOR_NAME") ? : realgecos;
-	email = getenv("AUTHOR_EMAIL") ? : realemail;
-	audate = getenv("AUTHOR_DATE");
-	if (audate)
-		parse_rfc2822_date(audate, date, sizeof(date));
-
-	remove_special(gecos); remove_special(realgecos); remove_special(commitgecos);
-	remove_special(email); remove_special(realemail); remove_special(commitemail);
-
-	init_buffer(&buffer, &size);
-	add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
-
-	/*
-	 * NOTE! This ordering means that the same exact tree merged with a
-	 * different order of parents will be a _different_ changeset even
-	 * if everything else stays the same.
-	 */
-	for (i = 0; i < parents; i++)
-		add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
-
-	/* Person/date information */
-	add_buffer(&buffer, &size, "author %s <%s> %s\n", gecos, email, date);
-	add_buffer(&buffer, &size, "committer %s <%s> %s\n\n", commitgecos, commitemail, realdate);
-
-	/* And add the comment */
-	while (fgets(comment, sizeof(comment), stdin) != NULL)
-		add_buffer(&buffer, &size, "%s", comment);
-
-	finish_buffer("commit ", &buffer, &size);
-
-	write_sha1_file(buffer, size, commit_sha1);
-	printf("%s\n", sha1_to_hex(commit_sha1));
+	commit_tree(tree_sha1, parent_sha1, parents, NULL);
 	return 0;
 }
diff -ur linus.back/fsck-cache.c linus/fsck-cache.c
--- linus.back/fsck-cache.c	2005-04-25 17:30:21.630652176 -0400
+++ linus/fsck-cache.c	2005-04-22 10:25:07.000000000 -0400
@@ -85,7 +85,7 @@
 		if (map) {
 			char type[100];
 			unsigned long size;
-			void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+			void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size);
 			if (!buffer)
 				return -1;
 			if (check_sha1_signature(sha1, buffer, size, type) < 0)
diff -ur linus.back/Makefile linus/Makefile
--- linus.back/Makefile	2005-04-25 17:30:21.631652024 -0400
+++ linus/Makefile	2005-04-25 10:03:53.000000000 -0400
@@ -23,7 +23,7 @@
 install: $(PROG)
 	install $(PROG) $(HOME)/bin/
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o lib-tree.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h
 
@@ -71,6 +71,7 @@
 show-diff.o: $(LIB_H)
 show-files.o: $(LIB_H)
 tree.o: $(LIB_H)
+lib-tree.o: $(LIB_H)
 update-cache.o: $(LIB_H)
 usage.o: $(LIB_H)
 unpack-file.o: $(LIB_H)
diff -ur linus.back/sha1_file.c linus/sha1_file.c
--- linus.back/sha1_file.c	2005-04-25 17:30:21.633651720 -0400
+++ linus/sha1_file.c	2005-04-25 17:15:53.050696400 -0400
@@ -116,12 +116,14 @@
 	return map;
 }
 
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+void * unpack_sha1_file(const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size)
 {
 	int ret, bytes;
 	z_stream stream;
 	char buffer[8192];
 	char *buf;
+	unsigned long offset;
 
 	/* Get the data stream */
 	memset(&stream, 0, sizeof(stream));
@@ -134,12 +136,12 @@
 	ret = inflate(&stream, 0);
 	if (sscanf(buffer, "%10s %lu", type, size) != 2)
 		return NULL;
-
 	bytes = strlen(buffer) + 1;
 	buf = malloc(*size);
-	if (!buf)
+	if (!buf) {
+		perror("malloc");
 		return NULL;
-
+	}
 	memcpy(buf, buffer + bytes, stream.total_out - bytes);
 	bytes = stream.total_out - bytes;
 	if (bytes < *size && ret == Z_OK) {
@@ -149,6 +151,56 @@
 			/* nothing */;
 	}
 	inflateEnd(&stream);
+
+	/* we've found a packed object */
+	if (strcmp(type, "packed") == 0) {
+		char *p = buf;
+		unsigned long header_len = *size;
+		offset = stream.total_in;
+		if (!sha1)
+			return NULL;
+		while(p < buf + header_len) {
+			unsigned long item_len;
+			unsigned char sha1_hex[50];
+			unsigned char item_sha[20];
+			memcpy(item_sha, p, 20);
+			sscanf(p + 20, "%lu ", &item_len);
+			p += 20 + strlen(p + 20) + 1;
+			if (memcmp(item_sha, sha1, 20) == 0) {
+				/* Get the data stream */
+				free(buf);
+				memset(&stream, 0, sizeof(stream));
+				stream.next_in = map + offset;
+				stream.avail_in = mapsize - offset;
+				stream.next_out = buffer;
+				stream.avail_out = sizeof(buffer);
+
+				inflateInit(&stream);
+				ret = inflate(&stream, 0);
+				if (sscanf(buffer, "%10s %lu", type, size) != 2)
+					return NULL;
+				bytes = strlen(buffer) + 1;
+				buf = malloc(*size);
+				if (!buf) {
+					perror("malloc");
+					return NULL;
+				}
+				memcpy(buf, buffer + bytes, 
+					stream.total_out - bytes);
+				bytes = stream.total_out - bytes;
+				if (bytes < *size && ret == Z_OK) {
+					stream.next_out = buf + bytes;
+					stream.avail_out = *size - bytes;
+					while (inflate(&stream, Z_FINISH) == Z_OK)
+						/* nothing */;
+				}
+				inflateEnd(&stream);
+				return buf;
+			}
+			offset += item_len;
+		}
+		return NULL;
+	}
 	return buf;
 }
 
@@ -159,7 +211,7 @@
 
 	map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size);
 		munmap(map, mapsize);
 		return buf;
 	}
@@ -305,3 +357,166 @@
 	close(fd);
 	return 0;
 }
+
+int pack_sha1_buffer(void *buf, unsigned long buf_len, 
+		     unsigned char *returnsha1,
+		     struct packed_item **packed_item)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	struct stat st;
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+	struct packed_item *item;
+
+	*packed_item = NULL;
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, buf, buf_len);
+	SHA1_Final(sha1, &c);
+
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+
+	filename = sha1_file_name(sha1);
+	if (stat(filename, &st) == 0)
+		return 0;
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	deflateInit(&stream, Z_BEST_COMPRESSION);
+	size = deflateBound(&stream, buf_len);
+	compressed = malloc(size);
+
+	/*
+	 * ASCII size + nul byte
+	 */	
+	stream.next_in = buf;
+	stream.avail_in = buf_len;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	/* Compress it */
+	while (deflate(&stream, Z_FINISH) == Z_OK)
+		/* nothing */;
+	deflateEnd(&stream);
+	size = stream.total_out;
+
+	item = malloc(sizeof(struct packed_item));
+	if (!item) {
+		free(compressed);
+		return -1;
+	}
+	memcpy(item->sha1, sha1, 20);
+	item->len = size;
+	item->next = NULL;
+	item->data = compressed;
+	*packed_item = item;
+	return 0;
+}
+
+static char *create_packed_header(struct packed_item *head, unsigned long *size)
+{
+	char *metadata = NULL;
+	int metadata_size = 0;
+	*size = 0;
+
+	while(head) {
+		char *p;
+		metadata = realloc(metadata, metadata_size + 220);
+		if (!metadata)
+			return NULL;
+		p = metadata+metadata_size;
+		memcpy(p, head->sha1, 20);
+		p += 20;
+		metadata_size += 1 + sprintf(p, "%lu ", head->len) + 20;
+		head = head->next;
+	}
+	*size = metadata_size;
+	return metadata;
+}
+
+int write_packed_buffer(struct packed_item *head)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	char *metadata = malloc(200);
+	char *header;
+	int metadata_size;
+	int fd;
+	int ret = 0;
+	unsigned long header_len;
+	struct packed_item *item;
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+	int nr = 0;
+
+	header = create_packed_header(head, &header_len);
+	metadata_size = 1+sprintf(metadata, "packed %lu", header_len);
+
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, header, header_len);
+	item = head;
+	while(item) {
+		SHA1_Update(&c, item->data, item->len);
+		item = item->next;
+		nr++;
+	}
+	SHA1_Final(sha1, &c);
+
+	filename = strdup(sha1_file_name(sha1));
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		/* add collision check! */
+		if (errno != EEXIST) {
+			ret = -errno;
+		}
+		goto out;
+	}
+       /* compress just the header info */
+        memset(&stream, 0, sizeof(stream));
+        deflateInit(&stream, Z_BEST_COMPRESSION);
+        size = deflateBound(&stream, header_len + metadata_size);
+        compressed = malloc(size);
+
+        stream.next_in = metadata;
+        stream.avail_in = metadata_size;
+        stream.next_out = compressed;
+        stream.avail_out = size;
+        while (deflate(&stream, 0) == Z_OK)
+                /* nothing */;
+        stream.next_in = header;
+        stream.avail_in = header_len;
+        while (deflate(&stream, Z_FINISH) == Z_OK)
+                /* nothing */;
+        deflateEnd(&stream);
+        size = stream.total_out;
+
+	write(fd, compressed, size);
+	free(compressed);
+
+	item = head;
+	while(item) {
+		char *item_file;
+		struct packed_item *next = item->next;
+		write(fd, item->data, item->len);
+		item_file = sha1_file_name(item->sha1);
+		if (link(filename, item_file) && errno != EEXIST) {
+			ret = -errno;
+			break;
+		}
+		free(item->data);
+		free(item);
+		item = next;
+	}
+out:
+	free(header);
+	free(metadata);
+	free(filename);
+	return ret;
+}
diff -ur linus.back/update-cache.c linus/update-cache.c
--- linus.back/update-cache.c	2005-04-25 17:30:21.635651416 -0400
+++ linus/update-cache.c	2005-04-25 14:24:14.000000000 -0400
@@ -12,57 +12,48 @@
  * like "update-cache *" and suddenly having all the object
  * files be revision controlled.
  */
-static int allow_add = 0, allow_remove = 0;
+static int allow_add = 0, allow_remove = 0, commit = 0;
 
-static int index_fd(unsigned char *sha1, int fd, struct stat *st)
+static int index_fd(unsigned char *sha1, int fd, struct stat *st, struct packed_item **head, struct packed_item **tail, unsigned long *packed_size)
 {
-	z_stream stream;
 	unsigned long size = st->st_size;
-	int max_out_bytes = size + 200;
-	void *out = malloc(max_out_bytes);
 	void *metadata = malloc(200);
 	int metadata_size;
 	void *in;
-	SHA_CTX c;
+	char *copy;
+	int ret;
+	struct packed_item *new_item;
 
 	in = "";
 	if (size)
 		in = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (!out || (int)(long)in == -1)
+	if (!metadata || (int)(long)in == -1)
 		return -1;
-
 	metadata_size = 1+sprintf(metadata, "blob %lu", size);
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, metadata, metadata_size);
-	SHA1_Update(&c, in, size);
-	SHA1_Final(sha1, &c);
-
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
-
-	/*
-	 * ASCII size + nul byte
-	 */	
-	stream.next_in = metadata;
-	stream.avail_in = metadata_size;
-	stream.next_out = out;
-	stream.avail_out = max_out_bytes;
-	while (deflate(&stream, 0) == Z_OK)
-		/* nothing */;
-
-	/*
-	 * File content
-	 */
-	stream.next_in = in;
-	stream.avail_in = size;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/*nothing */;
-
-	deflateEnd(&stream);
-	
-	return write_sha1_buffer(sha1, out, stream.total_out);
+	copy = malloc(metadata_size + size);
+	if (!copy)
+		return -1;
+	memcpy(copy, metadata, metadata_size);
+	memcpy(copy + metadata_size, in, size);
+	ret = pack_sha1_buffer(copy, metadata_size + size, sha1, &new_item);
+	if (new_item) {
+		if (*tail)
+			(*tail)->next = new_item;
+		*tail = new_item;
+		if (!*head)
+			*head = new_item;
+		*packed_size += new_item->len;
+		if (*packed_size > (512 * 1024)) {
+			write_packed_buffer(*head);
+			*head = NULL;
+			*tail = NULL;
+			*packed_size = 0;
+		}
+	}
+	munmap(in, size);
+	free(copy);
+	return ret;
 }
 
 /*
@@ -85,7 +76,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(char *path, struct packed_item **packed_head, struct packed_item **packed_tail, unsigned long *packed_size)
 {
 	int size, namelen;
 	struct cache_entry *ce;
@@ -113,7 +104,8 @@
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
 
-	if (index_fd(ce->sha1, fd, &st) < 0)
+	if (index_fd(ce->sha1, fd, &st, packed_head, 
+		     packed_tail, packed_size) < 0)
 		return -1;
 
 	return add_cache_entry(ce, allow_add);
@@ -282,12 +274,30 @@
 		unlink(lockfile_name);
 }
 
+static int path_comp(const void *p1, const void *p2)
+{
+	const char *s1 = *(char **)p1;
+	const char *s2 = *(char **)p2;
+	int len1 = strlen(s1);
+	int len2 = strlen(s2);
+	int ret;
+	ret = cache_name_compare(s1, len1, s2, len2);
+	return ret;
+}
+
 int main(int argc, char **argv)
 {
 	int i, newfd, entries;
 	int allow_options = 1;
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct packed_item *packed_head = NULL;
+	struct packed_item *packed_tail = NULL;
+	unsigned long packed_size = 0;
+	char **paths = malloc(argc * sizeof(char *));
+	int num_paths = 0;
+	unsigned char parent_sha1[20];
+	int parents = 0;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -318,6 +328,17 @@
 				allow_remove = 1;
 				continue;
 			}
+			if (!strcmp(path, "--commit")) {
+				commit = 1;
+				continue;
+			}
+			if (!strcmp(path, "--parent")) {
+				if (i+1 >= argc || get_sha1_hex(argv[i+1], parent_sha1))
+					die("update-cache: --parent sha1");
+				parents = 1;
+				i+=1;
+				continue;
+			}
 			if (!strcmp(path, "--refresh")) {
 				refresh_cache();
 				continue;
@@ -334,8 +355,27 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
-			die("Unable to add %s to database", path);
+		paths[num_paths++] = path;
+
+	}
+	// qsort(paths, num_paths, sizeof(char *), path_comp);
+	for(i = 0 ; i < num_paths ; i++) {
+		if (add_file_to_cache(paths[i], &packed_head, &packed_tail, &packed_size))
+			die("Unable to add %s to database", paths[i]);
+
+	}
+	if (commit) {
+		char tree_sha1[20];
+		if (write_tree(active_cache, active_nr, "", 0, tree_sha1, &packed_head) != active_nr)
+			die("write-tree failed");
+fprintf(stderr, "write_tree gave us %s\n", sha1_to_hex(tree_sha1));
+
+		if (commit_tree(tree_sha1, &parent_sha1, parents, &packed_head))
+			die("commit-tree failed");
+	}
+	if (packed_head) {
+		if (write_packed_buffer(packed_head))
+			die("write packed buffer failed");
 	}
 	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
 		die("Unable to write new cachefile");
diff -ur linus.back/write-tree.c linus/write-tree.c
--- linus.back/write-tree.c	2005-04-25 17:30:21.635651416 -0400
+++ linus/write-tree.c	2005-04-25 10:01:30.000000000 -0400
@@ -3,106 +3,15 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
-
-static int check_valid_sha1(unsigned char *sha1)
-{
-	char *filename = sha1_file_name(sha1);
-	int ret;
-
-	/* If we were anal, we'd check that the sha1 of the contents actually matches */
-	ret = access(filename, R_OK);
-	if (ret)
-		perror(filename);
-	return ret;
-}
-
-static int prepend_integer(char *buffer, unsigned val, int i)
-{
-	buffer[--i] = '\0';
-	do {
-		buffer[--i] = '0' + (val % 10);
-		val /= 10;
-	} while (val);
-	return i;
-}
-
-#define ORIG_OFFSET (40)	/* Enough space to add the header of "tree <size>\0" */
-
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
-{
-	unsigned char subdir_sha1[20];
-	unsigned long size, offset;
-	char *buffer;
-	int i, nr;
-
-	/* Guess at some random initial size */
-	size = 8192;
-	buffer = malloc(size);
-	offset = ORIG_OFFSET;
-
-	nr = 0;
-	do {
-		struct cache_entry *ce = cachep[nr];
-		const char *pathname = ce->name, *filename, *dirname;
-		int pathlen = ce_namelen(ce), entrylen;
-		unsigned char *sha1;
-		unsigned int mode;
-
-		/* Did we hit the end of the directory? Return how many we wrote */
-		if (baselen >= pathlen || memcmp(base, pathname, baselen))
-			break;
 
-		sha1 = ce->sha1;
-		mode = ntohl(ce->ce_mode);
-
-		/* Do we have _further_ subdirectories? */
-		filename = pathname + baselen;
-		dirname = strchr(filename, '/');
-		if (dirname) {
-			int subdir_written;
-
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
-			nr += subdir_written;
-
-			/* Now we need to write out the directory entry into this tree.. */
-			mode = S_IFDIR;
-			pathlen = dirname - pathname;
-
-			/* ..but the directory entry doesn't count towards the total count */
-			nr--;
-			sha1 = subdir_sha1;
-		}
-
-		if (check_valid_sha1(sha1) < 0)
-			exit(1);
-
-		entrylen = pathlen - baselen;
-		if (offset + entrylen + 100 > size) {
-			size = alloc_nr(offset + entrylen + 100);
-			buffer = realloc(buffer, size);
-		}
-		offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
-		buffer[offset++] = 0;
-		memcpy(buffer + offset, sha1, 20);
-		offset += 20;
-		nr++;
-	} while (nr < maxentries);
-
-	i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET);
-	i -= 5;
-	memcpy(buffer+i, "tree ", 5);
-
-	write_sha1_file(buffer + i, offset - i, returnsha1);
-	free(buffer);
-	return nr;
-}
+#include "cache.h"
 
 int main(int argc, char **argv)
 {
 	int i, unmerged;
 	int entries = read_cache();
 	unsigned char sha1[20];
+	struct packed_item *head = NULL;
 
 	if (entries <= 0)
 		die("write-tree: no cache contents to write");
@@ -123,8 +32,12 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(active_cache, entries, "", 0, sha1, &head) != entries)
 		die("write-tree: internal error");
+	if (head) {
+		if (write_packed_buffer(head))
+			die("write_packed_buffer failed");
+	}
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;
 }

^ permalink raw reply	[relevance 16%]

* Re: [PATCH] introduce xmalloc and xrealloc
  @ 2005-04-26 15:42 23%   ` Christopher Li
  0 siblings, 0 replies; 200+ results
From: Christopher Li @ 2005-04-26 15:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git mailing list

On Tue, Apr 26, 2005 at 11:25:58AM -0700, Linus Torvalds wrote:
> 
> I'd prefer xmalloc()/xrealloc() instead, and just do it in one place.

Done.

Chris

Introduce xmalloc and xrealloc
 
Signed-off-by: Christopher Li<chrislgit@chrisli.org>
Index: git-hack/blob.c
===================================================================
--- git-hack.orig/blob.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/blob.c	2005-04-26 11:38:26.000000000 -0400
@@ -8,7 +8,7 @@
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
-		struct blob *ret = malloc(sizeof(struct blob));
+		struct blob *ret = xmalloc(sizeof(struct blob));
 		memset(ret, 0, sizeof(struct blob));
 		created_object(sha1, &ret->object);
 		ret->object.type = blob_type;
Index: git-hack/checkout-cache.c
===================================================================
--- git-hack.orig/checkout-cache.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/checkout-cache.c	2005-04-26 11:38:26.000000000 -0400
@@ -39,7 +39,7 @@
 static void create_directories(const char *path)
 {
 	int len = strlen(path);
-	char *buf = malloc(len + 1);
+	char *buf = xmalloc(len + 1);
 	const char *slash = path;
 
 	while ((slash = strchr(slash+1, '/')) != NULL) {
Index: git-hack/commit-tree.c
===================================================================
--- git-hack.orig/commit-tree.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/commit-tree.c	2005-04-26 11:38:26.000000000 -0400
@@ -18,7 +18,7 @@
  */
 static void init_buffer(char **bufp, unsigned int *sizep)
 {
-	char *buf = malloc(BLOCKING);
+	char *buf = xmalloc(BLOCKING);
 	*sizep = 0;
 	*bufp = buf;
 }
@@ -40,7 +40,7 @@
 	buf = *bufp;
 	if (newsize > alloc) {
 		alloc = (newsize + 32767) & ~32767;
-		buf = realloc(buf, alloc);
+		buf = xrealloc(buf, alloc);
 		*bufp = buf;
 	}
 	*sizep = newsize;
Index: git-hack/commit.c
===================================================================
--- git-hack.orig/commit.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/commit.c	2005-04-26 11:38:26.000000000 -0400
@@ -9,7 +9,7 @@
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
-		struct commit *ret = malloc(sizeof(struct commit));
+		struct commit *ret = xmalloc(sizeof(struct commit));
 		memset(ret, 0, sizeof(struct commit));
 		created_object(sha1, &ret->object);
 		ret->object.type = commit_type;
@@ -78,7 +78,7 @@
 
 void commit_list_insert(struct commit *item, struct commit_list **list_p)
 {
-	struct commit_list *new_list = malloc(sizeof(struct commit_list));
+	struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
 	new_list->item = item;
 	new_list->next = *list_p;
 	*list_p = new_list;
Index: git-hack/convert-cache.c
===================================================================
--- git-hack.orig/convert-cache.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/convert-cache.c	2005-04-26 11:38:26.000000000 -0400
@@ -18,8 +18,7 @@
 
 static struct entry *insert_new(unsigned char *sha1, int pos)
 {
-	struct entry *new = malloc(sizeof(struct entry));
-
+	struct entry *new = xmalloc(sizeof(struct entry));
 	memset(new, 0, sizeof(*new));
 	memcpy(new->old_sha1, sha1, 20);
 	memmove(convert + pos + 1, convert + pos, (nr_convert - pos) * sizeof(struct entry *));
@@ -68,7 +67,7 @@
 
 static int write_subdirectory(void *buffer, unsigned long size, const char *base, int baselen, unsigned char *result_sha1)
 {
-	char *new = malloc(size);
+	char *new = xmalloc(size);
 	unsigned long newlen = 0;
 	unsigned long used;
 
@@ -226,9 +225,9 @@
 
 static void convert_date(void *buffer, unsigned long size, unsigned char *result_sha1)
 {
-	char *new = malloc(size + 100);
+	char *new = xmalloc(size + 100);
 	unsigned long newlen = 0;
-
+	
 	// "tree <sha1>\n"
 	memcpy(new + newlen, buffer, 46);
 	newlen += 46;
@@ -283,7 +282,7 @@
 	if (!data)
 		die("unable to read object %s", sha1_to_hex(sha1));
 
-	buffer = malloc(size);
+	buffer = xmalloc(size);
 	memcpy(buffer, data, size);
 	
 	if (!strcmp(type, "blob")) {
Index: git-hack/diff-tree.c
===================================================================
--- git-hack.orig/diff-tree.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/diff-tree.c	2005-04-26 11:38:26.000000000 -0400
@@ -37,7 +37,7 @@
 static char *malloc_base(const char *base, const char *path, int pathlen)
 {
 	int baselen = strlen(base);
-	char *newbase = malloc(baselen + pathlen + 2);
+	char *newbase = xmalloc(baselen + pathlen + 2);
 	memcpy(newbase, base, baselen);
 	memcpy(newbase + baselen, path, pathlen);
 	memcpy(newbase + baselen + pathlen, "/", 2);
@@ -270,7 +270,7 @@
 
 		paths = &argv[3];
 		nr_paths = argc - 3;
-		pathlens = malloc(nr_paths * sizeof(int));
+		pathlens = xmalloc(nr_paths * sizeof(int));
 		for (i=0; i<nr_paths; i++)
 			pathlens[i] = strlen(paths[i]);
 	}
Index: git-hack/http-pull.c
===================================================================
--- git-hack.orig/http-pull.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/http-pull.c	2005-04-26 11:38:26.000000000 -0400
@@ -73,7 +73,7 @@
 	curl_easy_setopt(curl, CURLOPT_FILE, NULL);
 	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
 
-	url = malloc(strlen(base) + 50);
+	url = xmalloc(strlen(base) + 50);
 	strcpy(url, base);
 	posn = url + strlen(base);
 	strcpy(posn, "objects/");
Index: git-hack/init-db.c
===================================================================
--- git-hack.orig/init-db.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/init-db.c	2005-04-26 11:38:26.000000000 -0400
@@ -34,7 +34,7 @@
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
 	len = strlen(sha1_dir);
-	path = malloc(len + 40);
+	path = xmalloc(len + 40);
 	memcpy(path, sha1_dir, len);
 
 	safe_create_dir(sha1_dir);
Index: git-hack/object.c
===================================================================
--- git-hack.orig/object.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/object.c	2005-04-26 11:38:26.000000000 -0400
@@ -52,7 +52,7 @@
 
 	if (obj_allocs == nr_objs) {
 		obj_allocs = alloc_nr(obj_allocs);
-		objs = realloc(objs, obj_allocs * sizeof(struct object *));
+		objs = xrealloc(objs, obj_allocs * sizeof(struct object *));
 	}
 
 	/* Insert it into the right place */
@@ -75,7 +75,7 @@
 	}
 
 	target->used = 1;
-	p = malloc(sizeof(*p));
+	p = xmalloc(sizeof(*p));
 	p->item = target;
 	p->next = NULL;
 	*pp = p;
Index: git-hack/read-cache.c
===================================================================
--- git-hack.orig/read-cache.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/read-cache.c	2005-04-26 11:38:26.000000000 -0400
@@ -143,7 +143,7 @@
 	/* Make sure the array is big enough .. */
 	if (active_nr == active_alloc) {
 		active_alloc = alloc_nr(active_alloc);
-		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+		active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *));
 	}
 
 	/* Add it in.. */
Index: git-hack/sha1_file.c
===================================================================
--- git-hack.orig/sha1_file.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/sha1_file.c	2005-04-26 11:38:26.000000000 -0400
@@ -73,7 +73,7 @@
 	if (!base) {
 		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
 		int len = strlen(sha1_file_directory);
-		base = malloc(len + 60);
+		base = xmalloc(len + 60);
 		memcpy(base, sha1_file_directory, len);
 		memset(base+len, 0, 60);
 		base[len] = '/';
@@ -161,9 +161,7 @@
 		return NULL;
 
 	bytes = strlen(buffer) + 1;
-	buf = malloc(*size);
-	if (!buf)
-		return NULL;
+	buf = xmalloc(*size);
 
 	memcpy(buf, buffer + bytes, stream.total_out - bytes);
 	bytes = stream.total_out - bytes;
@@ -271,7 +269,7 @@
 	memset(&stream, 0, sizeof(stream));
 	deflateInit(&stream, Z_BEST_COMPRESSION);
 	size = deflateBound(&stream, len+hdrlen);
-	compressed = malloc(size);
+	compressed = xmalloc(size);
 
 	/* Compress it */
 	stream.next_out = compressed;
Index: git-hack/show-files.c
===================================================================
--- git-hack.orig/show-files.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/show-files.c	2005-04-26 11:38:26.000000000 -0400
@@ -30,9 +30,9 @@
 
 	if (nr_dir == dir_alloc) {
 		dir_alloc = alloc_nr(dir_alloc);
-		dir = realloc(dir, dir_alloc*sizeof(char *));
+		dir = xrealloc(dir, dir_alloc*sizeof(char *));
 	}
-	name = malloc(len + 1);
+	name = xmalloc(len + 1);
 	memcpy(name, pathname, len + 1);
 	dir[nr_dir++] = name;
 }
Index: git-hack/tree.c
===================================================================
--- git-hack.orig/tree.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/tree.c	2005-04-26 11:38:26.000000000 -0400
@@ -9,7 +9,7 @@
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
-	struct cache_entry *ce = malloc(size);
+	struct cache_entry *ce = xmalloc(size);
 
 	memset(ce, 0, size);
 
@@ -39,7 +39,7 @@
 		if (S_ISDIR(mode)) {
 			int retval;
 			int pathlen = strlen(path);
-			char *newbase = malloc(baselen + 1 + pathlen);
+			char *newbase = xmalloc(baselen + 1 + pathlen);
 			void *eltbuf;
 			char elttype[20];
 			unsigned long eltsize;
@@ -74,7 +74,7 @@
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
-		struct tree *ret = malloc(sizeof(struct tree));
+		struct tree *ret = xmalloc(sizeof(struct tree));
 		memset(ret, 0, sizeof(struct tree));
 		created_object(sha1, &ret->object);
 		ret->object.type = tree_type;
@@ -116,7 +116,7 @@
 		    sscanf(bufptr, "%o", &mode) != 1)
 			return -1;
 
-		entry = malloc(sizeof(struct tree_entry_list));
+		entry = xmalloc(sizeof(struct tree_entry_list));
 		entry->name = strdup(path + 1);
 		entry->directory = S_ISDIR(mode);
 		entry->executable = mode & S_IXUSR;
Index: git-hack/update-cache.c
===================================================================
--- git-hack.orig/update-cache.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/update-cache.c	2005-04-26 11:38:26.000000000 -0400
@@ -35,8 +35,8 @@
 	z_stream stream;
 	unsigned long size = st->st_size;
 	int max_out_bytes = size + 200;
-	void *out = malloc(max_out_bytes);
-	void *metadata = malloc(200);
+	void *out = xmalloc(max_out_bytes);
+	void *metadata = xmalloc(200);
 	int metadata_size;
 	void *in;
 	SHA_CTX c;
@@ -122,7 +122,7 @@
 	}
 	namelen = strlen(path);
 	size = cache_entry_size(namelen);
-	ce = malloc(size);
+	ce = xmalloc(size);
 	memset(ce, 0, size);
 	memcpy(ce->name, path, namelen);
 	fill_stat_cache_info(ce, &st);
@@ -205,7 +205,7 @@
 		return ERR_PTR(-EINVAL);
 
 	size = ce_size(ce);
-	updated = malloc(size);
+	updated = xmalloc(size);
 	memcpy(updated, ce, size);
 	fill_stat_cache_info(updated, &st);
 	return updated;
@@ -281,7 +281,7 @@
 
 	len = strlen(arg3);
 	size = cache_entry_size(len);
-	ce = malloc(size);
+	ce = xmalloc(size);
 	memset(ce, 0, size);
 
 	memcpy(ce->sha1, sha1, 20);
Index: git-hack/write-tree.c
===================================================================
--- git-hack.orig/write-tree.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/write-tree.c	2005-04-26 11:38:26.000000000 -0400
@@ -26,7 +26,7 @@
 
 	/* Guess at some random initial size */
 	size = 8192;
-	buffer = malloc(size);
+	buffer = xmalloc(size);
 	offset = 0;
 
 	nr = 0;
@@ -68,7 +68,7 @@
 		entrylen = pathlen - baselen;
 		if (offset + entrylen + 100 > size) {
 			size = alloc_nr(offset + entrylen + 100);
-			buffer = realloc(buffer, size);
+			buffer = xrealloc(buffer, size);
 		}
 		offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
 		buffer[offset++] = 0;
Index: git-hack/revision.h
===================================================================
--- git-hack.orig/revision.h	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/revision.h	2005-04-26 11:38:26.000000000 -0400
@@ -68,10 +68,9 @@
 
 	if (rev_allocs == nr_revs) {
 		rev_allocs = alloc_nr(rev_allocs);
-		revs = realloc(revs, rev_allocs * sizeof(struct revision *));
+		revs = xrealloc(revs, rev_allocs * sizeof(struct revision *));
 	}
-	n = malloc(sizeof(struct revision) + strlen(tag));
-
+	n = xmalloc(sizeof(struct revision) + strlen(tag));
 	n->flags = 0;
 	memcpy(n->sha1, sha1, 20);
 	n->parent = NULL;
@@ -96,7 +95,7 @@
 		pp = &p->next;
 	}
 
-	p = malloc(sizeof(*p));
+	p = xmalloc(sizeof(*p));
 	p->parent = parent_rev;
 	p->next = NULL;
 	*pp = p;
Index: git-hack/diff.c
===================================================================
--- git-hack.orig/diff.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/diff.c	2005-04-26 11:38:26.000000000 -0400
@@ -59,8 +59,7 @@
 		if (*cp == '\'')
 			cnt += 3;
 
-	if (! (buf = malloc(cnt)))
-	    return buf;
+	buf = xmalloc(cnt);
 	bp = buf;
 	while ((c = *src++)) {
 		if (c != '\'')
@@ -100,7 +99,7 @@
 			strlen(diff_arg) +
 			strlen(name_1_sq) + strlen(name_2_sq)
 			- 5);
-	char *cmd = malloc(cmd_size);
+	char *cmd = xmalloc(cmd_size);
 	int next_at = 0;
 
 	next_at += snprintf(cmd+next_at, cmd_size-next_at,
Index: git-hack/strbuf.c
===================================================================
--- git-hack.orig/strbuf.c	2005-04-26 11:38:21.000000000 -0400
+++ git-hack/strbuf.c	2005-04-26 11:38:26.000000000 -0400
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "strbuf.h"
+#include "cache.h"
 
 void strbuf_init(struct strbuf *sb) {
 	sb->buf = 0;
@@ -15,7 +16,7 @@
 static void inline strbuf_add(struct strbuf *sb, int ch) {
 	if (sb->alloc <= sb->len) {
 		sb->alloc = sb->alloc * 3 / 2 + 16;
-		sb->buf = realloc(sb->buf, sb->alloc);
+		sb->buf = xrealloc(sb->buf, sb->alloc);
 	}
 	sb->buf[sb->len++] = ch;
 }
Index: git-hack/cache.h
===================================================================
--- git-hack.orig/cache.h	2005-04-26 11:40:43.000000000 -0400
+++ git-hack/cache.h	2005-04-26 11:40:59.000000000 -0400
@@ -147,4 +147,20 @@
 						unsigned long *size,
 						unsigned char *tree_sha1_ret);
 
+static inline void *xmalloc(int size)
+{
+	void *ret = malloc(size);
+	if (!ret)
+		die("Out of memory, malloc failed");
+	return ret;
+}
+
+static inline void *xrealloc(void *ptr, int size)
+{
+	void *ret = realloc(ptr, size);
+	if (!ret)
+		die("Out of memory, realloc failed");
+	return ret;
+}
+
 #endif /* CACHE_H */



^ permalink raw reply	[relevance 23%]

* [PATCH] Rename and extend read_tree_with_tree_or_commit_sha1
@ 2005-04-28 19:15 16% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-04-28 19:15 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This patch renames read_tree_with_tree_or_commit_sha1() to
read_object_with_reference() and extends it to automatically
dereference not just "commit" objects but "tag" objects.  With
this patch, you can say e.g.:

    ls-tree $tag
    read-tree -m $(merge-base $tag $HEAD) $tag $HEAD
    diff-cache $tag
    diff-tree $tag $HEAD

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

cache.h      |    7 +++---
diff-cache.c |    2 -
diff-tree.c  |    4 +--
git-mktag.c  |    2 -
ls-tree.c    |    2 -
read-tree.c  |    2 -
sha1_file.c  |   67 +++++++++++++++++++++++++++++++----------------------------
7 files changed, 46 insertions(+), 40 deletions(-)

# - 04/28 11:25 Show Index: line from built-in diff driver.
# + 04/28 11:59 Rename and extend read_tree_with_tree_or_commit_sha1
Index: cache.h
--- k/cache.h  (mode:100644)
+++ l/cache.h  (mode:100644)
@@ -143,9 +143,10 @@ extern int error(const char *err, ...);
 
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 
-extern void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
-						unsigned long *size,
-						unsigned char *tree_sha1_ret);
+extern void *read_object_with_reference(const unsigned char *sha1,
+					const unsigned char *required_type,
+					unsigned long *size,
+					unsigned char *sha1_ret);
 
 static inline void *xmalloc(int size)
 {
Index: diff-cache.c
--- k/diff-cache.c  (mode:100644)
+++ l/diff-cache.c  (mode:100644)
@@ -180,7 +180,7 @@ int main(int argc, char **argv)
 
 	mark_merge_entries();
 
-	tree = read_tree_with_tree_or_commit_sha1(tree_sha1, &size, 0);
+	tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
 	if (!tree)
 		die("bad tree object %s", argv[1]);
 	if (read_tree(tree, size, 1))
Index: diff-tree.c
--- k/diff-tree.c  (mode:100644)
+++ l/diff-tree.c  (mode:100644)
@@ -238,10 +238,10 @@ static int diff_tree_sha1(const unsigned
 	unsigned long size1, size2;
 	int retval;
 
-	tree1 = read_tree_with_tree_or_commit_sha1(old, &size1, 0);
+	tree1 = read_object_with_reference(old, "tree", &size1, 0);
 	if (!tree1)
 		die("unable to read source tree (%s)", sha1_to_hex(old));
-	tree2 = read_tree_with_tree_or_commit_sha1(new, &size2, 0);
+	tree2 = read_object_with_reference(new, "tree", &size2, 0);
 	if (!tree2)
 		die("unable to read destination tree (%s)", sha1_to_hex(new));
 	retval = diff_tree(tree1, size1, tree2, size2, base);
Index: git-mktag.c
--- k/git-mktag.c  (mode:100644)
+++ l/git-mktag.c  (mode:100644)
@@ -114,7 +114,7 @@ int main(int argc, char **argv)
 	// Read the signature
 	size = read(0, buffer, MAXSIZE);
 
-	// Verify it for some basic sanity: it needs to start with "object <sha1>\ntag "
+	// Verify it for some basic sanity: it needs to start with "object <sha1>\ntype "
 	if (verify_tag(buffer, size) < 0)
 		die("invalid tag signature file");
 
Index: ls-tree.c
--- k/ls-tree.c  (mode:100644)
+++ l/ls-tree.c  (mode:100644)
@@ -73,7 +73,7 @@ static int list(unsigned char *sha1)
 	void *buffer;
 	unsigned long size;
 
-	buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, 0);
+	buffer = read_object_with_reference(sha1, "tree", &size, 0);
 	if (!buffer)
 		die("unable to read sha1 file");
 	list_recursive(buffer, "tree", size, NULL);
Index: read-tree.c
--- k/read-tree.c  (mode:100644)
+++ l/read-tree.c  (mode:100644)
@@ -12,7 +12,7 @@ static int unpack_tree(unsigned char *sh
 	void *buffer;
 	unsigned long size;
 
-	buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, 0);
+	buffer = read_object_with_reference(sha1, "tree", &size, 0);
 	if (!buffer)
 		return -1;
 	return read_tree(buffer, size, stage);
Index: sha1_file.c
--- k/sha1_file.c  (mode:100644)
+++ l/sha1_file.c  (mode:100644)
@@ -189,44 +189,49 @@ void * read_sha1_file(const unsigned cha
 	return NULL;
 }
 
-void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
-					 unsigned long *size,
-					 unsigned char *tree_sha1_return)
+void *read_object_with_reference(const unsigned char *sha1,
+				 const unsigned char *required_type,
+				 unsigned long *size,
+				 unsigned char *actual_sha1_return)
 {
 	char type[20];
 	void *buffer;
 	unsigned long isize;
-	int was_commit = 0;
-	unsigned char tree_sha1[20];
+	unsigned char actual_sha1[20];
 
-	buffer = read_sha1_file(sha1, type, &isize);
-
-	/* 
-	 * We might have read a commit instead of a tree, in which case
-	 * we parse out the tree_sha1 and attempt to read from there.
-	 * (buffer + 5) is because the tree sha1 is always at offset 5
-	 * in a commit record ("tree ").
-	 */
-	if (buffer &&
-	    !strcmp(type, "commit") &&
-	    !get_sha1_hex(buffer + 5, tree_sha1)) {
-		free(buffer);
-		buffer = read_sha1_file(tree_sha1, type, &isize);
-		was_commit = 1;
-	}
+	memcpy(actual_sha1, sha1, 20);
+	while (1) {
+		int ref_length = -1;
+		const char *ref_type = NULL;
+
+		buffer = read_sha1_file(actual_sha1, type, &isize);
+		if (!buffer)
+			return NULL;
+		if (!strcmp(type, required_type)) {
+			*size = isize;
+			if (actual_sha1_return)
+				memcpy(actual_sha1_return, actual_sha1, 20);
+			return buffer;
+		}
+		/* Handle references */
+		else if (!strcmp(type, "commit"))
+			ref_type = "tree ";
+		else if (!strcmp(type, "tag"))
+			ref_type = "object ";
+		else {
+			free(buffer);
+			return NULL;
+		}
+		ref_length = strlen(ref_type);
 
-	/*
-	 * Now do we have something and if so is it a tree?
-	 */
-	if (!buffer || strcmp(type, "tree")) {
-		free(buffer);
-		return NULL;
+		if (memcmp(buffer, ref_type, ref_length) ||
+		    get_sha1_hex(buffer + ref_length, actual_sha1)) {
+			free(buffer);
+			return NULL;
+		}
+		/* Now we have the ID of the referred-to object in
+		 * actual_sha1.  Check again. */
 	}
-
-	*size = isize;
-	if (tree_sha1_return)
-		memcpy(tree_sha1_return, was_commit ? tree_sha1 : sha1, 20);
-	return buffer;
 }
 
 int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *returnsha1)


^ permalink raw reply	[relevance 16%]

* [PATCH]: first take at cleanup of #include, xmalloc / xrealloc, git status report usage.
@ 2005-04-29 13:19 12% Robert Sütterlin
  0 siblings, 0 replies; 200+ results
From: Robert Sütterlin @ 2005-04-29 13:19 UTC (permalink / raw)
  To: git

This is a rather large monolithic or rather dualithic patch that tries 
to clean up #include usage in cache.h.

IMHO including headers that include headers that include headers ... 
are we there, yet? is a BAD(tm) thing.  So I removed every #include 
from cache.h that was not necessary to define the contents of cache.h 
itself.  Then I entered only the required headers to each sourcefile.  
This will help in identifying which subsystems don't use the libgit 
infrastructure, or which functionality needs to be added to libgit.

Also I added two report functions to usage (warning and message), 
trtied to remove xmalloc and xrealloc whereever simply dying was IMHO 
wrong, added more diagnostic output and return value chacking to some 
files.

This is the beginning of a cleanup of git code.  I feel that (except 
maybe for diff / merge) git has stabilised enough to start the 
refactoring / renaming / api cleanup stuff.

I also strongly believe that we should design a new internal memory 
buffer.  The usage of malloc / realloc in git is not good at all.  
Everybody and her dog seems to know how to best handle malloc, so there 
is a lot of code repetition and bad (i.e. no) api all over the place.  
A new internal buffer concept would of course mean, that all of the 
algorithms must be rewritten, but as Linus always says: "that is just 
coding."  Some not-so-core components already use strbuf --- which I do 
not like that much really --- still I'd call this a beginning.

Feel free to neglect any of my changes.

signed-off-by: Robert Suetterlin <robert@mpe.mpg.de>

intermediate commit before cg-update continuing work to clean up 
#include, malloc / realloc and diagnostics messages.

---
commit f03e0239ea6ae31d8f89a4a7965ed90832770c5b
tree 86241f0cd550785e3cba0a235f7e423d0503be93
parent 49612c471eebd26efe926a71752e254c1cdc382d
author Robert Suetterlin <krs@robert3.mpe-garching.mpg.de> 1114763833 
+0200
committer Robert Suetterlin <krs@robert3.mpe-garching.mpg.de> 
1114763833 +0200

Index: Makefile
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/Makefile  (mode:100644 
sha1:d73bea1cbb9451a89b03d6066bf2ed7fec32fd31)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/Makefile  (mode:100644 
sha1:3c461e439a8731b688533dccbc5dafa1471a5b3b)
@@ -73,7 +73,7 @@
  	LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
  else
  	SHA1_HEADER=<openssl/sha.h>
-	LIBS += -lssl
+	LIBS += -lcrypto
  endif
  endif

Index: blob.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/blob.c  (mode:100644 
sha1:3d99b93f020d84c5410c2b1056f2d7446b647d1e)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/blob.c  (mode:100644 
sha1:037e7ebcf786efee5741398afa2144d6d168e9f3)
@@ -1,20 +1,27 @@
-#include "blob.h"
-#include "cache.h"
  #include <stdlib.h>
+#include <string.h>
+
+#include "cache.h"
+
+#include "blob.h"

  const char *blob_type = "blob";

  struct blob *lookup_blob(unsigned char *sha1)
  {
  	struct object *obj = lookup_object(sha1);
-	if (!obj) {
-		struct blob *ret = xmalloc(sizeof(struct blob));
+	if (NULL == obj) {
+		struct blob *ret = malloc(sizeof(struct blob));
+		if (NULL == ret) {
+			error("Could not malloc(sizeof(struct blob))");
+			return NULL;
+		}
  		memset(ret, 0, sizeof(struct blob));
  		created_object(sha1, &ret->object);
  		ret->object.type = blob_type;
  		return ret;
  	}
-	if (obj->parsed && obj->type != blob_type) {
+	if (obj->type != blob_type) {
  		error("Object %s is a %s, not a blob",
  		      sha1_to_hex(sha1), obj->type);
  		return NULL;
Index: cache.h
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/cache.h  (mode:100644 
sha1:1052e17da7093024d34be3c939ab768e20cfa2a3)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/cache.h  (mode:100644 
sha1:036d6b6897ef119b4de051d957b5886680bfffe3)
@@ -1,19 +1,21 @@
  #ifndef CACHE_H
  #define CACHE_H

-#include <unistd.h>
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
  #include <sys/stat.h>
+
+#include <netinet/in.h>
+
+//#include <errno.h>
  #include <fcntl.h>
+#include <stdarg.h>
  #include <stddef.h>
  #include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
+//#include <stdio.h>
+//#include <string.h>
  #include <unistd.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <netinet/in.h>

  #include SHA1_HEADER
  #include <zlib.h>
@@ -25,6 +27,7 @@
  /*
   * Basic data structures for the directory cache
   *
+ * FIX this:  The Note below is outdated.
   * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
   * not even trying to be portable. It's trying to be efficient. It's
   * just a cache, after all.
@@ -145,6 +148,8 @@
  extern void usage(const char *err);
  extern void die(const char *err, ...);
  extern int error(const char *err, ...);
+extern void warning(const char *err, ...);
+extern void message(const char *msg, ...);

  extern int cache_name_compare(const char *name1, int len1, const char 
*name2, int len2);

Index: cat-file.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/cat-file.c  (mode:100644 
sha1:3c47d79a16305d326a65768fe9f37ee25928510b)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/cat-file.c  (mode:100644 
sha1:568cfbc266416f8afa88995a90a3d17132e8db8b)
@@ -3,6 +3,9 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <errno.h>
+#include <string.h>
+
  #include "cache.h"

  int main(int argc, char **argv)
Index: check-files.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/check-files.c  
(mode:100644 sha1:7d16691aa9d51b5b4670d5837b3527ee7c7da79c)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/check-files.c  
(mode:100644 sha1:438fa7fc084b94a5fe6dd0a4200b69d1ef147b75)
@@ -6,6 +6,9 @@
   *
   * Copyright (C) 2005 Linus Torvalds
   */
+#include <errno.h>
+#include <string.h>
+
  #include "cache.h"

  static void check_file(const char *path)
Index: checkout-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/checkout-cache.c  
(mode:100644 sha1:b5ca20e8d0e25a688bcca3f0be39e9493dc947ce)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/checkout-cache.c  
(mode:100644 sha1:c6576f35685a0a83627af2fa5edba742a103c2ad)
@@ -32,34 +32,42 @@
   * of "-a" causing problems (not possible in the above example,
   * but get used to it in scripting!).
   */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+
  #include "cache.h"

  static int force = 0, quiet = 0, not_new = 0;

-static void create_directories(const char *path)
+static int
+create_directories(const char *path)
  {
-	int len = strlen(path);
-	char *buf = xmalloc(len + 1);
-	const char *slash = path;
+	char *buf = (char *)path;
+	char *slash = buf;

  	while ((slash = strchr(slash+1, '/')) != NULL) {
-		len = slash - path;
-		memcpy(buf, path, len);
-		buf[len] = 0;
-		mkdir(buf, 0755);
+		*slash = '\0';
+		if (0 != mkdir(buf, 0755))
+			return error("Unable to mkdir(``%s'', 0755)", buf);
+		*slash = '/';
  	}
-	free(buf);
+
+	return 0;
  }

-static int create_file(const char *path, unsigned int mode)
+static int
+create_file(const char *path, unsigned int mode)
  {
  	int fd;

  	mode = (mode & 0100) ? 0777 : 0666;
  	fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
  	if (fd < 0) {
-		if (errno == ENOENT) {
-			create_directories(path);
+		if (ENOENT == errno) {
+			if (0 != create_directories(path)) return -1;
  			fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
  		}
  	}
@@ -110,7 +118,7 @@
  			return 0;
  		if (!force) {
  			if (!quiet)
-				fprintf(stderr, "checkout-cache: %s already exists\n", path);
+				message("checkout-cache: %s already exists\n", path);
  			return 0;
  		}

@@ -132,8 +140,7 @@
  	if (pos < 0) {
  		if (!quiet) {
  			pos = -pos - 1;
-			fprintf(stderr,
-				"checkout-cache: %s is %s.\n",
+			message("checkout-cache: %s is %s.\n",
  				name,
  				(pos < active_nr &&
  				 !strcmp(active_cache[pos]->name, name)) ?
Index: commit-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/commit-tree.c  
(mode:100644 sha1:23de13361944ad7ba7c5320cf7cdd04e81842c60)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/commit-tree.c  
(mode:100644 sha1:e396ca80f6a87c09130b19fc5452605ac7d83861)
@@ -3,13 +3,13 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
-#include "cache.h"
-
+#include <ctype.h>
  #include <pwd.h>
  #include <time.h>
+#include <stdio.h>
  #include <string.h>
-#include <ctype.h>
-#include <time.h>
+
+#include "cache.h"

  #define BLOCKING (1ul << 14)

Index: convert-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/convert-cache.c  
(mode:100644 sha1:631d1aa910e7328c99642495f93908c749074f91)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/convert-cache.c  
(mode:100644 sha1:e50248857b1b707a771a42fe4ce7f7dcc5fdc79f)
@@ -1,6 +1,9 @@
  #define _XOPEN_SOURCE /* glibc2 needs this */
-#include <time.h>
  #include <ctype.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  struct entry {
Index: diff-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/diff-cache.c  (mode:100644 
sha1:49f815cf732a32c87d965f22b00850643e7aab77)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/diff-cache.c  (mode:100644 
sha1:1177977fba4d3d2fcd3cd6ec72451abb84d414a1)
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "diff.h"

Index: diff-tree-helper.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/diff-tree-helper.c  
(mode:100644 sha1:f3efc8a6f2d21c33bd6096dae3150df61800b015)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/diff-tree-helper.c  
(mode:100644 sha1:4071871b6d3416d02d6203c47950d482d79c78f4)
@@ -1,6 +1,9 @@
  /*
   * Copyright (C) 2005 Junio C Hamano
   */
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "strbuf.h"
  #include "diff.h"
Index: diff-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/diff-tree.c  (mode:100644 
sha1:5a1ad34652fcda63a37c3aeb55c0231f1be69bdd)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/diff-tree.c  (mode:100644 
sha1:ac026816c32cb44d43025236409655f97197aff2)
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "diff.h"

Index: diff.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/diff.c  (mode:100644 
sha1:4cc41f097dfe1ade230d2d6e438b0249dfbc1a76)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/diff.c  (mode:100644 
sha1:0326f0488d2c037f238f9012d8a007473b13b968)
@@ -3,6 +3,11 @@
   */
  #include <sys/types.h>
  #include <sys/wait.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "diff.h"

Index: fsck-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/fsck-cache.c  (mode:100644 
sha1:f9b1431dd8f4f3b426a7e410de952277aaa11401)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/fsck-cache.c  (mode:100644 
sha1:265319c97cc68313e3e62d304c38d074dc22abdb)
@@ -1,11 +1,13 @@
-#include "cache.h"
-
  #include <sys/types.h>
+
  #include <dirent.h>
+#include <stdio.h>
+#include <string.h>

  #include "commit.h"
  #include "tree.h"
  #include "blob.h"
+#include "cache.h"

  #define REACHABLE 0x0001

@@ -44,7 +46,7 @@
  	if (parse_tree(item))
  		return -1;
  	if (item->has_full_path) {
-		fprintf(stderr, "warning: fsck-cache: tree %s "
+		warning("fsck-cache: tree %s "
  			"has full pathnames in it\n", sha1_to_hex(sha1));
  	}
  	return 0;
@@ -182,7 +184,7 @@
  			if (!fsck_name(name))
  				continue;
  		}
-		fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+		error("bad sha1 file: %s/%s\n", path, de->d_name);
  	}
  	closedir(dir);
  	return 0;
@@ -238,10 +240,10 @@

  	if (!heads) {
  		if (show_unreachable) {
-			fprintf(stderr, "unable to do reachability without a head\n");
+			message("unable to do reachability without a head\n");
  			show_unreachable = 0;
  		}
-		fprintf(stderr, "expect dangling commits - potential heads - due to 
lack of head information\n");
+		message("expect dangling commits - potential heads - due to lack of 
head information\n");
  	}

  	check_connectivity();
Index: git-export.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/git-export.c  (mode:100644 
sha1:9c867a285b7753859bb2cdcdb2615b386847db70)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/git-export.c  (mode:100644 
sha1:c141f559b9f3e4812bd5a3f3f06df6e246f58142)
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "commit.h"

Index: git-mktag.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/git-mktag.c  (mode:100644 
sha1:5d2830dc2bdfa2e76afc3fd4687db8faffaefba2)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/git-mktag.c  (mode:100644 
sha1:ae0d0c560a6da9ace877b25e7691745d660a9e3a)
@@ -1,3 +1,6 @@
+#include <string.h>
+#include <stdio.h>
+
  #include "cache.h"

  /*
Index: init-db.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/init-db.c  (mode:100644 
sha1:83f95e8b926f4fd28e0db0ccfc4f040d4172ee8a)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/init-db.c  (mode:100644 
sha1:e4ce5acea8efb8488a2557d022ca9673a6d5170a)
@@ -3,13 +3,17 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  void safe_create_dir(char *dir)
  {
  	if (mkdir(dir, 0755) < 0) {
  		if (errno != EEXIST) {
-			perror(dir);
+			error("%s: %s", dir, strerror(errno));
  			exit(1);
  		}
  	}
@@ -31,7 +35,7 @@
  	sha1_dir = getenv(DB_ENVIRONMENT);
  	if (!sha1_dir) {
  		sha1_dir = DEFAULT_DB_ENVIRONMENT;
-		fprintf(stderr, "defaulting to local storage area\n");
+		error("defaulting to local storage area");
  	}
  	len = strlen(sha1_dir);
  	path = xmalloc(len + 40);
Index: ls-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/ls-tree.c  (mode:100644 
sha1:60c169000bfaf7aa21406861e82140449f9a07ea)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/ls-tree.c  (mode:100644 
sha1:94e3780d30bbdbb33693d2d767e81b26c83bd612)
@@ -3,6 +3,9 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  int line_termination = '\n';
Index: merge-base.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/merge-base.c  (mode:100644 
sha1:2c40881302e586366f03ae6ac6e7c0035847e2f0)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/merge-base.c  (mode:100644 
sha1:ec9162900c34f45b2c736436554481d380ec0778)
@@ -1,4 +1,6 @@
  #include <stdlib.h>
+#include <stdio.h>
+
  #include "cache.h"
  #include "commit.h"

Index: merge-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/merge-cache.c  
(mode:100644 sha1:4902749fbb4230f218a350efa0ff786ded40337a)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/merge-cache.c  
(mode:100644 sha1:8c944f383e699677e92d945d61e85ebf1a125321)
@@ -1,6 +1,9 @@
  #include <sys/types.h>
  #include <sys/wait.h>

+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  static const char *pgm = NULL;
Index: read-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/read-cache.c  (mode:100644 
sha1:2112168477b8cc87970a94c584104d888ad0c067)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/read-cache.c  (mode:100644 
sha1:2c2f85a3cdad584eddfa2a1db23d122630f14a75)
@@ -3,7 +3,9 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
-#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
  #include "cache.h"

  struct cache_entry **active_cache = NULL;
Index: read-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/read-tree.c  (mode:100644 
sha1:1ad7ffc555b635fe57fa7834b12d71ff576be065)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/read-tree.c  (mode:100644 
sha1:8b2de2a750328f82759c23c6ec35e35cfac42689)
@@ -3,6 +3,9 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  static int stage = 0;
Index: rev-list.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/rev-list.c  (mode:100644 
sha1:77bfc29db1aad08ba9d7d87ce08d33d4a88e74e3)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/rev-list.c  (mode:100644 
sha1:7cd56acf83c17e752f2cabd06efc4acc2f0b10ea)
@@ -1,3 +1,4 @@
+#include <stdio.h>
  #include "cache.h"
  #include "commit.h"

Index: rev-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/rev-tree.c  (mode:100644 
sha1:94d500ec091e8c1ac0bd4c68a7e39fd5213a79eb)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/rev-tree.c  (mode:100644 
sha1:4a4d7c6b4baf8119c3f475eeb4c0302a978ff63c)
@@ -1,7 +1,10 @@
  #define _XOPEN_SOURCE /* glibc2 needs this */
  #define _BSD_SOURCE /* for tm.tm_gmtoff */
-#include <time.h>
+
  #include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>

  #include "cache.h"
  #include "commit.h"
Index: rpush.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/rpush.c  (mode:100644 
sha1:0293a1a46311d7e20b13177143741ab9d6d0d201)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/rpush.c  (mode:100644 
sha1:83b197668b1b61ccbe73aa88084adcf8ee1e807e)
@@ -1,7 +1,10 @@
-#include "cache.h"
-#include "rsh.h"
+#include <sys/types.h>
  #include <sys/socket.h>
  #include <errno.h>
+#include <string.h>
+
+#include "cache.h"
+#include "rsh.h"

  void service(int fd_in, int fd_out) {
  	ssize_t size;
@@ -14,10 +17,10 @@
  		do {
  			size = read(fd_in, sha1 + posn, 20 - posn);
  			if (size < 0) {
-				perror("rpush: read ");
+				error("rpush: read %s", strerror(errno));
  				return;
  			}
-			if (!size)
+			if (0 == size)
  				return;
  			posn += size;
  		} while (posn < 20);
@@ -26,7 +29,7 @@

  		buf = map_sha1_file(sha1, &objsize);
  		if (!buf) {
-			fprintf(stderr, "rpush: could not find %s\n",
+			error("rpush: could not find %s\n",
  				sha1_to_hex(sha1));
  			return;
  		}
@@ -34,10 +37,11 @@
  		do {
  			size = write(fd_out, buf + posn, objsize - posn);
  			if (size <= 0) {
-				if (!size) {
-					fprintf(stderr, "rpush: write closed");
+				if (0 == size) {
+					error("rpush: write closed");
  				} else {
-					perror("rpush: write ");
+					error("rpush: write %s",
+					     strerror(errno));
  				}
  				return;
  			}
Index: rsh.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/rsh.c  (mode:100644 
sha1:af2f47b174e3895e6c02c4cd8f16a89e3bacbbbb)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/rsh.c  (mode:100644 
sha1:c1c1b2653460588cb1c76fffc68dce002ae3b6f9)
@@ -1,10 +1,12 @@
-#include "rsh.h"
-
-#include <string.h>
  #include <sys/types.h>
  #include <sys/socket.h>

+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
+
+#include "rsh.h"

  #define COMMAND_SIZE 4096

Index: sha1_file.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/sha1_file.c  (mode:100644 
sha1:2bc1590efa688e7a4d7b3a89d3bffb1482e7302a)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/sha1_file.c  (mode:100644 
sha1:7b25a17e78fd114f0436bc48f4b52d3852266153)
@@ -6,7 +6,16 @@
   * This handles basic git sha1 object files - packing, unpacking,
   * creation etc.
   */
-#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+//#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
  #include "cache.h"

  const char *sha1_file_directory = NULL;
@@ -64,6 +73,7 @@
   * NOTE! This returns a statically allocated buffer, so you have to be
   * careful about using it. Do a "strdup()" if you need to save the
   * filename.
+ * NOTE! This is not thread safe.
   */
  char *sha1_file_name(const unsigned char *sha1)
  {
@@ -71,7 +81,7 @@
  	static char *name, *base;

  	if (!base) {
-		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : 
DEFAULT_DB_ENVIRONMENT;
+		char *sha1_file_directory = get_object_directory();
  		int len = strlen(sha1_file_directory);
  		base = xmalloc(len + 60);
  		memcpy(base, sha1_file_directory, len);
@@ -109,22 +119,27 @@
  	struct stat st;
  	void *map;
  	int fd;
+	mode_t mode = O_RDONLY | sha1_file_open_flag;

-	fd = open(filename, O_RDONLY | sha1_file_open_flag);
+	fd = open(filename, mode);
  	if (fd < 0) {
-		/* See if it works without O_NOATIME */
+		/* See if it works without special flags */
  		switch (sha1_file_open_flag) {
  		default:
-			fd = open(filename, O_RDONLY);
+			mode = O_RDONLY;
+			fd = open(filename, mode);
  			if (fd >= 0)
  				break;
-		/* Fallthrough */
+			/* FALLTHROUGH */
  		case 0:
-			perror(filename);
+			error("Unable to open(%s, %o): %s", filename, mode,
+			     strerror(errno));
  			return NULL;
  		}

-		/* If it failed once, it will probably fail again. Stop using 
O_NOATIME */
+		/*
+		 * If it failed once, it will probably fail again.
+		 *  Stop using O_NOATIME */
  		sha1_file_open_flag = 0;
  	}
  	if (fstat(fd, &st) < 0) {
@@ -144,7 +159,7 @@
  	int ret, bytes;
  	z_stream stream;
  	char buffer[8192];
-	char *buf;
+	char *buf = NULL;

  	/* Get the data stream */
  	memset(&stream, 0, sizeof(stream));
@@ -154,23 +169,38 @@
  	stream.avail_out = sizeof(buffer);

  	inflateInit(&stream);
-	ret = inflate(&stream, 0);
-	if (ret < Z_OK)
-		return NULL;
-	if (sscanf(buffer, "%10s %lu", type, size) != 2)
-		return NULL;
+	ret = inflate(&stream, Z_SYNC_FLUSH);
+	if (ret < Z_OK) {
+		error("Error during initial inflate.");
+		goto end;
+	}
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
+		error("Malformed object.");
+		goto end;
+	}

  	bytes = strlen(buffer) + 1;
-	buf = xmalloc(*size);
+	buf = malloc(*size);
+	if (NULL == buf) {
+		error("Unable to malloc(%d): %s", *size, strerror(errno));
+		goto end;
+	}

  	memcpy(buf, buffer + bytes, stream.total_out - bytes);
  	bytes = stream.total_out - bytes;
-	if (bytes < *size && ret == Z_OK) {
+	if (bytes < *size && Z_OK == ret) {
  		stream.next_out = buf + bytes;
  		stream.avail_out = *size - bytes;
-		while (inflate(&stream, Z_FINISH) == Z_OK)
+		while (Z_OK == (ret = inflate(&stream, Z_FINISH)))
  			/* nothing */;
  	}
+
+	if (Z_STREAM_END != ret) {
+		free(buf);
+		buf = NULL;
+		error("Error during inflate.");
+	}
+end:
  	inflateEnd(&stream);
  	return buf;
  }
@@ -231,8 +261,8 @@

  int write_sha1_file(char *buf, unsigned long len, const char *type, 
unsigned char *returnsha1)
  {
-	int size;
-	char *compressed;
+	int size, ret;
+	char *compressed = NULL;
  	z_stream stream;
  	unsigned char sha1[20];
  	SHA_CTX c;
@@ -249,14 +279,16 @@
  	SHA1_Update(&c, buf, len);
  	SHA1_Final(sha1, &c);

-	if (returnsha1)
+	if (NULL != returnsha1)
  		memcpy(returnsha1, sha1, 20);

  	filename = sha1_file_name(sha1);
  	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
  	if (fd < 0) {
-		if (errno != EEXIST)
-			return -1;
+		if (EEXIST != errno)
+			return error(
+"Cannot open(%s, O_WRONLY | O_CREAT | O_EXCL, 0666):\n%s",
+				    filename, strerror(errno));

  		/*
  		 * We might do collision checking here, but we'd need to
@@ -267,9 +299,17 @@

  	/* Set it up */
  	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
+	if(Z_OK != deflateInit(&stream, Z_BEST_COMPRESSION)) {
+		unlink(filename);
+		ret = error("deflateInit(&stream, Z_BEST_COMPRESSION) failed");
+		goto end;
+        }
  	size = deflateBound(&stream, len+hdrlen);
-	compressed = xmalloc(size);
+	compressed = malloc(size);
+	if (NULL == compressed) {
+		ret = error("Unable to malloc(%d):%s", size, strerror(errno));
+		goto end;
+	}

  	/* Compress it */
  	stream.next_out = compressed;
@@ -278,23 +318,39 @@
  	/* First header.. */
  	stream.next_in = hdr;
  	stream.avail_in = hdrlen;
-	while (deflate(&stream, 0) == Z_OK)
+	while (Z_OK == (ret = deflate(&stream, Z_NO_FLUSH)))
  		/* nothing */
+	if (Z_STREAM_END != ret) {
+		ret = error("Error deflating header");
+		goto end;
+	}

  	/* Then the data itself.. */
  	stream.next_in = buf;
  	stream.avail_in = len;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
+	while (Z_OK == (ret = deflate(&stream, Z_FINISH)))
  		/* nothing */;
-	deflateEnd(&stream);
-	size = stream.total_out;
+	if (Z_STREAM_END != ret) {
+		ret = error("Error deflating data");
+		goto end;
+	}

-	if (write(fd, compressed, size) != size)
-		die("unable to write file");
+	size = write(fd, compressed, stream.total_out);
+	ret = 0;
+	if (stream.total_out != size) {
+		if (0 > size)
+			ret = error("Error writing to %s:%s", filename,
+				   strerror(errno));
+		else
+			ret = error("Unexpected short write to %s", filename);
+	}
+end:
  	free(compressed);
+	deflateEnd(&stream);
  	close(fd);
+	if (0 != ret) unlink(filename);
  		
-	return 0;
+	return ret;
  }

  static inline int collision_check(char *filename, void *buf, unsigned 
int size)
@@ -354,7 +410,6 @@
  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];
@@ -366,7 +421,9 @@
  	local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);

  	if (local < 0)
-		return error("Couldn't open %s\n", filename);
+		return error(
+"Error open(%s, O_WRONLY | O_CREAT | O_EXCL, 0666):\n%s",
+			    filename, strerror(errno));

  	memset(&stream, 0, sizeof(stream));

@@ -377,13 +434,12 @@
  	do {
  		ssize_t size;
  		size = read(fd, buf, 4096);
-		if (size <= 0) {
+		if (0 >= size) {
  			close(local);
  			unlink(filename);
-			if (!size)
-				return error("Connection closed?");
-			perror("Reading from connection");
-			return -1;
+			if (0 == size) return error("Connection closed?");
+			return error("Reading from connection: %s",
+				    strerror(errno));
  		}
  		write(local, buf, size);
  		stream.avail_in = size;
Index: show-diff.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/show-diff.c  (mode:100644 
sha1:b13dbabcbd48b509d71bf36ff75ee569005e0d83)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/show-diff.c  (mode:100644 
sha1:9c44d7b5e0c62f54cf59b50565837bc04e20a9e6)
@@ -3,6 +3,10 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"
  #include "diff.h"

@@ -88,7 +92,7 @@
  	 * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
  	 */
  	if (entries < 0) {
-		perror("read_cache");
+		error("read_cache: %s", strerror(errno));
  		exit(1);
  	}

@@ -113,7 +117,7 @@

  		if (stat(ce->name, &st) < 0) {
  			if (errno != ENOENT) {
-				perror(ce->name);
+				error("%s: %s", ce->name, strerror(errno));
  				continue;
  			}	
  			if (silent)
Index: show-files.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/show-files.c  (mode:100644 
sha1:dd9ea231ef0e5af1d55f16add1d2f265a9bcc904)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/show-files.c  (mode:100644 
sha1:12771b89e32c841dc2227fe624ab0ad1d623ef77)
@@ -6,6 +6,8 @@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include <dirent.h>
+#include <string.h>
+#include <stdio.h>

  #include "cache.h"

Index: tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/tree.c  (mode:100644 
sha1:7c55bb9bfa1565dc9df5cab31207a02004d7fe10)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/tree.c  (mode:100644 
sha1:9db7f13cda9e5adac67e5c258574adedc0e16e42)
@@ -1,7 +1,10 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "tree.h"
  #include "blob.h"
  #include "cache.h"
-#include <stdlib.h>

  const char *tree_type = "tree";

Index: unpack-file.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/unpack-file.c  
(mode:100644 sha1:6ff3d51c182627f42b104932ecea9b95d6225a5d)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/unpack-file.c  
(mode:100644 sha1:07f4d576b81d1abd0c906b68cc93c733cc84ccf6)
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  static char *create_temp_file(unsigned char *sha1)
Index: update-cache.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/update-cache.c  
(mode:100644 sha1:30ab8972bd0d49fa0ae3fef33f68618c8b042acf)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/update-cache.c  
(mode:100644 sha1:99b08762af96b0dd457abdf45b37b723a703b4af)
@@ -3,7 +3,11 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <errno.h>
  #include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  /*
Index: usage.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/usage.c  (mode:100644 
sha1:e774d2ef32726af0707d817cdb63fc8751ddc9d8)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/usage.c  (mode:100644 
sha1:58285fca616c970e2e76d4251197b5ee0e0baa3e)
@@ -4,6 +4,7 @@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include <stdarg.h>
+#include <stdio.h>
  #include "cache.h"

  static void report(const char *prefix, const char *err, va_list params)
@@ -37,4 +38,28 @@
  	report("error: ", err, params);
  	va_end(params);
  	return -1;
+}
+
+void
+warning(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	report("warning: ", err, params);
+	va_end(params);
+
+	return;
+}
+
+void
+message(const char *msg, ...)
+{
+	va_list params;
+
+	va_start(params, msg);
+	report("", msg, params);
+	va_end(params);
+
+	return;
  }
Index: write-tree.c
===================================================================
--- c3aa1e6b53cc59d5fbe261f3f859584904ae3a63/write-tree.c  (mode:100644 
sha1:168352853d37bdca71d68ad8312b87b84477dea1)
+++ 86241f0cd550785e3cba0a235f7e423d0503be93/write-tree.c  (mode:100644 
sha1:9349a974498bc9a52810d5c5203c0f27952ff14b)
@@ -3,6 +3,10 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
  #include "cache.h"

  static int check_valid_sha1(unsigned char *sha1)
@@ -12,8 +16,8 @@

  	/* If we were anal, we'd check that the sha1 of the contents actually 
matches */
  	ret = access(filename, R_OK);
-	if (ret)
-		perror(filename);
+	if (0 != ret)
+		error("access(%s, R_OK): %s", filename, strerror(errno));
  	return ret;
  }

@@ -97,10 +101,10 @@
  		struct cache_entry *ce = active_cache[i];
  		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
  			if (++unmerged > 10) {
-				fprintf(stderr, "...\n");
+				message("...");
  				break;
  			}
-			fprintf(stderr, "%s: unmerged (%s)\n", ce->name, 
sha1_to_hex(ce->sha1));
+			message("%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1));
  		}
  	}
  	if (unmerged)


\f
!-------------------------------------------------------------flip-


Added two report functions (warning, message) to usage.c.
Tried to correct all usages of xmalloc, xrealloc where simple dying
was not an option IMHO.

---
commit c0dc464ff1c7c28e263fbccafa3e7965417b002b
tree 8d544bed2cad3eb71e31dfee64544972beb49f3a
parent f03e0239ea6ae31d8f89a4a7965ed90832770c5b
author Robert Suetterlin <krs@robert3.mpe-garching.mpg.de> 1114778282 
+0200
committer Robert Suetterlin <krs@robert3.mpe-garching.mpg.de> 
1114778282 +0200

Index: Makefile
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/Makefile  (mode:100644 
sha1:3c461e439a8731b688533dccbc5dafa1471a5b3b)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/Makefile  (mode:100644 
sha1:6133db7c39995dee2dc4f4f1bfef88bc12b8f0c6)
@@ -21,7 +21,7 @@

  # DEFINES += -DNSEC

-CFLAGS=-g -O2 -Wall
+CFLAGS=-g -O -pipe -Wall -Werror
  CFLAGS+=$(DEFINES)

  # Should be changed to /usr/local
Index: cache.h
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/cache.h  (mode:100644 
sha1:036d6b6897ef119b4de051d957b5886680bfffe3)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/cache.h  (mode:100644 
sha1:5651f0b8e3181f9369467ee7c9203ce513c8cd79)
@@ -1,24 +1,11 @@
  #ifndef CACHE_H
  #define CACHE_H

-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-
-//#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-//#include <stdio.h>
-//#include <string.h>
-#include <unistd.h>
-
-#include SHA1_HEADER
-#include <zlib.h>
+//FIX: these two includes are either unnecesary, or like stddef
+// should be #included in the files that use the feature supplied
+// by the header file.
+#include <stddef.h> /* defines offsetof(), used in cache_entry_size()  
*/
+#include <stdlib.h> /* needed by inline functions xmalloc and xrealloc 
*/

  #if ZLIB_VERNUM < 0x1200
  #define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) 
+ 11)
Index: cat-file.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/cat-file.c  (mode:100644 
sha1:568cfbc266416f8afa88995a90a3d17132e8db8b)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/cat-file.c  (mode:100644 
sha1:b3edf2adc27e49d84cd1ca7a6d550d5b17d6b3e7)
@@ -5,6 +5,7 @@
   */
  #include <errno.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: check-files.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/check-files.c  
(mode:100644 sha1:438fa7fc084b94a5fe6dd0a4200b69d1ef147b75)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/check-files.c  
(mode:100644 sha1:cc336ff2fe90fc381de0d5b1eeccf9d8d9c41dec)
@@ -6,7 +6,10 @@
   *
   * Copyright (C) 2005 Linus Torvalds
   */
+#include <sys/stat.h>
+
  #include <errno.h>
+#include <fcntl.h>
  #include <string.h>

  #include "cache.h"
Index: checkout-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/checkout-cache.c  
(mode:100644 sha1:c6576f35685a0a83627af2fa5edba742a103c2ad)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/checkout-cache.c  
(mode:100644 sha1:fd42b25c405c124d2c44a72de32061bf3fecbbd0)
@@ -32,11 +32,14 @@
   * of "-a" causing problems (not possible in the above example,
   * but get used to it in scripting!).
   */
+#include <sys/param.h>
  #include <sys/types.h>
  #include <sys/stat.h>

  #include <errno.h>
+#include <fcntl.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: commit-tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/commit-tree.c  
(mode:100644 sha1:e396ca80f6a87c09130b19fc5452605ac7d83861)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/commit-tree.c  
(mode:100644 sha1:c4c20dfd1129e13171af325ac1a076926aa45370)
@@ -6,8 +6,10 @@
  #include <ctype.h>
  #include <pwd.h>
  #include <time.h>
-#include <stdio.h>
+#include <stdarg.h> /* add_buffer */
+#include <stdio.h> /* add_buffer, parse_rfc2822_date, main */
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

@@ -273,7 +275,7 @@
  		parents++;
  	}
  	if (!parents)
-		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
+		message("Committing initial tree %s\n", argv[1]);
  	pw = getpwuid(getuid());
  	if (!pw)
  		die("You don't exist. Go away!");
Index: convert-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/convert-cache.c  
(mode:100644 sha1:e50248857b1b707a771a42fe4ce7f7dcc5fdc79f)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/convert-cache.c  
(mode:100644 sha1:be0bbb67d15a825568eee3fca38d68780bfa6f5c)
@@ -1,4 +1,6 @@
  #define _XOPEN_SOURCE /* glibc2 needs this */
+#include <sys/stat.h>
+
  #include <ctype.h>
  #include <time.h>
  #include <stdio.h>
Index: diff-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/diff-cache.c  (mode:100644 
sha1:1177977fba4d3d2fcd3cd6ec72451abb84d414a1)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/diff-cache.c  (mode:100644 
sha1:d821c62811c2c968ec81f0eba6794bfcab5ed8f0)
@@ -1,3 +1,5 @@
+#include <sys/stat.h>
+
  #include <stdio.h>
  #include <string.h>

Index: diff-tree-helper.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/diff-tree-helper.c  
(mode:100644 sha1:4071871b6d3416d02d6203c47950d482d79c78f4)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/diff-tree-helper.c  
(mode:100644 sha1:d86042af7ad940ae20e3d24af2d688dde294a3a3)
@@ -1,6 +1,8 @@
  /*
   * Copyright (C) 2005 Junio C Hamano
   */
+#include <sys/param.h>
+
  #include <stdio.h>
  #include <string.h>

Index: diff-tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/diff-tree.c  (mode:100644 
sha1:ac026816c32cb44d43025236409655f97197aff2)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/diff-tree.c  (mode:100644 
sha1:4236f5baa23d158064544373d0d44984053899f5)
@@ -1,3 +1,5 @@
+#include <sys/stat.h>
+
  #include <stdio.h>
  #include <string.h>

Index: diff.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/diff.c  (mode:100644 
sha1:0326f0488d2c037f238f9012d8a007473b13b968)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/diff.c  (mode:100644 
sha1:e6680ebb5ea4f6451f4dcd6ce8edadb768b96c0a)
@@ -2,11 +2,14 @@
   * Copyright (C) 2005 Junio C Hamano
   */
  #include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
  #include <sys/wait.h>

  #include <errno.h>
  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"
  #include "diff.h"
Index: fsck-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/fsck-cache.c  (mode:100644 
sha1:265319c97cc68313e3e62d304c38d074dc22abdb)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/fsck-cache.c  (mode:100644 
sha1:7a16928924425b142d5350375e1c949bfee0066e)
@@ -1,4 +1,5 @@
  #include <sys/types.h>
+#include <sys/mman.h> /* needed to munmap a map returned by 
map_sha1_file */

  #include <dirent.h>
  #include <stdio.h>
@@ -135,6 +136,7 @@
  	return 0;
  }

+// FIX: uses map_sha1_file and unpack_sha1_file, never frees buffer
  static int fsck_name(char *hex)
  {
  	unsigned char sha1[20];
Index: git-mktag.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/git-mktag.c  (mode:100644 
sha1:ae0d0c560a6da9ace877b25e7691745d660a9e3a)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/git-mktag.c  (mode:100644 
sha1:72e1eb38fb562c0275b4903dcc23e05f14f1532c)
@@ -1,3 +1,6 @@
+#include <sys/types.h> /* only needed for mman.h */
+#include <sys/mman.h> /*only needed for munmap */
+
  #include <string.h>
  #include <stdio.h>

@@ -25,6 +28,7 @@
  /*
   * We refuse to tag something we can't verify. Just because.
   */
+// FIX: uses map_sha1_file and unpack_sha1_file
  static int verify_object(unsigned char *sha1, const char 
*expected_type)
  {
  	int ret = -1;
@@ -115,7 +119,7 @@
  		usage("cat <signaturefile> | git-mktag");

  	// Read the signature
-	size = read(0, buffer, MAXSIZE);
+	size = fread(buffer, MAXSIZE, 1, stdin);

  	// Verify it for some basic sanity: it needs to start with "object 
<sha1>\ntag "
  	if (verify_tag(buffer, size) < 0)
Index: http-pull.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/http-pull.c  (mode:100644 
sha1:192dcc370dee47c52c72915394bb6f2a79f64e12)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/http-pull.c  (mode:100644 
sha1:fba8940c5435eb05e1093172b7ebb20e1795761b)
@@ -1,14 +1,17 @@
+#include <errno.h>
  #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 <string.h>
+#include <unistd.h>

  #include <curl/curl.h>
  #include <curl/easy.h>
+#include SHA1_HEADER
+#include <zlib.h>
+
+#include "cache.h"
+#include "commit.h"

  static CURL *curl;

@@ -93,7 +96,7 @@
  	close(local);
  	inflateEnd(&stream);
  	SHA1_Final(real_sha1, &c);
-	if (zret != Z_STREAM_END) {
+	if (Z_STREAM_END != zret) {
  		unlink(filename);
  		return error("File %s (%s) corrupt\n", hex, url);
  	}
Index: init-db.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/init-db.c  (mode:100644 
sha1:e4ce5acea8efb8488a2557d022ca9673a6d5170a)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/init-db.c  (mode:100644 
sha1:aba6b2630dfac2f8a3d58db776fe7c1c0535dd3a)
@@ -3,6 +3,8 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/stat.h>
+
  #include <errno.h>
  #include <stdio.h>
  #include <string.h>
Index: ls-tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/ls-tree.c  (mode:100644 
sha1:94e3780d30bbdbb33693d2d767e81b26c83bd612)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/ls-tree.c  (mode:100644 
sha1:ea2c7ce121d203711e54efb3bd41788c60c7f3ef)
@@ -3,6 +3,8 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/stat.h>
+
  #include <stdio.h>
  #include <string.h>

Index: merge-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/merge-cache.c  
(mode:100644 sha1:8c944f383e699677e92d945d61e85ebf1a125321)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/merge-cache.c  
(mode:100644 sha1:281ae0ab5da499a68f5072e197f2d38980b87b8a)
@@ -1,8 +1,10 @@
  #include <sys/types.h>
+#include <sys/stat.h>
  #include <sys/wait.h>

  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: read-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/read-cache.c  (mode:100644 
sha1:2c2f85a3cdad584eddfa2a1db23d122630f14a75)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/read-cache.c  (mode:100644 
sha1:0e99d46b859a13b9aaceb497488e6255a883663b)
@@ -3,9 +3,16 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
  #include <errno.h>
+#include <fcntl.h>
  #include <string.h>
+#include <unistd.h>

+#include SHA1_HEADER
  #include "cache.h"

  struct cache_entry **active_cache = NULL;
Index: read-tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/read-tree.c  (mode:100644 
sha1:8b2de2a750328f82759c23c6ec35e35cfac42689)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/read-tree.c  (mode:100644 
sha1:d3dbbd2bc1f85554b6ea96edf7e7ffee73afd79e)
@@ -3,8 +3,12 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/param.h>
+
+#include <fcntl.h>
  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: rpush.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/rpush.c  (mode:100644 
sha1:83b197668b1b61ccbe73aa88084adcf8ee1e807e)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/rpush.c  (mode:100644 
sha1:bb67e578915c571523d49d2b7ae6344ee45b2853)
@@ -1,7 +1,9 @@
  #include <sys/types.h>
  #include <sys/socket.h>
+
  #include <errno.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"
  #include "rsh.h"
Index: rsh.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/rsh.c  (mode:100644 
sha1:c1c1b2653460588cb1c76fffc68dce002ae3b6f9)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/rsh.c  (mode:100644 
sha1:85f508a6ae6f9dfcc215a8468bc2cb337cf94c4f)
@@ -3,6 +3,7 @@

  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: sha1_file.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/sha1_file.c  (mode:100644 
sha1:7b25a17e78fd114f0436bc48f4b52d3852266153)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/sha1_file.c  (mode:100644 
sha1:0f07a82f7ab5a6bc89dec0d912cf5ce2d7fff64a)
@@ -7,15 +7,19 @@
   * creation etc.
   */
  #include <sys/types.h>
-#include <sys/uio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+//#include <sys/uio.h>

  #include <errno.h>
  #include <fcntl.h>
-//#include <stdarg.h>
  #include <stdio.h>
  #include <string.h>
  #include <unistd.h>

+#include SHA1_HEADER
+#include <zlib.h>
+
  #include "cache.h"

  const char *sha1_file_directory = NULL;
@@ -319,9 +323,9 @@
  	stream.next_in = hdr;
  	stream.avail_in = hdrlen;
  	while (Z_OK == (ret = deflate(&stream, Z_NO_FLUSH)))
-		/* nothing */
-	if (Z_STREAM_END != ret) {
-		ret = error("Error deflating header");
+		/* nothing */;
+	if (Z_STREAM_ERROR == ret) {
+		ret = error("deflate(header): inconsistent stream state.");
  		goto end;
  	}

@@ -457,7 +461,7 @@

  	close(local);
  	SHA1_Final(real_sha1, &c);
-	if (ret != Z_STREAM_END) {
+	if (Z_STREAM_END != ret) {
  		unlink(filename);
  		return error("File %s corrupted", sha1_to_hex(sha1));
  	}
Index: show-diff.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/show-diff.c  (mode:100644 
sha1:9c44d7b5e0c62f54cf59b50565837bc04e20a9e6)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/show-diff.c  (mode:100644 
sha1:187cadd510e86018493061addd72465d9c920caa)
@@ -3,6 +3,8 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/stat.h>
+
  #include <errno.h>
  #include <stdio.h>
  #include <string.h>
Index: show-files.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/show-files.c  (mode:100644 
sha1:12771b89e32c841dc2227fe624ab0ad1d623ef77)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/show-files.c  (mode:100644 
sha1:c54ffdd14b1815381d1957cab9ce0499c9739691)
@@ -5,6 +5,9 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/param.h>
+#include <sys/stat.h>
+
  #include <dirent.h>
  #include <string.h>
  #include <stdio.h>
Index: tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/tree.c  (mode:100644 
sha1:9db7f13cda9e5adac67e5c258574adedc0e16e42)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/tree.c  (mode:100644 
sha1:f9762bf82e528ad3842c8ada4d8ccaf5acce96c3)
@@ -1,3 +1,5 @@
+#include <sys/stat.h>
+
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
Index: unpack-file.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/unpack-file.c  
(mode:100644 sha1:07f4d576b81d1abd0c906b68cc93c733cc84ccf6)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/unpack-file.c  
(mode:100644 sha1:5a867509ba1f7276cdeec6ff46fd6fd0f89c80c8)
@@ -1,5 +1,6 @@
  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"

Index: update-cache.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/update-cache.c  
(mode:100644 sha1:99b08762af96b0dd457abdf45b37b723a703b4af)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/update-cache.c  
(mode:100644 sha1:78d4ba3fbbf548b85935a6fb83f445dcb5eec3c0)
@@ -3,10 +3,20 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/types.h> /* FIX: used in index_fd, should be part of 
sha1_file */
+#include <sys/mman.h> /* FIX: used in index_fd, should be part of 
sha1_file */
+#include <sys/param.h> /* only used in main for MAXPATHLEN */
+#include <sys/stat.h>
+
  #include <errno.h>
+#include <fcntl.h>
  #include <signal.h>
  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>
+
+#include SHA1_HEADER /* FIX: used in index_fd, should be part of 
sha1_file */
+#include <zlib.h> /* FIX: used in index_fd, should be part of 
sha1_file */

  #include "cache.h"

@@ -79,7 +89,7 @@
  	stream.next_in = in;
  	stream.avail_in = size;
  	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/*nothing */;
+		/* nothing */;

  	deflateEnd(&stream);
  	
@@ -115,7 +125,7 @@

  	fd = open(path, O_RDONLY);
  	if (fd < 0) {
-		if (errno == ENOENT) {
+		if (ENOENT == errno) {
  			if (allow_remove)
  				return remove_file_from_cache(path);
  		}
@@ -123,7 +133,7 @@
  	}
  	if (fstat(fd, &st) < 0) {
  		close(fd);
-		return -1;
+		return error("fstat(\"%s\"): %s", path, strerror(errno));
  	}
  	if (S_ISDIR(st.st_mode)) {
  		fprintf(stderr, "'%s' is a directory, ignoring\n", path);
Index: write-tree.c
===================================================================
--- 86241f0cd550785e3cba0a235f7e423d0503be93/write-tree.c  (mode:100644 
sha1:9349a974498bc9a52810d5c5203c0f27952ff14b)
+++ 8d544bed2cad3eb71e31dfee64544972beb49f3a/write-tree.c  (mode:100644 
sha1:1f32b3ab5b482b68934e1d8373b253750962a027)
@@ -3,9 +3,12 @@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
+#include <sys/stat.h>
+
  #include <errno.h>
  #include <stdio.h>
  #include <string.h>
+#include <unistd.h>

  #include "cache.h"



\f
!-------------------------------------------------------------flip-



^ permalink raw reply	[relevance 12%]

* Re: Trying to use AUTHOR_DATE
  @ 2005-04-30 10:53 12%       ` Edgar Toernig
    0 siblings, 1 reply; 200+ results
From: Edgar Toernig @ 2005-04-30 10:53 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: H. Peter Anvin, Luck, Tony, git

Linus Torvalds wrote:
>
> Edgar, willing to create a separate "parse-date.c" with your "my_mktime()" 
> thing and move the old date parsing there? That way we'll just use that 
> instead of libcurl..

Here it is.  I moved the strftime stuff too (workaround for non-standard
%s %z sequence).

--- k/Makefile  (mode:100644)
+++ l/Makefile  (mode:100644)
@@ -28,7 +28,8 @@ all: $(PROG)
 install: $(PROG) $(SCRIPTS)
 	install $(PROG) $(SCRIPTS) $(HOME)/bin/
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o tag.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
+	 tag.o date.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h
 
--- k/cache.h  (mode:100644)
+++ l/cache.h  (mode:100644)
@@ -147,6 +160,9 @@ extern void *read_object_with_reference(
 					const unsigned char *required_type,
 					unsigned long *size,
 					unsigned char *sha1_ret);
+
+void parse_date(char *date, char *buf, int bufsize);
+void datestamp(char *buf, int bufsize);
 
 static inline void *xmalloc(int size)
 {
--- k/commit-tree.c  (mode:100644)
+++ l/commit-tree.c  (mode:100644)
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
-#include <curl/curl.h>
 
 #define BLOCKING (1ul << 14)
 
@@ -81,24 +80,6 @@ static void remove_special(char *p)
 	}
 }
 
-/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
-   (i.e. English) day/month names, and it doesn't work correctly with %z. */
-static void parse_date(char *date, time_t *now, char *result, int maxlen)
-{
-	char *p;
-	time_t then;
-
-	if ((then = curl_getdate(date, now)) == 0)
-		return;
-
-	/* find the timezone at the end */
-	p = date + strlen(date);
-	while (p > date && isdigit(*--p))
-		;
-	if ((*p == '+' || *p == '-') && strlen(p) == 5)
-		snprintf(result, maxlen, "%lu %5.5s", then, p);
-}
-
 static void check_valid(unsigned char *sha1, const char *expect)
 {
 	void *buf;
@@ -132,8 +113,6 @@ int main(int argc, char **argv)
 	char *audate;
 	char comment[1000];
 	struct passwd *pw;
-	time_t now;
-	struct tm *tm;
 	char *buffer;
 	unsigned int size;
 
@@ -163,10 +142,8 @@ int main(int argc, char **argv)
 		strcat(realemail, ".");
 		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
 	}
-	time(&now);
-	tm = localtime(&now);
 
-	strftime(realdate, sizeof(realdate), "%s %z", tm);
+	datestamp(realdate, sizeof(realdate));
 	strcpy(date, realdate);
 
 	commitgecos = getenv("COMMIT_AUTHOR_NAME") ? : realgecos;
@@ -175,7 +152,7 @@ int main(int argc, char **argv)
 	email = getenv("AUTHOR_EMAIL") ? : realemail;
 	audate = getenv("AUTHOR_DATE");
 	if (audate)
-		parse_date(audate, &now, date, sizeof(date));
+		parse_date(audate, date, sizeof(date));
 
 	remove_special(gecos); remove_special(realgecos); remove_special(commitgecos);
 	remove_special(email); remove_special(realemail); remove_special(commitemail);
--- /dev/null
+++ l/date.c  (mode:100644)
@@ -0,0 +1,187 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+static time_t my_mktime(struct tm *tm)
+{
+	static const int mdays[] = {
+	    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+	};
+	int year = tm->tm_year - 70;
+	int month = tm->tm_mon;
+	int day = tm->tm_mday;
+
+	if (year < 0 || year > 129) /* algo only works for 1970-2099 */
+		return -1;
+	if (month < 0 || month > 11) /* array bounds */
+		return -1;
+	if (month < 2 || (year + 2) % 4)
+		day--;
+	return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
+		tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
+}
+
+static const char *month_names[] = {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *weekday_names[] = {
+        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+
+static char *skipfws(char *str)
+{
+	while (isspace(*str))
+		str++;
+	return str;
+}
+
+	
+/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
+   (i.e. English) day/month names, and it doesn't work correctly with %z. */
+void parse_date(char *date, char *result, int maxlen)
+{
+	struct tm tm;
+	char *p, *tz;
+	int i, offset;
+	time_t then;
+
+	memset(&tm, 0, sizeof(tm));
+
+	/* Skip day-name */
+	p = skipfws(date);
+	if (!isdigit(*p)) {
+		for (i=0; i<7; i++) {
+			if (!strncmp(p,weekday_names[i],3) && p[3] == ',') {
+				p = skipfws(p+4);
+				goto day;
+			}
+		}
+		return;
+	}					
+
+	/* day */
+ day:
+	tm.tm_mday = strtoul(p, &p, 10);
+
+	if (tm.tm_mday < 1 || tm.tm_mday > 31)
+		return;
+
+	if (!isspace(*p))
+		return;
+
+	p = skipfws(p);
+
+	/* month */
+
+	for (i=0; i<12; i++) {
+		if (!strncmp(p, month_names[i], 3) && isspace(p[3])) {
+			tm.tm_mon = i;
+			p = skipfws(p+strlen(month_names[i]));
+			goto year;
+		}
+	}
+	return; /* Error -- bad month */
+
+	/* year */
+ year:	
+	tm.tm_year = strtoul(p, &p, 10);
+
+	if (!tm.tm_year && !isspace(*p))
+		return;
+
+	if (tm.tm_year > 1900)
+		tm.tm_year -= 1900;
+		
+	p=skipfws(p);
+
+	/* hour */
+	if (!isdigit(*p))
+		return;
+	tm.tm_hour = strtoul(p, &p, 10);
+	
+	if (tm.tm_hour > 23)
+		return;
+
+	if (*p != ':')
+		return; /* Error -- bad time */
+	p++;
+
+	/* minute */
+	if (!isdigit(*p))
+		return;
+	tm.tm_min = strtoul(p, &p, 10);
+	
+	if (tm.tm_min > 59)
+		return;
+
+	if (*p != ':')
+		goto zone;
+	p++;
+
+	/* second */
+	if (!isdigit(*p))
+		return;
+	tm.tm_sec = strtoul(p, &p, 10);
+	
+	if (tm.tm_sec > 59)
+		return;
+
+ zone:
+	if (!isspace(*p))
+		return;
+
+	p = skipfws(p);
+
+	if (*p == '-')
+		offset = -60;
+	else if (*p == '+')
+		offset = 60;
+	else
+	       return;
+
+	if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
+		return;
+
+	tz = p;
+	i = strtoul(p+1, NULL, 10);
+	offset *= ((i % 100) + ((i / 100) * 60));
+
+	p = skipfws(p + 5);
+	if (*p && *p != '(') /* trailing comment like (EDT) is ok */
+		return;
+
+	then = my_mktime(&tm); /* mktime uses local timezone */
+	if (then == -1)
+		return;
+
+	then -= offset;
+
+	snprintf(result, maxlen, "%lu %5.5s", then, tz);
+}
+
+void datestamp(char *buf, int bufsize)
+{
+	time_t now;
+	struct tm *tm;
+	int offset;
+
+	time(&now);
+
+	tm = localtime(&now); /* get timezone and tm_isdst */
+	offset = -timezone / 60;
+	if (tm->tm_isdst > 0)
+		offset += 60;
+
+	snprintf(buf, bufsize, "%lu %+05d", now, offset/60*100 + offset%60);
+}

Ciao, ET.

^ permalink raw reply	[relevance 12%]

* git compatibility patches
@ 2005-04-30 11:40 17% Edgar Toernig
  0 siblings, 0 replies; 200+ results
From: Edgar Toernig @ 2005-04-30 11:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

With these fourc patches and the previous date patch git compiles
and works on my good old gcc2.7/libc5/2.0-kernel system.

The first one: support for pre-1.2 zlib:

--- k/cache.h  (mode:100644)
+++ l/cache.h  (mode:100644)
@@ -17,6 +17,10 @@
 #include SHA1_HEADER
 #include <zlib.h>
 
+#if ZLIB_VERNUM < 0x1200
+#define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
+#endif
+
 /*
  * Basic data structures for the directory cache
  *




The second one: missing dirent.d_type field

--- k/cache.h  (mode:100644)
+++ l/cache.h  (mode:100644)
@@ -21,6 +21,15 @@
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
+#ifdef DT_UNKNOWN
+#define DTYPE(de)	((de)->d_type)
+#else
+#define DT_UNKNOWN	0
+#define DT_DIR		1
+#define DT_REG		2
+#define DTYPE(de)	DT_UNKNOWN
+#endif
+
 /*
  * Basic data structures for the directory cache
  *
--- k/show-files.c  (mode:100644)
+++ l/show-files.c  (mode:100644)
@@ -129,7 +129,7 @@ static void read_directory(const char *p
 			len = strlen(de->d_name);
 			memcpy(fullname + baselen, de->d_name, len+1);
 
-			switch (de->d_type) {
+			switch (DTYPE(de)) {
 			struct stat st;
 			default:
 				continue;



The third one: replace AF_LOCAL with AF_UNIX (there's no AF_LOCAL in POSIX).

--- k/rsh.c  (mode:100644)
+++ l/rsh.c  (mode:100644)
@@ -48,7 +48,7 @@ int setup_connection(int *fd_in, int *fd
 		}
 	}
 	strcpy(posn, " -");
-	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) {
 		return error("Couldn't create socket");
 	}
 	if (!fork()) {


And the last one: move variable declarations to the start of the function.

--- k/tag.c  (mode:100644)
+++ l/tag.c  (mode:100644)
@@ -26,6 +26,10 @@ int parse_tag(struct tag *item)
         char type[20];
         void *data, *bufptr;
         unsigned long size;
+	int typelen, taglen;
+	unsigned char object[20];
+	const char *type_line, *tag_line, *sig_line;
+
         if (item->object.parsed)
                 return 0;
         item->object.parsed = 1;
@@ -36,10 +40,6 @@ int parse_tag(struct tag *item)
         if (strcmp(type, tag_type))
                 return error("Object %s not a tag",
                              sha1_to_hex(item->object.sha1));
-
-	int typelen, taglen;
-	unsigned char object[20];
-	const char *type_line, *tag_line, *sig_line;
 
 	if (size < 64)
 		return -1;

Ciao, ET.

^ permalink raw reply	[relevance 17%]

* Re: Trying to use AUTHOR_DATE
  @ 2005-04-30 12:49 11%           ` Edgar Toernig
  0 siblings, 0 replies; 200+ results
From: Edgar Toernig @ 2005-04-30 12:49 UTC (permalink / raw)
  To: David Woodhouse; +Cc: Linus Torvalds, H. Peter Anvin, Luck, Tony, git

David Woodhouse wrote:
>
> > +       if (tm->tm_isdst > 0)
> > +               offset += 60;
> 
> Some locales have DST offsets which aren't 60 minutes, don't they?

Oh shit :-/

If grepped through the tz-database and it seems there's one
"country" left that has non-60-minute DST: Lord Howe Island.
All others dropped that before 1970.

Ok, here's a new version of the patch.

--- k/Makefile  (mode:100644)
+++ l/Makefile  (mode:100644)
@@ -28,7 +28,8 @@ all: $(PROG)
 install: $(PROG) $(SCRIPTS)
 	install $(PROG) $(SCRIPTS) $(HOME)/bin/
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o tag.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
+	 tag.o date.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h
 
@@ -91,7 +92,6 @@ git-diff-tree-helper: diff-tree-helper.c
 git-tar-tree: tar-tree.c
 
 git-http-pull: LIBS += -lcurl
-git-commit-tree: LIBS += -lcurl
 
 # Library objects..
 blob.o: $(LIB_H)
--- k/cache.h  (mode:100644)
+++ l/cache.h  (mode:100644)
@@ -148,6 +148,9 @@ extern void *read_object_with_reference(
 					unsigned long *size,
 					unsigned char *sha1_ret);
 
+void parse_date(char *date, char *buf, int bufsize);
+void datestamp(char *buf, int bufsize);
+
 static inline void *xmalloc(int size)
 {
 	void *ret = malloc(size);
--- k/commit-tree.c  (mode:100644)
+++ l/commit-tree.c  (mode:100644)
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
-#include <curl/curl.h>
 
 #define BLOCKING (1ul << 14)
 
@@ -81,24 +80,6 @@ static void remove_special(char *p)
 	}
 }
 
-/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
-   (i.e. English) day/month names, and it doesn't work correctly with %z. */
-static void parse_date(char *date, time_t *now, char *result, int maxlen)
-{
-	char *p;
-	time_t then;
-
-	if ((then = curl_getdate(date, now)) == 0)
-		return;
-
-	/* find the timezone at the end */
-	p = date + strlen(date);
-	while (p > date && isdigit(*--p))
-		;
-	if ((*p == '+' || *p == '-') && strlen(p) == 5)
-		snprintf(result, maxlen, "%lu %5.5s", then, p);
-}
-
 static void check_valid(unsigned char *sha1, const char *expect)
 {
 	void *buf;
@@ -132,8 +113,6 @@ int main(int argc, char **argv)
 	char *audate;
 	char comment[1000];
 	struct passwd *pw;
-	time_t now;
-	struct tm *tm;
 	char *buffer;
 	unsigned int size;
 
@@ -163,10 +142,8 @@ int main(int argc, char **argv)
 		strcat(realemail, ".");
 		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
 	}
-	time(&now);
-	tm = localtime(&now);
 
-	strftime(realdate, sizeof(realdate), "%s %z", tm);
+	datestamp(realdate, sizeof(realdate));
 	strcpy(date, realdate);
 
 	commitgecos = getenv("COMMIT_AUTHOR_NAME") ? : realgecos;
@@ -175,7 +152,7 @@ int main(int argc, char **argv)
 	email = getenv("AUTHOR_EMAIL") ? : realemail;
 	audate = getenv("AUTHOR_DATE");
 	if (audate)
-		parse_date(audate, &now, date, sizeof(date));
+		parse_date(audate, date, sizeof(date));
 
 	remove_special(gecos); remove_special(realgecos); remove_special(commitgecos);
 	remove_special(email); remove_special(realemail); remove_special(commitemail);
--- /dev/null
+++ l/date.c  (mode:100644)
@@ -0,0 +1,184 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+static time_t my_mktime(struct tm *tm)
+{
+	static const int mdays[] = {
+	    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+	};
+	int year = tm->tm_year - 70;
+	int month = tm->tm_mon;
+	int day = tm->tm_mday;
+
+	if (year < 0 || year > 129) /* algo only works for 1970-2099 */
+		return -1;
+	if (month < 0 || month > 11) /* array bounds */
+		return -1;
+	if (month < 2 || (year + 2) % 4)
+		day--;
+	return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
+		tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
+}
+
+static const char *month_names[] = {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *weekday_names[] = {
+        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+
+static char *skipfws(char *str)
+{
+	while (isspace(*str))
+		str++;
+	return str;
+}
+
+	
+/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
+   (i.e. English) day/month names, and it doesn't work correctly with %z. */
+void parse_date(char *date, char *result, int maxlen)
+{
+	struct tm tm;
+	char *p, *tz;
+	int i, offset;
+	time_t then;
+
+	memset(&tm, 0, sizeof(tm));
+
+	/* Skip day-name */
+	p = skipfws(date);
+	if (!isdigit(*p)) {
+		for (i=0; i<7; i++) {
+			if (!strncmp(p,weekday_names[i],3) && p[3] == ',') {
+				p = skipfws(p+4);
+				goto day;
+			}
+		}
+		return;
+	}					
+
+	/* day */
+ day:
+	tm.tm_mday = strtoul(p, &p, 10);
+
+	if (tm.tm_mday < 1 || tm.tm_mday > 31)
+		return;
+
+	if (!isspace(*p))
+		return;
+
+	p = skipfws(p);
+
+	/* month */
+
+	for (i=0; i<12; i++) {
+		if (!strncmp(p, month_names[i], 3) && isspace(p[3])) {
+			tm.tm_mon = i;
+			p = skipfws(p+strlen(month_names[i]));
+			goto year;
+		}
+	}
+	return; /* Error -- bad month */
+
+	/* year */
+ year:	
+	tm.tm_year = strtoul(p, &p, 10);
+
+	if (!tm.tm_year && !isspace(*p))
+		return;
+
+	if (tm.tm_year > 1900)
+		tm.tm_year -= 1900;
+		
+	p=skipfws(p);
+
+	/* hour */
+	if (!isdigit(*p))
+		return;
+	tm.tm_hour = strtoul(p, &p, 10);
+	
+	if (tm.tm_hour > 23)
+		return;
+
+	if (*p != ':')
+		return; /* Error -- bad time */
+	p++;
+
+	/* minute */
+	if (!isdigit(*p))
+		return;
+	tm.tm_min = strtoul(p, &p, 10);
+	
+	if (tm.tm_min > 59)
+		return;
+
+	if (*p != ':')
+		goto zone;
+	p++;
+
+	/* second */
+	if (!isdigit(*p))
+		return;
+	tm.tm_sec = strtoul(p, &p, 10);
+	
+	if (tm.tm_sec > 59)
+		return;
+
+ zone:
+	if (!isspace(*p))
+		return;
+
+	p = skipfws(p);
+
+	if (*p == '-')
+		offset = -60;
+	else if (*p == '+')
+		offset = 60;
+	else
+	       return;
+
+	if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
+		return;
+
+	tz = p;
+	i = strtoul(p+1, NULL, 10);
+	offset *= ((i % 100) + ((i / 100) * 60));
+
+	p = skipfws(p + 5);
+	if (*p && *p != '(') /* trailing comment like (EDT) is ok */
+		return;
+
+	then = my_mktime(&tm); /* mktime uses local timezone */
+	if (then == -1)
+		return;
+
+	then -= offset;
+
+	snprintf(result, maxlen, "%lu %5.5s", then, tz);
+}
+
+void datestamp(char *buf, int bufsize)
+{
+	time_t now;
+	int offset;
+
+	time(&now);
+
+	offset = my_mktime(localtime(&now)) - now;
+	offset /= 60;
+
+	snprintf(buf, bufsize, "%lu %+05d", now, offset/60*100 + offset%60);
+}

Ciao, ET.

^ permalink raw reply	[relevance 11%]

* [1/2] Library support for refs/
  @ 2005-05-01 21:52 20% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-05-01 21:52 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This includes three things: in init, create .git/refs/; a function to read
a refs file; and a function to write a refs file.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Index: Makefile
===================================================================
--- bab2f51e8218b023728539c7841ee7613ebd36e8/Makefile  (mode:100644 sha1:a3028efd80a4165ade03158361e0224fb46364f5)
+++ f0d6a3af54a5ec8dd588fb8e501e38f6252eda19/Makefile  (mode:100644 sha1:e43a1db55962c771cc934227213d6520939bd0ce)
@@ -29,9 +29,10 @@
 	install $(PROG) $(SCRIPTS) $(HOME)/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
===================================================================
--- bab2f51e8218b023728539c7841ee7613ebd36e8/cache.h  (mode:100644 sha1:af6345820f3f8c533868394059b2d3b189e6b422)
+++ f0d6a3af54a5ec8dd588fb8e501e38f6252eda19/cache.h  (mode:100644 sha1:42a08f57c5b7a7cd013ab3e99f3965014068b787)
@@ -100,6 +100,11 @@
 
 #define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
 
+#define REF_ENVIRONMENT "REF_FILE_DIRECTORY"
+#define DEFAULT_REF_ENVIRONMENT ".git/refs"
+
+#define get_refs_directory() (getenv(REF_ENVIRONMENT) ? : DEFAULT_REF_ENVIRONMENT)
+
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define DEFAULT_INDEX_ENVIRONMENT ".git/index"
 
Index: init-db.c
===================================================================
--- bab2f51e8218b023728539c7841ee7613ebd36e8/init-db.c  (mode:100644 sha1:83f95e8b926f4fd28e0db0ccfc4f040d4172ee8a)
+++ f0d6a3af54a5ec8dd588fb8e501e38f6252eda19/init-db.c  (mode:100644 sha1:6bed5a6abdfd7da152ed13b825376c2d2f8820c4)
@@ -38,6 +38,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:bab2f51e8218b023728539c7841ee7613ebd36e8)
+++ f0d6a3af54a5ec8dd588fb8e501e38f6252eda19/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:bab2f51e8218b023728539c7841ee7613ebd36e8)
+++ f0d6a3af54a5ec8dd588fb8e501e38f6252eda19/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 */


^ permalink raw reply	[relevance 20%]

* [PATCH] delta compressed git
@ 2005-05-03  1:30 17% Chris Mason
  0 siblings, 0 replies; 200+ results
From: Chris Mason @ 2005-05-03  1:30 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 1817 bytes --]

Hello everyone,

Here's an early form of some code for delta compression in git archives.  It 
builds on top of my packed item patch from before.  Using this patch will 
create repositories that can't be read by unpatched git, and it is only ready 
for light testing.  The file format might change slightly in later revs.

deltas live as subfiles in packed files, and the packed item header has the 
sha1 of the file the delta is against. deltas are never taken against deltas, 
only whole files (so the chain length is only 1).  

When importing all of Ingo's bk->cvs patches into git (28,000 changesets), 
delta git applies the patches faster (2hrs vs 2.5hrs), consumes less space 
(900MB vs 2.5GB), and checks out the resulting git tree faster in hot and 
cold caches.

Another 200MB or so would be saved by packing trees and commits into the same 
files as the blobs.  This is easy to do, but makes the patch harder to 
maintain because I need to move code around in commit-tree.c and 
write-tree.c.  So I've left those bits out for now.

Because the packed files are created per changeset, if a changeset only 
modifies one file the delta will still end up using a whole block.  So, you 
could get much higher space savings with a tool to walk back over existing 
changesets and pack them together.  This doesn't exist yet, but wouldn't be 
difficult, and I expect it to get close to the mercurial/bk repository sizes.

The patch uses zdelta for delta compression, which you can download here:
http://cis.poly.edu/zdelta/

I'm open to suggestions on better delta libs.  I picked this one because it 
was easy to code.  In order for things to work with git you need to apply the 
attached zdelta.diff to the zdelta-2.1 sources.  It fixes a silly default in 
the Makefile and a symbol collision with zlib.

-chris

[-- Attachment #2: zdelta.diff --]
[-- Type: text/x-diff, Size: 1715 bytes --]

diff -ur zdelta-2.1.orig/infcodes.c zdelta-2.1/infcodes.c
--- zdelta-2.1.orig/infcodes.c	2003-10-26 19:30:09.000000000 -0500
+++ zdelta-2.1/infcodes.c	2005-05-02 16:03:37.000000000 -0400
@@ -145,7 +145,7 @@
     if (m >= MAX_MATCH && n >= 10) 
     {
       UPDATE
-      r = inflate_fast(c->lbits, c->dbits, c->zdbits, 
+      r = zd_inflate_fast(c->lbits, c->dbits, c->zdbits, 
 		       c->ltree, c->dtree, c->zdtree, s, z);
       LOAD
       if (r != ZD_OK)
Only in zdelta-2.1: infcodes.o
diff -ur zdelta-2.1.orig/inffast.c zdelta-2.1/inffast.c
--- zdelta-2.1.orig/inffast.c	2003-10-26 19:30:09.000000000 -0500
+++ zdelta-2.1/inffast.c	2005-05-02 16:03:20.000000000 -0400
@@ -8,7 +8,7 @@
 /* zdelta:
  *
  * modified: 
- *          inflate_fast
+ *          zd_inflate_fast
  * added:
  *          --
  * removed:
@@ -41,7 +41,7 @@
 /*
  * zdelta: modified
  */
-int inflate_fast(bl, bd, bzd, tl, td, tzd, s, z)
+int zd_inflate_fast(bl, bd, bzd, tl, td, tzd, s, z)
 uInt bl, bd, bzd;
 inflate_huft *tl;
 inflate_huft *td;
diff -ur zdelta-2.1.orig/inffast.h zdelta-2.1/inffast.h
--- zdelta-2.1.orig/inffast.h	2003-10-26 19:30:13.000000000 -0500
+++ zdelta-2.1/inffast.h	2005-05-02 16:02:58.000000000 -0400
@@ -22,7 +22,7 @@
 
 #ifndef ZD_INFFAST_H
 #define ZD_INFFAST_H
-extern int inflate_fast OF((
+extern int zd_inflate_fast OF((
     uInt,
     uInt,
     uInt,
diff -ur zdelta-2.1.orig/Makefile zdelta-2.1/Makefile
--- zdelta-2.1.orig/Makefile	2004-02-13 18:19:51.000000000 -0500
+++ zdelta-2.1/Makefile	2005-05-02 15:30:08.000000000 -0400
@@ -35,7 +35,7 @@
 
 CC=gcc
 
-CFLAGS= -O2 -W -Wall -pedantic -ansi -g -DREFNUM=2
+CFLAGS= -O2 -W -Wall -pedantic -ansi -g -DREFNUM=1
 
 LDSHARED=$(CC)
 CPP=$(CC) -E

[-- Attachment #3: delta-tree.diff --]
[-- Type: text/x-diff, Size: 23440 bytes --]

Index: Makefile
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/Makefile  (mode:100644 sha1:2d2913b6b98ac836b43755b1304d2a838dad87dd)
+++ uncommitted/Makefile  (mode:100644)
@@ -36,7 +36,7 @@
 LIB_OBJS += diff.o
 
 LIBS = $(LIB_FILE)
-LIBS += -lz
+LIBS += -lzd -lz
 
 ifdef MOZILLA_SHA1
   SHA1_HEADER="mozilla-sha1/sha1.h"
Index: cache.h
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/cache.h  (mode:100644 sha1:3277d48708f885fa1b7cc56c9d16061c65a2eeb9)
+++ uncommitted/cache.h  (mode:100644)
@@ -16,6 +16,7 @@
 
 #include SHA1_HEADER
 #include <zlib.h>
+#include <zdlib.h>
 
 /*
  * Basic data structures for the directory cache
@@ -64,6 +65,18 @@
 	char name[0];
 };
 
+struct packed_item {
+	/* length of compressed data */
+	unsigned long len;
+	struct packed_item *next;
+	/* sha1 of uncompressed data */
+	char sha1[20];
+	char refsha1[20];
+	char type[20];
+	/* compressed data */
+	char *data;
+};
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
@@ -119,7 +132,7 @@
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
+extern void * unpack_sha1_file(const unsigned char *sha1, 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 long len, const char *type, unsigned char *return_sha1);
 
@@ -135,6 +148,10 @@
 /* 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! */
+extern int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+                            unsigned char *returnsha1, unsigned char *refsha1, 
+			    struct packed_item **);
+int write_packed_buffer(struct packed_item *head);
 
 /* General helper functions */
 extern void usage(const char *err);
Index: fsck-cache.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/fsck-cache.c  (mode:100644 sha1:f9b1431dd8f4f3b426a7e410de952277aaa11401)
+++ uncommitted/fsck-cache.c  (mode:100644)
@@ -142,7 +142,7 @@
 		if (map) {
 			char type[100];
 			unsigned long size;
-			void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+			void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size);
 			if (!buffer)
 				return -1;
 			if (check_sha1_signature(sha1, buffer, size, type) < 0)
Index: git-mktag.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/git-mktag.c  (mode:100644 sha1:5d2830dc2bdfa2e76afc3fd4687db8faffaefba2)
+++ uncommitted/git-mktag.c  (mode:100644)
@@ -31,7 +31,7 @@
 	if (map) {
 		char type[100];
 		unsigned long size;
-		void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+		void *buffer = unpack_sha1_file(sha1,map,mapsize,type,&size);
 
 		if (buffer) {
 			if (!strcmp(type, expected_type))
Index: sha1_file.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/sha1_file.c  (mode:100644 sha1:db2880e389e556dd3a5eef02aa8a3bb235528057)
+++ uncommitted/sha1_file.c  (mode:100644)
@@ -139,31 +139,195 @@
 	return map;
 }
 
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+static int find_packed_header(const unsigned char *sha1, char *buf, unsigned long buf_len,
+		              unsigned char *refsha1, char *type, unsigned long *offset)
+{
+	char *p;
+	p = buf;
+
+	*offset = 0;
+	while(p < buf + buf_len) {
+		unsigned long item_len;
+		unsigned char item_sha[20];
+		memcpy(item_sha, p, 20);
+		sscanf(p + 20, "%s %lu ", type, &item_len);
+		p += 20 + strlen(p + 20) + 1;
+		if (strcmp(type, "delta") == 0) {
+			memcpy(refsha1, p, 20);
+			p += 20;
+		}
+		if (memcmp(item_sha, sha1, 20) == 0)
+			return 0;
+		*offset += item_len;
+	}
+	return -1;
+}
+
+
+static void * _unpack_sha1_file(z_stream *stream, const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size)
 {
 	int ret, bytes;
+	char buffer[8192];
+	char *buf;
+
+	/* Get the data stream */
+	memset(stream, 0, sizeof(*stream));
+	stream->next_in = map;
+	stream->avail_in = mapsize;
+	stream->next_out = buffer;
+	stream->avail_out = sizeof(buffer);
+
+	inflateInit(stream);
+	ret = inflate(stream, 0);
+	if (ret < Z_OK) {
+		return NULL;
+	}
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
+		return NULL;
+	}
+	bytes = strlen(buffer) + 1;
+	buf = xmalloc(*size);
+
+	memcpy(buf, buffer + bytes, stream->total_out - bytes);
+	bytes = stream->total_out - bytes;
+	if (bytes < *size && ret == Z_OK) {
+		stream->next_out = buf + bytes;
+		stream->avail_out = *size - bytes;
+		while (inflate(stream, Z_FINISH) == Z_OK)
+			/* nothing */;
+	}
+	inflateEnd(stream);
+	return buf;
+}
+static int find_sha1_ref(unsigned char *sha1)
+{
+	unsigned char foundsha1[20];
 	z_stream stream;
+	char *buf;
+	unsigned long header_len;
+	char type[20];
+	char *map;
+	unsigned long mapsize;
+	unsigned long offset;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return -1;
+	buf = _unpack_sha1_file(&stream, sha1, map, mapsize, type, &header_len);
+
+	if (!buf)
+		goto fail;
+	if (strcmp(type, "packed"))
+		goto fail;
+        if (find_packed_header(sha1, buf, header_len, foundsha1, type, &offset))
+		goto fail;
+	munmap(map, mapsize);
+	free(buf);
+
+	if (strcmp(type, "delta"))
+		return 0;
+	memcpy(sha1, foundsha1, 20);
+	return 0;
+fail:
+	munmap(map, mapsize);
+	free(buf);
+	return -1;
+}
+
+static void * unpack_delta(char *refsha1, char *delta_start, 
+			   unsigned long delta_len, char *type, 
+			   unsigned long *size)
+{
+	zd_stream dstream;
+	int ret, bytes;
 	char buffer[8192];
 	char *buf;
+	char *refbuffer = NULL;
+	unsigned long refsize = 0;
 
+	memset(&dstream, 0, sizeof(dstream));
+	refbuffer = read_sha1_file(refsha1, type, &refsize);
+	if (!refbuffer) {
+		return NULL;
+	}
+	dstream.base[0] = refbuffer;
+	dstream.base_avail[0] = refsize;
+	dstream.refnum = 1;
+	dstream.next_in = delta_start;
+	dstream.avail_in = delta_len;
+	dstream.next_out = buffer;
+	dstream.avail_out = sizeof(buffer);
+	ret = zd_inflateInit(&dstream);
+	ret = zd_inflate(&dstream, 0);
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
+		free(refbuffer);
+		return NULL;
+	}
+	bytes = strlen(buffer) + 1;
+	buf = xmalloc(*size);
+	memcpy(buf, buffer + bytes, 
+		dstream.total_out - bytes);
+	bytes = dstream.total_out - bytes;
+	if (bytes < *size && ret == ZD_OK) {
+		dstream.next_out = buf + bytes;
+		dstream.avail_out = *size - bytes;
+		while (zd_inflate(&dstream, ZD_FINISH) == ZD_OK)
+			/* nothing */;
+	}
+	zd_inflateEnd(&dstream);
+	free(refbuffer);
+	return buf;
+}
+
+void * unpack_sha1_file(const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size)
+{
+	int ret, bytes;
+	z_stream stream;
+	char buffer[8192];
+	char *buf;
+	unsigned long offset;
+	unsigned long header_len;
+	unsigned char refsha1[20];
+	unsigned char headertype[20];
+
+	buf = _unpack_sha1_file(&stream, sha1, map, mapsize, type, size);
+	if (!buf)
+		return buf;
+	if (strcmp(type, "packed"))
+		return buf;
+
+	if (!sha1) {
+		free(buf);
+		return NULL;
+	}
+	header_len = *size;
+        if (find_packed_header(sha1, buf, header_len, refsha1, headertype, &offset)) {
+		free(buf);
+		return NULL;
+	}
+	offset += stream.total_in;
+	free(buf);
+	if (!strcmp(headertype, "delta"))
+		return unpack_delta(refsha1, map+offset, mapsize-offset, type,size);
 	/* Get the data stream */
 	memset(&stream, 0, sizeof(stream));
-	stream.next_in = map;
-	stream.avail_in = mapsize;
+	buf = NULL;
+	stream.next_in = map + offset;
+	stream.avail_in = mapsize - offset;
 	stream.next_out = buffer;
 	stream.avail_out = sizeof(buffer);
+	ret = inflateInit(&stream);
 
-	inflateInit(&stream);
 	ret = inflate(&stream, 0);
-	if (ret < Z_OK)
-		return NULL;
-	if (sscanf(buffer, "%10s %lu", type, size) != 2)
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
 		return NULL;
-
+	}
 	bytes = strlen(buffer) + 1;
 	buf = xmalloc(*size);
-
-	memcpy(buf, buffer + bytes, stream.total_out - bytes);
+	memcpy(buf, buffer + bytes, 
+		stream.total_out - bytes);
 	bytes = stream.total_out - bytes;
 	if (bytes < *size && ret == Z_OK) {
 		stream.next_out = buf + bytes;
@@ -182,7 +346,7 @@
 
 	map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size);
 		munmap(map, mapsize);
 		return buf;
 	}
@@ -268,7 +432,8 @@
 	/* Set it up */
 	memset(&stream, 0, sizeof(stream));
 	deflateInit(&stream, Z_BEST_COMPRESSION);
-	size = deflateBound(&stream, len+hdrlen);
+	// size = zd_deflateBound(&stream, len+hdrlen);
+	size = len + hdrlen + 12;
 	compressed = xmalloc(size);
 
 	/* Compress it */
@@ -413,3 +578,323 @@
 		return 1;
 	return 0;
 }
+
+static void *pack_delta_buffer(void *buf, unsigned long buf_len, char *metadata, int metadata_size, unsigned long *compsize, unsigned char *refsha1)
+{
+	char *compressed;
+	zd_stream stream;
+	unsigned long size;
+	char *refbuffer = NULL;
+	char reftype[20];
+	unsigned long refsize = 0;
+	int ret;
+
+	if (find_sha1_ref(refsha1)) {
+		return NULL;
+	}
+	refbuffer = read_sha1_file(refsha1, reftype, &refsize);
+
+	/* note, we could just continue without the delta here */
+	if (!refbuffer) {
+		free(refbuffer);
+		return NULL;
+	}
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	/* TODO, real deflate bound here */
+	size = buf_len + metadata_size + 12;
+	compressed = xmalloc(size);
+
+	/*
+	 * ASCII size + nul byte
+	 */	
+	stream.base[0] = refbuffer;
+	stream.base_avail[0] = refsize;
+	stream.refnum = 1;
+	stream.next_in = metadata;
+	stream.avail_in = metadata_size;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	ret = zd_deflateInit(&stream, ZD_BEST_COMPRESSION);
+	/* TODO check for -ENOMEM */
+	while ((ret = zd_deflate(&stream, 0)) == ZD_OK)
+		/* nothing */;
+
+	stream.next_in = buf;
+	stream.avail_in = buf_len;
+	/* Compress it */
+	while ((ret = zd_deflate(&stream, ZD_FINISH)) == ZD_OK)
+		/* nothing */;
+	ret = zd_deflateEnd(&stream);
+	size = stream.total_out;
+	*compsize = size;
+
+	/* ugh, we're comparing the compressed size against the uncompressed size
+	 * of the reference buffer.  But, this is as good as we can do without
+	 * an extra read
+	 */
+	if (size > refsize) {
+		free(refbuffer);
+		free(compressed);
+		return NULL;
+	}
+	free(refbuffer);
+	return compressed;
+}
+
+static void *pack_buffer(void *buf, unsigned long buf_len, char *metadata, int metadata_size, unsigned long *compsize)
+{
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+	int ret;
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	/* TODO, real deflate bound here */
+	size = buf_len + metadata_size + 12;
+	compressed = xmalloc(size);
+
+	/*
+	 * ASCII size + nul byte
+	 */	
+	stream.next_in = metadata;
+	stream.avail_in = metadata_size;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	ret = deflateInit(&stream, Z_BEST_COMPRESSION);
+	/* TODO check for -ENOMEM */
+	while ((ret = deflate(&stream, 0)) == Z_OK)
+		/* nothing */;
+
+	stream.next_in = buf;
+	stream.avail_in = buf_len;
+	/* Compress it */
+	while ((ret = deflate(&stream, Z_FINISH)) == Z_OK)
+		/* nothing */;
+	ret = deflateEnd(&stream);
+	size = stream.total_out;
+	*compsize = size;
+	return compressed;
+}
+
+int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+		     unsigned char *returnsha1,
+		     unsigned char *refsha1,
+		     struct packed_item **packed_item)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	struct stat st;
+	char *compressed = NULL;
+	unsigned long size;
+	struct packed_item *item;
+	char *metadata = xmalloc(200);
+	int metadata_size;
+	int delta = 0;
+
+	*packed_item = NULL;
+
+	metadata_size = 1 + sprintf(metadata, "%s %lu", type, buf_len);
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, buf, buf_len);
+	SHA1_Final(sha1, &c);
+
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+
+	filename = sha1_file_name(sha1);
+	if (stat(filename, &st) == 0)
+		goto out;
+
+	
+	if (refsha1) {
+		compressed = pack_delta_buffer(buf, buf_len, metadata, metadata_size, &size, refsha1);
+		delta = (compressed != NULL);
+	}
+	if (!compressed) {
+		compressed = pack_buffer(buf, buf_len, metadata, metadata_size, &size);
+	}
+	free(metadata);
+	if (!compressed) {
+		return -1;
+	}
+	item = xmalloc(sizeof(struct packed_item));
+	memcpy(item->sha1, sha1, 20);
+	if (delta) {
+		strcpy(item->type, "delta");
+		memcpy(item->refsha1, refsha1, 20);
+	} else {
+		strcpy(item->type, type);
+		memset(item->refsha1, 0, 20);
+	}
+	item->len = size;
+	item->next = NULL;
+	item->data = compressed;
+	*packed_item = item;
+out:
+	return 0;
+}
+
+static char *create_packed_header(struct packed_item *head, unsigned long *size)
+{
+	char *metadata = NULL;
+	int metadata_size = 0;
+	*size = 0;
+	int entry_size = 0;
+
+	while(head) {
+		char *p;
+		metadata = realloc(metadata, metadata_size + 220);
+		if (!metadata)
+			return NULL;
+		p = metadata+metadata_size;
+		memcpy(p, head->sha1, 20);
+		p += 20;
+		entry_size = 1 + sprintf(p, "%s %lu", head->type, head->len);
+		metadata_size += entry_size + 20;
+		if (strcmp(head->type, "delta") == 0) {
+			memcpy(p + entry_size, head->refsha1, 20);
+			metadata_size += 20;
+		}
+
+		head = head->next;
+	}
+	*size = metadata_size;
+	return metadata;
+}
+
+#define WRITE_BUFFER_SIZE 8192
+static char write_buffer[WRITE_BUFFER_SIZE];
+static unsigned long write_buffer_len;
+
+static int c_write(int fd, void *data, unsigned int len)
+{
+	while (len) {
+		unsigned int buffered = write_buffer_len;
+		unsigned int partial = WRITE_BUFFER_SIZE - buffered;
+		if (partial > len)
+			partial = len;
+		memcpy(write_buffer + buffered, data, partial);
+		buffered += partial;
+		if (buffered == WRITE_BUFFER_SIZE) {
+			if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
+				return -1;
+			buffered = 0;
+		}
+		write_buffer_len = buffered;
+		len -= partial;
+		data += partial;
+ 	}
+ 	return 0;
+}
+
+static int c_flush(int fd)
+{
+	if (write_buffer_len) {
+		int left = write_buffer_len;
+		if (write(fd, write_buffer, left) != left)
+			return -1;
+		write_buffer_len = 0;
+	}
+	return 0;
+}
+int write_packed_buffer(struct packed_item *head)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	char *metadata = xmalloc(200);
+	char *header;
+	int metadata_size;
+	int fd;
+	int ret = 0;
+	unsigned long header_len;
+	struct packed_item *item;
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+	int zdret;
+
+	header = create_packed_header(head, &header_len);
+	metadata_size = 1+sprintf(metadata, "packed %lu", header_len);
+	/* 
+	 * the header contains the sha1 of each item, so we only sha1 the
+	 * header
+	 */ 
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, header, header_len);
+	SHA1_Final(sha1, &c);
+
+	filename = strdup(sha1_file_name(sha1));
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		/* add collision check! */
+		if (errno != EEXIST) {
+			ret = -errno;
+		}
+		goto out_nofile;
+	}
+       /* compress just the header info */
+        memset(&stream, 0, sizeof(stream));
+        deflateInit(&stream, Z_BEST_COMPRESSION);
+	/* TODO, bounds check */
+	size = header_len + metadata_size + 12;
+        compressed = xmalloc(size);
+
+        stream.next_in = metadata;
+        stream.avail_in = metadata_size;
+        stream.next_out = compressed;
+        stream.avail_out = size;
+        while ((zdret = deflate(&stream, 0)) == Z_OK)
+                /* nothing */;
+        stream.next_in = header;
+        stream.avail_in = header_len;
+        while ((zdret = deflate(&stream, Z_FINISH)) == Z_OK)
+                /* nothing */;
+        zdret = deflateEnd(&stream);
+        size = stream.total_out;
+
+	c_write(fd, compressed, size);
+	free(compressed);
+
+	item = head;
+	while(item) {
+		if (c_write(fd, item->data, item->len)) {
+			ret = -EIO;
+			goto out;
+		}
+		item = item->next;
+	}
+	if (c_flush(fd)) {
+		ret = -EIO;
+		goto out;
+	}
+	item = head;
+	while(item) {
+		char *item_file;
+		struct packed_item *next = item->next;
+		item_file = sha1_file_name(item->sha1);
+		if (link(filename, item_file) && errno != EEXIST) {
+			ret = -errno;
+			break;
+		}
+		free(item->data);
+		free(item);
+		item = next;
+	}
+	unlink(filename);
+out:
+	close(fd);
+out_nofile:
+	free(header);
+	free(metadata);
+	free(filename);
+	return ret;
+}
Index: update-cache.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/update-cache.c  (mode:100644 sha1:16e1bb9aea6413db35039042289605124d759501)
+++ uncommitted/update-cache.c  (mode:100644)
@@ -31,55 +31,39 @@
 	return (unsigned long)ptr > (unsigned long)-1000L;
 }
 
-static int index_fd(unsigned char *sha1, int fd, struct stat *st)
+static int index_fd(unsigned char *sha1, unsigned char *refsha1, int fd, struct stat *st, struct packed_item **head, struct packed_item **tail, unsigned long *packed_size, int *packed_nr)
 {
-	z_stream stream;
 	unsigned long size = st->st_size;
-	int max_out_bytes = size + 200;
-	void *out = xmalloc(max_out_bytes);
-	void *metadata = xmalloc(200);
-	int metadata_size;
 	void *in;
-	SHA_CTX c;
+	int ret;
+	struct packed_item *new_item;
 
 	in = "";
 	if (size)
 		in = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (!out || (int)(long)in == -1)
+	if ((int)(long)in == -1) {
 		return -1;
-
-	metadata_size = 1+sprintf(metadata, "blob %lu", size);
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, metadata, metadata_size);
-	SHA1_Update(&c, in, size);
-	SHA1_Final(sha1, &c);
-
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
-
-	/*
-	 * ASCII size + nul byte
-	 */	
-	stream.next_in = metadata;
-	stream.avail_in = metadata_size;
-	stream.next_out = out;
-	stream.avail_out = max_out_bytes;
-	while (deflate(&stream, 0) == Z_OK)
-		/* nothing */;
-
-	/*
-	 * File content
-	 */
-	stream.next_in = in;
-	stream.avail_in = size;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/*nothing */;
-
-	deflateEnd(&stream);
-	
-	return write_sha1_buffer(sha1, out, stream.total_out);
+	}
+	ret = pack_sha1_buffer(in, size, "blob", sha1, refsha1, &new_item);
+	if (new_item) {
+		if (*tail)
+			(*tail)->next = new_item;
+		*tail = new_item;
+		if (!*head)
+			*head = new_item;
+		*packed_size += new_item->len;
+		*packed_nr++;
+		if (*packed_size > (512 * 1024) || *packed_nr > 1024) {
+			write_packed_buffer(*head);
+			*head = NULL;
+			*tail = NULL;
+			*packed_size = 0;
+			*packed_nr = 0;
+		}
+	}
+	munmap(in, size);
+	return ret;
 }
 
 /*
@@ -102,12 +86,14 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(char *path, struct packed_item **packed_head, struct packed_item **packed_tail, unsigned long *packed_size, int *packed_nr)
 {
 	int size, namelen;
 	struct cache_entry *ce;
 	struct stat st;
 	int fd;
+	int pos;
+	unsigned char *refsha1 = NULL;
 
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
@@ -129,8 +115,12 @@
 	fill_stat_cache_info(ce, &st);
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
+	pos = cache_name_pos(ce->name, namelen);
+	if (pos >= 0)
+		refsha1 = active_cache[pos]->sha1;
 
-	if (index_fd(ce->sha1, fd, &st) < 0)
+	if (index_fd(ce->sha1, refsha1, fd, &st, packed_head, 
+		     packed_tail, packed_size, packed_nr) < 0)
 		return -1;
 
 	return add_cache_entry(ce, allow_add);
@@ -311,6 +301,10 @@
 	int allow_options = 1;
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct packed_item *packed_head = NULL;
+	struct packed_item *packed_tail = NULL;
+	unsigned long packed_size = 0;
+	int packed_nr = 0;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -362,8 +356,13 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(path, &packed_head, &packed_tail, &packed_size, &packed_nr))
 			die("Unable to add %s to database", path);
+
+	}
+	if (packed_head) {
+		if (write_packed_buffer(packed_head))
+			die("write packed buffer failed");
 	}
 	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
 		die("Unable to write new cachefile");
Index: write-tree.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/write-tree.c  (mode:100644 sha1:168352853d37bdca71d68ad8312b87b84477dea1)
+++ uncommitted/write-tree.c  (mode:100644)
@@ -5,24 +5,13 @@
  */
 #include "cache.h"
 
-static int check_valid_sha1(unsigned char *sha1)
-{
-	char *filename = sha1_file_name(sha1);
-	int ret;
-
-	/* If we were anal, we'd check that the sha1 of the contents actually matches */
-	ret = access(filename, R_OK);
-	if (ret)
-		perror(filename);
-	return ret;
-}
-
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1, struct packed_item **head)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
 	char *buffer;
 	int nr;
+	struct packed_item *item;
 
 	/* Guess at some random initial size */
 	size = 8192;
@@ -50,7 +39,7 @@
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1, head);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -62,9 +51,6 @@
 			sha1 = subdir_sha1;
 		}
 
-		if (check_valid_sha1(sha1) < 0)
-			exit(1);
-
 		entrylen = pathlen - baselen;
 		if (offset + entrylen + 100 > size) {
 			size = alloc_nr(offset + entrylen + 100);
@@ -77,7 +63,11 @@
 		nr++;
 	} while (nr < maxentries);
 
-	write_sha1_file(buffer, offset, "tree", returnsha1);
+	pack_sha1_buffer(buffer, offset, "tree", returnsha1, NULL, &item);
+	if (item) {
+		item->next = *head;
+		*head = item;
+	}
 	free(buffer);
 	return nr;
 }
@@ -87,6 +77,7 @@
 	int i, unmerged;
 	int entries = read_cache();
 	unsigned char sha1[20];
+	struct packed_item *head = NULL;
 
 	if (entries <= 0)
 		die("write-tree: no cache contents to write");
@@ -107,8 +98,12 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(active_cache, entries, "", 0, sha1, &head) != entries)
 		die("write-tree: internal error");
+	if (head) {
+		if (write_packed_buffer(head))
+			die("write_packed_buffer error");
+	}
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;
 }

^ permalink raw reply	[relevance 17%]

* [PATCH] Careful object pulling
  @ 2005-05-04  4:07 18% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-05-04  4:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List

This splits out the careful methods for writing a file and placing it in
the correct location from the function to write a buffer to the file and
makes the various functions used by git-*-pull programs use those
functions to write their files.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Index: cache.h
===================================================================
--- 51a882a2dc62e0d3cdc79e0badc61559fb723481/cache.h  (mode:100644 sha1:8dd812827604d510038f5d93e3718c43f9d12c30)
+++ 4e31436bacfff09ce673665a1061b41e37ffd661/cache.h  (mode:100644 sha1:0d7411c3b86a899cee45627997f4bb7ba0df2ea7)
@@ -134,6 +134,12 @@
 extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
 extern int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 
+/* Open a file for writing a sha1 file. */
+extern int open_sha1_tmpfile(char tmpfile[PATH_MAX]);
+
+/* Put a sha1 file in the correct place. */
+extern int place_sha1_file(char tmpfile[PATH_MAX], const unsigned char *sha1);
+
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
 /* Read a tree into the cache */
Index: http-pull.c
===================================================================
--- 51a882a2dc62e0d3cdc79e0badc61559fb723481/http-pull.c  (mode:100644 sha1:f693aba61b4dcb4b738faf1335ec74aa1545e45d)
+++ 4e31436bacfff09ce673665a1061b41e37ffd661/http-pull.c  (mode:100644 sha1:793d8b9e125c1f164f774e2888d26beaa75e1df0)
@@ -52,8 +52,9 @@
 	char real_sha1[20];
 	char *url;
 	char *posn;
+	char tmpname[PATH_MAX];
 
-	local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	local = open_sha1_tmpfile(tmpname);
 
 	if (local < 0)
 		return error("Couldn't open %s\n", filename);
@@ -88,15 +89,14 @@
 	inflateEnd(&stream);
 	SHA1_Final(real_sha1, &c);
 	if (zret != Z_STREAM_END) {
-		unlink(filename);
+		unlink(tmpname);
 		return error("File %s (%s) corrupt\n", hex, url);
 	}
 	if (memcmp(sha1, real_sha1, 20)) {
-		unlink(filename);
+		unlink(tmpname);
 		return error("File %s has bad hash\n", hex);
 	}
-	
-	return 0;
+	return place_sha1_file(tmpname, sha1);
 }
 
 int main(int argc, char **argv)
Index: sha1_file.c
===================================================================
--- 51a882a2dc62e0d3cdc79e0badc61559fb723481/sha1_file.c  (mode:100644 sha1:e6ce455ae90bd430f2128f454bdb6e0575412486)
+++ 4e31436bacfff09ce673665a1061b41e37ffd661/sha1_file.c  (mode:100644 sha1:85daa0b0045c3f19e697d1a7aa8ab15ff54eab99)
@@ -276,6 +276,55 @@
 	}
 }
 
+int open_sha1_tmpfile(char tmpfile[PATH_MAX])
+{
+	int fd;
+
+	snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
+	fd = mkstemp(tmpfile);
+	if (fd < 0) {
+		fprintf(stderr,
+			"unable to create temporary sha1 filename %s: %s",
+			tmpfile, strerror(errno));
+		return -1;
+	}
+	return fd;
+}
+
+int place_sha1_file(char tmpfile[PATH_MAX], const unsigned char *sha1)
+{
+	char *filename = sha1_file_name(sha1);
+	int ret;
+
+	ret = link(tmpfile, filename);
+	if (ret < 0) {
+		ret = errno;
+
+		/*
+		 * Coda hack - coda doesn't like cross-directory links,
+		 * so we fall back to a rename, which will mean that it
+		 * won't be able to check collisions, but that's not a
+		 * big deal.
+		 *
+		 * When this succeeds, we just return 0. We have nothing
+		 * left to unlink.
+		 */
+		if (ret == EXDEV && !rename(tmpfile, filename))
+			return 0;
+	}
+	unlink(tmpfile);
+	if (ret) {
+		if (ret != EEXIST) {
+			fprintf(stderr,
+				"unable to write sha1 filename %s: %s", 
+				filename, strerror(ret));
+			return -1;
+		}
+		/* FIXME!!! Collision check here ? */
+	}
+	return 0;
+}
+
 int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
 	int size;
@@ -286,7 +335,7 @@
 	char *filename;
 	static char tmpfile[PATH_MAX];
 	char hdr[50];
-	int fd, hdrlen, ret;
+	int fd, hdrlen;
 
 	/* Generate the header */
 	hdrlen = sprintf(hdr, "%s %lu", type, len)+1;
@@ -316,12 +365,9 @@
 		return -1;
 	}
 
-	snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
-	fd = mkstemp(tmpfile);
-	if (fd < 0) {
-		fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
-		return -1;
-	}
+	fd = open_sha1_tmpfile(tmpfile);
+	if (fd < 0)
+		return fd;
 
 	/* Set it up */
 	memset(&stream, 0, sizeof(stream));
@@ -349,53 +395,28 @@
 
 	if (write(fd, compressed, size) != size)
 		die("unable to write file");
+
 	fchmod(fd, 0444);
 	close(fd);
 
-	ret = link(tmpfile, filename);
-	if (ret < 0) {
-		ret = errno;
-
-		/*
-		 * Coda hack - coda doesn't like cross-directory links,
-		 * so we fall back to a rename, which will mean that it
-		 * won't be able to check collisions, but that's not a
-		 * big deal.
-		 *
-		 * When this succeeds, we just return 0. We have nothing
-		 * left to unlink.
-		 */
-		if (ret == EXDEV && !rename(tmpfile, filename))
-			return 0;
-	}
-	unlink(tmpfile);
-	if (ret) {
-		if (ret != EEXIST) {
-			fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
-			return -1;
-		}
-		/* FIXME!!! Collision check here ? */
-	}
-
-	return 0;
+	return place_sha1_file(tmpfile, sha1);
 }
 
 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];
+	char tmpname[PATH_MAX];
 	int ret;
 	SHA_CTX c;
 
-	local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	local = open_sha1_tmpfile(tmpname);
 
 	if (local < 0)
-		return error("Couldn't open %s\n", filename);
+		return -1;
 
 	memset(&stream, 0, sizeof(stream));
 
@@ -408,7 +429,7 @@
 		size = read(fd, buf, 4096);
 		if (size <= 0) {
 			close(local);
-			unlink(filename);
+			unlink(tmpname);
 			if (!size)
 				return error("Connection closed?");
 			perror("Reading from connection");
@@ -431,15 +452,15 @@
 	close(local);
 	SHA1_Final(real_sha1, &c);
 	if (ret != Z_STREAM_END) {
-		unlink(filename);
+		unlink(tmpname);
 		return error("File %s corrupted", sha1_to_hex(sha1));
 	}
 	if (memcmp(sha1, real_sha1, 20)) {
-		unlink(filename);
+		unlink(tmpname);
 		return error("File %s has bad hash\n", sha1_to_hex(sha1));
 	}
-	
-	return 0;
+
+	return place_sha1_file(tmpname, sha1);
 }
 
 int has_sha1_file(const unsigned char *sha1)


^ permalink raw reply	[relevance 18%]

* Re: [PATCH] add the ability to create and retrieve delta objects
  @ 2005-05-04 15:56 17%     ` Chris Mason
  0 siblings, 0 replies; 200+ results
From: Chris Mason @ 2005-05-04 15:56 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Linus Torvalds, Alon Ziv, git

[-- Attachment #1: Type: text/plain, Size: 2655 bytes --]

On Tuesday 03 May 2005 04:06, Nicolas Pitre wrote:
> On Mon, 2 May 2005, Linus Torvalds wrote:
> > If you do something like this, you want such a delta-blob to be named by
> > the sha1 of the result, so that things that refer to it can transparently
> > see either the original blob _or_ the "deltified" one, and will never
> > care.
>
> Yep, that's what I've done last weekend (and just made it actually
> work since people are getting interested).
>

My first run didn't go well, diff_delta generates an invalid delta when passed 
a buffer of length 0.  I really should not have been calling it this way, but 
it should do a quick check and return an error instead of something 
invalid ;)

I did two additional runs, first where I fixed the delta chain length at 1 as 
in the zdelta patch.   In this mode, if it tried to diff against a delta it 
would find the delta's parent and diff against that instead.  Even though 
zdelta had the same speeds for applying patches as xdiff(1), zdelta used 
significantly more cpu (53m vs 40m).

The next run was with the patch I've attached below, it allows chains up to 16 
deltas in length.  
                             git         zdelta       xdiff (1)      xdiff(16)
apply                  150m       117m       117m         104m
checkout             4m30s      3m41      4m43s        7m11s
checkout (hot)     56s           12s         14s             16s
space usage        2.5G         1G           1.2G           800m

The longer delta chains trigger more random io on checkout, negating the speed 
improvements from the packed item patch.  The hot cache times show that xdiff 
isn't using a huge amount of cpu to patch things in, and so there's room for 
smarter packing and regenerating deltas in order to keep checkout times low.  
This patch still doesn't pack commits and trees in with the blob files, and 
it doesn't delta trees, and so I expect better space/speed numbers in later 
revs.

I won't be able to work on this until next week, but here's my plan:

1) update to current git.  My patch is from before the safe file generation 
changes.

2) change update-cache and write-tree so that packing/deltas are off by 
default.  Add --packed and --delta options to both.

3) create a git-pack tool that can pack/unpack existing changesets,trees and 
files, optionally adding/removing deltas.

My current code should preserve the delta object header used by Nicolas, and 
removes all knowledge of deltas from the packed item headers.  This is not 
quite as efficient, but the resulting code is much cleaner.  I haven't tried, 
but it should be able to read a file created by his mkdelta.c.

-chris

[-- Attachment #2: delta-tree-3.diff --]
[-- Type: text/x-diff, Size: 32177 bytes --]

diff -urN --exclude .git linus.diff/cache.h linus.mine/cache.h
--- linus.diff/cache.h	2005-05-04 09:54:49.154735216 -0400
+++ linus.mine/cache.h	2005-05-04 08:47:28.618990016 -0400
@@ -64,6 +64,16 @@
 	char name[0];
 };
 
+struct packed_item {
+	/* length of compressed data */
+	unsigned long len;
+	struct packed_item *next;
+	/* sha1 of uncompressed data */
+	char sha1[20];
+	/* compressed data */
+	char *data;
+};
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
@@ -119,8 +129,9 @@
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
+extern void * unpack_sha1_file(const unsigned char *sha1, void *map, unsigned long mapsize, char *type, unsigned long *size, int *chain);
 extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
+extern void * read_sha1_delta_ref(const unsigned char *sha1, char *type, unsigned long *size, int *chain);
 extern int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
@@ -135,6 +146,10 @@
 /* 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! */
+extern int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+                            unsigned char *returnsha1, unsigned char *refsha1, 
+			    struct packed_item **);
+int write_packed_buffer(struct packed_item *head);
 
 /* General helper functions */
 extern void usage(const char *err);
diff -urN --exclude .git linus.diff/delta.h linus.mine/delta.h
--- linus.diff/delta.h	1969-12-31 19:00:00.000000000 -0500
+++ linus.mine/delta.h	2005-05-03 08:22:32.000000000 -0400
@@ -0,0 +1,6 @@
+extern void *diff_delta(void *from_buf, unsigned long from_size,
+			void *to_buf, unsigned long to_size,
+		        unsigned long *delta_size);
+extern void *patch_delta(void *src_buf, unsigned long src_size,
+			 void *delta_buf, unsigned long delta_size,
+			 unsigned long *dst_size);
diff -urN --exclude .git linus.diff/diff-delta.c linus.mine/diff-delta.c
--- linus.diff/diff-delta.c	1969-12-31 19:00:00.000000000 -0500
+++ linus.mine/diff-delta.c	2005-05-03 12:40:58.000000000 -0400
@@ -0,0 +1,315 @@
+/*
+ * diff-delta.c: generate a delta between two buffers
+ *
+ *  Many parts of this file have been lifted from LibXDiff version 0.10.
+ *  http://www.xmailserver.org/xdiff-lib.html
+ *
+ *  LibXDiff was written by Davide Libenzi <davidel@xmailserver.org>
+ *  Copyright (C) 2003	Davide Libenzi
+ *
+ *  Many mods for GIT usage by Nicolas Pitre <nico@cam.org>, (C) 2005.
+ *
+ *  This file is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include "delta.h"
+
+
+/* block size: min = 16, max = 64k, power of 2 */
+#define BLK_SIZE 16
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#define GR_PRIME 0x9e370001
+#define HASH(v, b) (((unsigned int)(v) * GR_PRIME) >> (32 - (b)))
+	
+/* largest prime smaller than 65536 */
+#define BASE 65521
+
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+#define NMAX 5552
+
+#define DO1(buf, i)  { s1 += buf[i]; s2 += s1; }
+#define DO2(buf, i)  DO1(buf, i); DO1(buf, i + 1);
+#define DO4(buf, i)  DO2(buf, i); DO2(buf, i + 2);
+#define DO8(buf, i)  DO4(buf, i); DO4(buf, i + 4);
+#define DO16(buf)    DO8(buf, 0); DO8(buf, 8);
+
+static unsigned int adler32(unsigned int adler, const unsigned char *buf, int len)
+{
+	int k;
+	unsigned int s1 = adler & 0xffff;
+	unsigned int s2 = adler >> 16;
+
+	while (len > 0) {
+		k = MIN(len, NMAX);
+		len -= k;
+		while (k >= 16) {
+			DO16(buf);
+			buf += 16;
+			k -= 16;
+		}
+		if (k != 0)
+			do {
+				s1 += *buf++;
+				s2 += s1;
+			} while (--k);
+		s1 %= BASE;
+		s2 %= BASE;
+	}
+
+	return (s2 << 16) | s1;
+}
+
+static unsigned int hashbits(unsigned int size)
+{
+	unsigned int val = 1, bits = 0;
+	while (val < size && bits < 32) {
+		val <<= 1;
+	       	bits++;
+	}
+	return bits ? bits: 1;
+}
+
+typedef struct s_chanode {
+	struct s_chanode *next;
+	int icurr;
+} chanode_t;
+
+typedef struct s_chastore {
+	chanode_t *head, *tail;
+	int isize, nsize;
+	chanode_t *ancur;
+	chanode_t *sncur;
+	int scurr;
+} chastore_t;
+
+static void cha_init(chastore_t *cha, int isize, int icount)
+{
+	cha->head = cha->tail = NULL;
+	cha->isize = isize;
+	cha->nsize = icount * isize;
+	cha->ancur = cha->sncur = NULL;
+	cha->scurr = 0;
+}
+
+static void *cha_alloc(chastore_t *cha)
+{
+	chanode_t *ancur;
+	void *data;
+
+	ancur = cha->ancur;
+	if (!ancur || ancur->icurr == cha->nsize) {
+		ancur = malloc(sizeof(chanode_t) + cha->nsize);
+		if (!ancur)
+			return NULL;
+		ancur->icurr = 0;
+		ancur->next = NULL;
+		if (cha->tail)
+			cha->tail->next = ancur;
+		if (!cha->head)
+			cha->head = ancur;
+		cha->tail = ancur;
+		cha->ancur = ancur;
+	}
+
+	data = (void *)ancur + sizeof(chanode_t) + ancur->icurr;
+	ancur->icurr += cha->isize;
+	return data;
+}
+
+static void cha_free(chastore_t *cha)
+{
+	chanode_t *cur = cha->head;
+	while (cur) {
+		chanode_t *tmp = cur;
+		cur = cur->next;
+		free(tmp);
+	}
+}
+
+typedef struct s_bdrecord {
+	struct s_bdrecord *next;
+	unsigned int fp;
+	const unsigned char *ptr;
+} bdrecord_t;
+
+typedef struct s_bdfile {
+	const unsigned char *data, *top;
+	chastore_t cha;
+	unsigned int fphbits;
+	bdrecord_t **fphash;
+} bdfile_t;
+
+static int delta_prepare(const unsigned char *buf, int bufsize, bdfile_t *bdf)
+{
+	unsigned int fphbits;
+	int i, hsize;
+	const unsigned char *base, *data, *top;
+	bdrecord_t *brec;
+	bdrecord_t **fphash;
+
+	fphbits = hashbits(bufsize / BLK_SIZE + 1);
+	hsize = 1 << fphbits;
+	fphash = malloc(hsize * sizeof(bdrecord_t *));
+	if (!fphash)
+		return -1;
+	for (i = 0; i < hsize; i++)
+		fphash[i] = NULL;
+	cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1);
+
+	bdf->data = data = base = buf;
+	bdf->top = top = buf + bufsize;
+	data += (bufsize / BLK_SIZE) * BLK_SIZE;
+	if (data == top)
+		data -= BLK_SIZE;
+
+	for ( ; data >= base; data -= BLK_SIZE) {
+		brec = cha_alloc(&bdf->cha);
+		if (!brec) {
+			cha_free(&bdf->cha);
+			free(fphash);
+			return -1;
+		}
+		brec->fp = adler32(0, data, MIN(BLK_SIZE, top - data));
+		brec->ptr = data;
+		i = HASH(brec->fp, fphbits);
+		brec->next = fphash[i];
+		fphash[i] = brec;
+	}
+
+	bdf->fphbits = fphbits;
+	bdf->fphash = fphash;
+
+	return 0;
+}
+
+static void delta_cleanup(bdfile_t *bdf)
+{
+	free(bdf->fphash);
+	cha_free(&bdf->cha);
+}
+
+#define COPYOP_SIZE(o, s) \
+    (!!(o & 0xff) + !!(o & 0xff00) + !!(o & 0xff0000) + !!(o & 0xff000000) + \
+     !!(s & 0xff) + !!(s & 0xff00) + 1)
+
+void *diff_delta(void *from_buf, unsigned long from_size,
+		 void *to_buf, unsigned long to_size,
+		 unsigned long *delta_size)
+{
+	int i, outpos, outsize, inscnt, csize, msize, moff;
+	unsigned int fp;
+	const unsigned char *data, *top, *ptr1, *ptr2;
+	unsigned char *out, *orig;
+	bdrecord_t *brec;
+	bdfile_t bdf;
+
+	if (delta_prepare(from_buf, from_size, &bdf))
+		return NULL;
+	
+	outpos = 0;
+	outsize = 4096;
+	out = malloc(outsize);
+	if (!out) {
+		delta_cleanup(&bdf);
+		return NULL;
+	}
+
+	data = to_buf;
+	top = to_buf + to_size;
+
+	out[outpos++] = from_size; from_size >>= 8;
+	out[outpos++] = from_size; from_size >>= 8;
+	out[outpos++] = from_size; from_size >>= 8;
+	out[outpos++] = from_size;
+	out[outpos++] = to_size; to_size >>= 8;
+	out[outpos++] = to_size; to_size >>= 8;
+	out[outpos++] = to_size; to_size >>= 8;
+	out[outpos++] = to_size;
+
+	inscnt = 0;
+	moff = 0;
+	while (data < top) {
+		msize = 0;
+		fp = adler32(0, data, MIN(top - data, BLK_SIZE));
+		i = HASH(fp, bdf.fphbits);
+		for (brec = bdf.fphash[i]; brec; brec = brec->next) {
+			if (brec->fp == fp) {
+				csize = bdf.top - brec->ptr;
+				if (csize > top - data)
+					csize = top - data;
+				for (ptr1 = brec->ptr, ptr2 = data; 
+				     csize && *ptr1 == *ptr2;
+				     csize--, ptr1++, ptr2++);
+
+				csize = ptr1 - brec->ptr;
+				if (csize > msize) {
+					moff = brec->ptr - bdf.data;
+					msize = csize;
+					if (msize >= 0x10000) {
+						msize = 0x10000;
+						break;
+					}
+				}
+			}
+		}
+
+		if (!msize || msize < COPYOP_SIZE(moff, msize)) {
+			if (!inscnt)
+				outpos++;
+			out[outpos++] = *data++;
+			inscnt++;
+			if (inscnt == 0x7f) {
+				out[outpos - inscnt - 1] = inscnt;
+				inscnt = 0;
+			}
+		} else {
+			if (inscnt) {
+				out[outpos - inscnt - 1] = inscnt;
+				inscnt = 0;
+			}
+
+			data += msize;
+			orig = out + outpos++;
+			i = 0x80;
+
+			if (moff & 0xff) { out[outpos++] = moff; i |= 0x01; }
+			moff >>= 8;
+			if (moff & 0xff) { out[outpos++] = moff; i |= 0x02; }
+			moff >>= 8;
+			if (moff & 0xff) { out[outpos++] = moff; i |= 0x04; }
+			moff >>= 8;
+			if (moff & 0xff) { out[outpos++] = moff; i |= 0x08; }
+
+			if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; }
+			msize >>= 8;
+			if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; }
+
+			*orig = i;
+		}
+
+		/* next time around the largest possible output is 1 + 4 + 3 */
+		if (outpos > outsize - 8) {
+			void *tmp = out;
+			outsize = outsize * 3 / 2;
+			out = realloc(out, outsize);
+			if (!out) {
+				free(tmp);
+				delta_cleanup(&bdf);
+				return NULL;
+			}
+		}
+	}
+
+	if (inscnt)
+		out[outpos - inscnt - 1] = inscnt;
+
+	delta_cleanup(&bdf);
+	*delta_size = outpos;
+	return out;
+}
diff -urN --exclude .git linus.diff/fsck-cache.c linus.mine/fsck-cache.c
--- linus.diff/fsck-cache.c	2005-05-04 09:54:49.158734608 -0400
+++ linus.mine/fsck-cache.c	2005-05-04 08:44:49.778137496 -0400
@@ -142,7 +142,7 @@
 		if (map) {
 			char type[100];
 			unsigned long size;
-			void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+			void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size, NULL);
 			if (!buffer)
 				return -1;
 			if (check_sha1_signature(sha1, buffer, size, type) < 0)
diff -urN --exclude .git linus.diff/git-mktag.c linus.mine/git-mktag.c
--- linus.diff/git-mktag.c	2005-05-04 09:54:49.158734608 -0400
+++ linus.mine/git-mktag.c	2005-05-04 08:45:04.763859320 -0400
@@ -31,7 +31,7 @@
 	if (map) {
 		char type[100];
 		unsigned long size;
-		void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+		void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size, NULL);
 
 		if (buffer) {
 			if (!strcmp(type, expected_type))
diff -urN --exclude .git linus.diff/Makefile linus.mine/Makefile
--- linus.diff/Makefile	2005-05-04 09:54:49.153735368 -0400
+++ linus.mine/Makefile	2005-05-03 16:28:15.000000000 -0400
@@ -25,7 +25,8 @@
 install: $(PROG) $(SCRIPTS)
 	install $(PROG) $(SCRIPTS) $(HOME)/bin/
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o diff-delta.o \
+	 patch-delta.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h
 
diff -urN --exclude .git linus.diff/patch-delta.c linus.mine/patch-delta.c
--- linus.diff/patch-delta.c	1969-12-31 19:00:00.000000000 -0500
+++ linus.mine/patch-delta.c	2005-05-04 09:57:53.520707328 -0400
@@ -0,0 +1,80 @@
+/*
+ * patch-delta.c:
+ * recreate a buffer from a source and the delta produced by diff-delta.c
+ *
+ * (C) 2005 Nicolas Pitre <nico@cam.org>
+ *
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "delta.h"
+
+void *patch_delta(void *src_buf, unsigned long src_size,
+		  void *delta_buf, unsigned long delta_size,
+		  unsigned long *dst_size)
+{
+	const unsigned char *data, *top;
+	unsigned char *dst, *out;
+	int size;
+
+	/* the smallest delta size possible is 10 bytes */
+	if (delta_size < 10) {
+		return NULL;
+	}
+	data = delta_buf;
+	top = delta_buf + delta_size;
+
+	/* make sure the orig file size matches what we expect */
+	size = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+	data += 4;
+	if (size != src_size) {
+		return NULL;
+	}
+	/* now the result size */
+	size = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+	data += 4;
+	dst = malloc(size);
+	if (!dst) {
+		return NULL;
+	}
+	out = dst;
+	while (data < top) {
+		unsigned char cmd = *data++;
+		if (cmd & 0x80) {
+			unsigned int cp_off = 0, cp_size = 0;
+			if (cmd & 0x01) cp_off = *data++;
+			if (cmd & 0x02) cp_off |= (*data++ << 8);
+			if (cmd & 0x04) cp_off |= (*data++ << 16);
+			if (cmd & 0x08) cp_off |= (*data++ << 24);
+			if (cmd & 0x10) cp_size = *data++;
+			if (cmd & 0x20) cp_size |= (*data++ << 8);
+			if (cp_size == 0) cp_size = 0x10000;
+			memcpy(out, src_buf + cp_off, cp_size);
+			out += cp_size;
+			if (out > dst + size) {
+				*(char *)0 = 0;
+			}
+		} else {
+			memcpy(out, data, cmd);
+			out += cmd;
+			data += cmd;
+			if (out > dst + size) {
+				*(char *)0 = 0;
+			}
+		}
+	}
+
+	/* sanity check */
+	if (data != top || out - dst != size) {
+		free(dst);
+		return NULL;
+	}
+
+	*dst_size = size;
+	return dst;
+}
diff -urN --exclude .git linus.diff/sha1_file.c linus.mine/sha1_file.c
--- linus.diff/sha1_file.c	2005-05-04 09:54:49.165733544 -0400
+++ linus.mine/sha1_file.c	2005-05-04 10:42:07.002316808 -0400
@@ -8,6 +8,7 @@
  */
 #include <stdarg.h>
 #include "cache.h"
+#include "delta.h"
 
 const char *sha1_file_directory = NULL;
 
@@ -139,39 +140,117 @@
 	return map;
 }
 
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+/*
+ * looks through buf for the header entry corresponding to sha1.  returns
+ * 0 an entry is found and sets offset to the offset of the packed item
+ * in the file.  The offset is relative to the start of the packed items
+ * so you have to add in the length of the header before using it
+ * -1 is returned if the sha1 could not be found
+ */
+static int find_packed_header(const unsigned char *sha1, char *buf, unsigned long buf_len, unsigned long *offset)
+{
+	char *p;
+	p = buf;
+
+	*offset = 0;
+	while(p < buf + buf_len) {
+		unsigned long item_len;
+		unsigned char item_sha[20];
+		memcpy(item_sha, p, 20);
+		sscanf(p + 20, "%lu", &item_len);
+		p += 20 + strlen(p + 20) + 1;
+		if (memcmp(item_sha, sha1, 20) == 0)
+			return 0;
+		*offset += item_len;
+	}
+	return -1;
+}
+
+
+/*
+ * uncompresses a data segment without any extra delta/packed processing
+ */
+static void * _unpack_sha1_file(z_stream *stream, void *map, 
+                                unsigned long mapsize, char *type, 
+				unsigned long *size)
 {
 	int ret, bytes;
-	z_stream stream;
 	char buffer[8192];
 	char *buf;
 
 	/* Get the data stream */
-	memset(&stream, 0, sizeof(stream));
-	stream.next_in = map;
-	stream.avail_in = mapsize;
-	stream.next_out = buffer;
-	stream.avail_out = sizeof(buffer);
-
-	inflateInit(&stream);
-	ret = inflate(&stream, 0);
-	if (ret < Z_OK)
+	memset(stream, 0, sizeof(*stream));
+	stream->next_in = map;
+	stream->avail_in = mapsize;
+	stream->next_out = buffer;
+	stream->avail_out = sizeof(buffer);
+
+	inflateInit(stream);
+	ret = inflate(stream, 0);
+	if (ret < Z_OK) {
 		return NULL;
-	if (sscanf(buffer, "%10s %lu", type, size) != 2)
+	}
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
 		return NULL;
-
+	}
 	bytes = strlen(buffer) + 1;
 	buf = xmalloc(*size);
 
-	memcpy(buf, buffer + bytes, stream.total_out - bytes);
-	bytes = stream.total_out - bytes;
+	memcpy(buf, buffer + bytes, stream->total_out - bytes);
+	bytes = stream->total_out - bytes;
 	if (bytes < *size && ret == Z_OK) {
-		stream.next_out = buf + bytes;
-		stream.avail_out = *size - bytes;
-		while (inflate(&stream, Z_FINISH) == Z_OK)
+		stream->next_out = buf + bytes;
+		stream->avail_out = *size - bytes;
+		while (inflate(stream, Z_FINISH) == Z_OK)
 			/* nothing */;
 	}
-	inflateEnd(&stream);
+	inflateEnd(stream);
+	return buf;
+}
+
+void * unpack_sha1_file(const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size, 
+			int *chain)
+{
+	z_stream stream;
+	char *buf;
+	unsigned long offset;
+	unsigned long header_len;
+	buf = _unpack_sha1_file(&stream, map, mapsize, type, size);
+	if (!buf)
+		return buf;
+	if (!strcmp(type, "delta")) {
+		char *delta_ref;
+		unsigned long delta_size;
+		char *newbuf;
+		unsigned long newsize;
+		if (chain)
+			*chain += 1;
+		delta_ref = read_sha1_delta_ref(buf, type, &delta_size, chain);
+		if (!delta_ref) {
+			free(buf);
+			return NULL;
+		}
+		newbuf = patch_delta(delta_ref, delta_size, buf+20, *size-20, &newsize);
+		free(buf);
+		free(delta_ref);
+		*size = newsize;
+		return newbuf;
+
+	} else if (!strcmp(type, "packed")) {
+		if (!sha1) {
+			free(buf);
+			return NULL;
+		}
+		header_len = *size;
+		if (find_packed_header(sha1, buf, header_len, &offset)) {
+			free(buf);
+			return NULL;
+		}
+		offset += stream.total_in;
+		free(buf);
+		buf = unpack_sha1_file(sha1, map+offset, mapsize-offset, type, size, chain);
+	}
 	return buf;
 }
 
@@ -182,7 +261,25 @@
 
 	map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size, NULL);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
+/*
+ * the same as read_sha1_file except chain is used to count the length
+ * of any delta chains hit while unpacking
+ */
+void * read_sha1_delta_ref(const unsigned char *sha1, char *type, unsigned long *size, int *chain)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (map) {
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size, chain);
 		munmap(map, mapsize);
 		return buf;
 	}
@@ -413,3 +510,306 @@
 		return 1;
 	return 0;
 }
+
+static void *pack_buffer(void *buf, unsigned long buf_len, char *metadata, int metadata_size, unsigned long *compsize)
+{
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	size = deflateBound(&stream, buf_len + metadata_size);
+	compressed = xmalloc(size);
+
+	/*
+	 * ASCII size + nul byte
+	 */	
+	stream.next_in = metadata;
+	stream.avail_in = metadata_size;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	deflateInit(&stream, Z_BEST_COMPRESSION);
+	while (deflate(&stream, 0) == Z_OK)
+		/* nothing */;
+
+	stream.next_in = buf;
+	stream.avail_in = buf_len;
+	/* Compress it */
+	while (deflate(&stream, Z_FINISH) == Z_OK)
+		/* nothing */;
+	deflateEnd(&stream);
+	size = stream.total_out;
+	*compsize = size;
+	return compressed;
+}
+
+/*
+ * generates a delta for buf against refsha1 and returns a compressed buffer
+ * with the results.  NULL is returned on error, or when the delta could
+ * not be done.  This might happen if the delta is larger then either the
+ * refsha1 or the buffer, or the delta chain is too long.
+ */
+static void *pack_delta_buffer(void *buf, unsigned long buf_len, char *metadata, int metadata_size, unsigned long *compsize, unsigned char *sha1, unsigned char *refsha1)
+{
+	char *compressed;
+	char *refbuffer = NULL;
+	char reftype[20];
+	unsigned long refsize = 0;
+	char *delta;
+	unsigned long delta_size;
+	char *lmetadata = xmalloc(220);
+	unsigned long lmetadata_size;
+	int chain_length = 0;
+
+	if (buf_len == 0)
+		return NULL;
+	refbuffer = read_sha1_delta_ref(refsha1, reftype, &refsize, &chain_length);
+
+	if (chain_length > 16) {
+		free(refbuffer);
+		return NULL;
+	}
+	/* note, we could just continue without the delta here */
+	if (!refbuffer) {
+		free(refbuffer);
+		return NULL;
+	}
+	delta = diff_delta(refbuffer, refsize, buf, buf_len, &delta_size);
+	free(refbuffer);
+	if (!delta)
+		return NULL;
+	if (delta_size > refsize || delta_size > buf_len) {
+		free(delta);
+		return NULL;
+	}
+	if (delta_size < 10) {
+		free(delta);
+		return NULL;
+	}
+	lmetadata_size = 1 + sprintf(lmetadata, "%s %lu","delta",delta_size+20);
+	memcpy(lmetadata + lmetadata_size, refsha1, 20);
+	lmetadata_size += 20;
+	compressed = pack_buffer(delta, delta_size, lmetadata, lmetadata_size, compsize);
+	free(lmetadata);
+	free(delta);
+	return compressed;
+}
+
+/*
+ * returns a newly malloc'd packed item with a compressed buffer for buf.  
+ * If refsha1 is non-null, attempts a delta against it.  The sha1 of buf 
+ * is returned via returnsha1.
+ */
+int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+		     unsigned char *returnsha1,
+		     unsigned char *refsha1,
+		     struct packed_item **packed_item)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	struct stat st;
+	char *compressed = NULL;
+	unsigned long size;
+	struct packed_item *item;
+	char *metadata = xmalloc(200);
+	int metadata_size;
+
+	*packed_item = NULL;
+
+	metadata_size = 1 + sprintf(metadata, "%s %lu", type, buf_len);
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, buf, buf_len);
+	SHA1_Final(sha1, &c);
+
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+
+	filename = sha1_file_name(sha1);
+	if (stat(filename, &st) == 0)
+		goto out;
+
+	
+	if (refsha1) {
+		compressed = pack_delta_buffer(buf, buf_len, metadata, 
+		                               metadata_size, &size, sha1, 
+					       refsha1);
+	}
+	if (!compressed) {
+		compressed = pack_buffer(buf, buf_len, metadata, 
+		                         metadata_size, &size);
+	}
+	free(metadata);
+	if (!compressed) {
+		return -1;
+	}
+	item = xmalloc(sizeof(struct packed_item));
+	memcpy(item->sha1, sha1, 20);
+	item->len = size;
+	item->next = NULL;
+	item->data = compressed;
+	*packed_item = item;
+out:
+	return 0;
+}
+
+static char *create_packed_header(struct packed_item *head, unsigned long *size)
+{
+	char *metadata = NULL;
+	int metadata_size = 0;
+	*size = 0;
+	int entry_size = 0;
+
+	while(head) {
+		char *p;
+		metadata = realloc(metadata, metadata_size + 220);
+		if (!metadata)
+			return NULL;
+		p = metadata+metadata_size;
+		memcpy(p, head->sha1, 20);
+		p += 20;
+		entry_size = 1 + sprintf(p, "%lu", head->len);
+		metadata_size += entry_size + 20;
+		head = head->next;
+	}
+	*size = metadata_size;
+	return metadata;
+}
+
+#define WRITE_BUFFER_SIZE 8192
+static char write_buffer[WRITE_BUFFER_SIZE];
+static unsigned long write_buffer_len;
+
+static int c_write(int fd, void *data, unsigned int len)
+{
+	while (len) {
+		unsigned int buffered = write_buffer_len;
+		unsigned int partial = WRITE_BUFFER_SIZE - buffered;
+		if (partial > len)
+			partial = len;
+		memcpy(write_buffer + buffered, data, partial);
+		buffered += partial;
+		if (buffered == WRITE_BUFFER_SIZE) {
+			if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
+				return -1;
+			buffered = 0;
+		}
+		write_buffer_len = buffered;
+		len -= partial;
+		data += partial;
+ 	}
+ 	return 0;
+}
+
+static int c_flush(int fd)
+{
+	if (write_buffer_len) {
+		int left = write_buffer_len;
+		if (write(fd, write_buffer, left) != left)
+			return -1;
+		write_buffer_len = 0;
+	}
+	return 0;
+}
+
+/*
+ * creates a new packed file for all the items in head.  hard links are
+ * made from the sha1 of all the items back to the packd file, and then
+ * the packed file is unlinked.
+ */
+int write_packed_buffer(struct packed_item *head)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *filename;
+	char *metadata = xmalloc(200);
+	char *header;
+	int metadata_size;
+	int fd;
+	int ret = 0;
+	unsigned long header_len;
+	struct packed_item *item;
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+
+	header = create_packed_header(head, &header_len);
+	metadata_size = 1+sprintf(metadata, "packed %lu", header_len);
+	/* 
+	 * the header contains the sha1 of each item, so we only sha1 the
+	 * header
+	 */ 
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, header, header_len);
+	SHA1_Final(sha1, &c);
+
+	filename = strdup(sha1_file_name(sha1));
+	fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		/* add collision check! */
+		if (errno != EEXIST) {
+			ret = -errno;
+		}
+		goto out_nofile;
+	}
+       /* compress just the header info */
+        memset(&stream, 0, sizeof(stream));
+        deflateInit(&stream, Z_BEST_COMPRESSION);
+	size = deflateBound(&stream, header_len + metadata_size);
+        compressed = xmalloc(size);
+
+        stream.next_in = metadata;
+        stream.avail_in = metadata_size;
+        stream.next_out = compressed;
+        stream.avail_out = size;
+        while (deflate(&stream, 0) == Z_OK)
+                /* nothing */;
+        stream.next_in = header;
+        stream.avail_in = header_len;
+        while (deflate(&stream, Z_FINISH) == Z_OK)
+                /* nothing */;
+        deflateEnd(&stream);
+        size = stream.total_out;
+
+	c_write(fd, compressed, size);
+	free(compressed);
+
+	item = head;
+	while(item) {
+		if (c_write(fd, item->data, item->len)) {
+			ret = -EIO;
+			goto out;
+		}
+		item = item->next;
+	}
+	if (c_flush(fd)) {
+		ret = -EIO;
+		goto out;
+	}
+	item = head;
+	while(item) {
+		char *item_file;
+		struct packed_item *next = item->next;
+		item_file = sha1_file_name(item->sha1);
+		if (link(filename, item_file) && errno != EEXIST) {
+			ret = -errno;
+			break;
+		}
+		free(item->data);
+		free(item);
+		item = next;
+	}
+	unlink(filename);
+out:
+	close(fd);
+out_nofile:
+	free(header);
+	free(metadata);
+	free(filename);
+	return ret;
+}
diff -urN --exclude .git linus.diff/update-cache.c linus.mine/update-cache.c
--- linus.diff/update-cache.c	2005-05-04 09:54:49.167733240 -0400
+++ linus.mine/update-cache.c	2005-05-02 20:51:32.000000000 -0400
@@ -31,55 +31,39 @@
 	return (unsigned long)ptr > (unsigned long)-1000L;
 }
 
-static int index_fd(unsigned char *sha1, int fd, struct stat *st)
+static int index_fd(unsigned char *sha1, unsigned char *refsha1, int fd, struct stat *st, struct packed_item **head, struct packed_item **tail, unsigned long *packed_size, int *packed_nr)
 {
-	z_stream stream;
 	unsigned long size = st->st_size;
-	int max_out_bytes = size + 200;
-	void *out = xmalloc(max_out_bytes);
-	void *metadata = xmalloc(200);
-	int metadata_size;
 	void *in;
-	SHA_CTX c;
+	int ret;
+	struct packed_item *new_item;
 
 	in = "";
 	if (size)
 		in = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (!out || (int)(long)in == -1)
+	if ((int)(long)in == -1) {
 		return -1;
-
-	metadata_size = 1+sprintf(metadata, "blob %lu", size);
-
-	SHA1_Init(&c);
-	SHA1_Update(&c, metadata, metadata_size);
-	SHA1_Update(&c, in, size);
-	SHA1_Final(sha1, &c);
-
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, Z_BEST_COMPRESSION);
-
-	/*
-	 * ASCII size + nul byte
-	 */	
-	stream.next_in = metadata;
-	stream.avail_in = metadata_size;
-	stream.next_out = out;
-	stream.avail_out = max_out_bytes;
-	while (deflate(&stream, 0) == Z_OK)
-		/* nothing */;
-
-	/*
-	 * File content
-	 */
-	stream.next_in = in;
-	stream.avail_in = size;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/*nothing */;
-
-	deflateEnd(&stream);
-	
-	return write_sha1_buffer(sha1, out, stream.total_out);
+	}
+	ret = pack_sha1_buffer(in, size, "blob", sha1, refsha1, &new_item);
+	if (new_item) {
+		if (*tail)
+			(*tail)->next = new_item;
+		*tail = new_item;
+		if (!*head)
+			*head = new_item;
+		*packed_size += new_item->len;
+		*packed_nr++;
+		if (*packed_size > (512 * 1024) || *packed_nr > 1024) {
+			write_packed_buffer(*head);
+			*head = NULL;
+			*tail = NULL;
+			*packed_size = 0;
+			*packed_nr = 0;
+		}
+	}
+	munmap(in, size);
+	return ret;
 }
 
 /*
@@ -102,12 +86,14 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(char *path, struct packed_item **packed_head, struct packed_item **packed_tail, unsigned long *packed_size, int *packed_nr)
 {
 	int size, namelen;
 	struct cache_entry *ce;
 	struct stat st;
 	int fd;
+	int pos;
+	unsigned char *refsha1 = NULL;
 
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
@@ -129,8 +115,12 @@
 	fill_stat_cache_info(ce, &st);
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
+	pos = cache_name_pos(ce->name, namelen);
+	if (pos >= 0)
+		refsha1 = active_cache[pos]->sha1;
 
-	if (index_fd(ce->sha1, fd, &st) < 0)
+	if (index_fd(ce->sha1, refsha1, fd, &st, packed_head, 
+		     packed_tail, packed_size, packed_nr) < 0)
 		return -1;
 
 	return add_cache_entry(ce, allow_add);
@@ -311,6 +301,10 @@
 	int allow_options = 1;
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct packed_item *packed_head = NULL;
+	struct packed_item *packed_tail = NULL;
+	unsigned long packed_size = 0;
+	int packed_nr = 0;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -362,8 +356,13 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(path, &packed_head, &packed_tail, &packed_size, &packed_nr))
 			die("Unable to add %s to database", path);
+
+	}
+	if (packed_head) {
+		if (write_packed_buffer(packed_head))
+			die("write packed buffer failed");
 	}
 	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
 		die("Unable to write new cachefile");
diff -urN --exclude .git linus.diff/write-tree.c linus.mine/write-tree.c
--- linus.diff/write-tree.c	2005-05-04 09:54:49.167733240 -0400
+++ linus.mine/write-tree.c	2005-05-02 20:51:32.000000000 -0400
@@ -5,24 +5,13 @@
  */
 #include "cache.h"
 
-static int check_valid_sha1(unsigned char *sha1)
-{
-	char *filename = sha1_file_name(sha1);
-	int ret;
-
-	/* If we were anal, we'd check that the sha1 of the contents actually matches */
-	ret = access(filename, R_OK);
-	if (ret)
-		perror(filename);
-	return ret;
-}
-
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1, struct packed_item **head)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
 	char *buffer;
 	int nr;
+	struct packed_item *item;
 
 	/* Guess at some random initial size */
 	size = 8192;
@@ -50,7 +39,7 @@
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1, head);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -62,9 +51,6 @@
 			sha1 = subdir_sha1;
 		}
 
-		if (check_valid_sha1(sha1) < 0)
-			exit(1);
-
 		entrylen = pathlen - baselen;
 		if (offset + entrylen + 100 > size) {
 			size = alloc_nr(offset + entrylen + 100);
@@ -77,7 +63,11 @@
 		nr++;
 	} while (nr < maxentries);
 
-	write_sha1_file(buffer, offset, "tree", returnsha1);
+	pack_sha1_buffer(buffer, offset, "tree", returnsha1, NULL, &item);
+	if (item) {
+		item->next = *head;
+		*head = item;
+	}
 	free(buffer);
 	return nr;
 }
@@ -87,6 +77,7 @@
 	int i, unmerged;
 	int entries = read_cache();
 	unsigned char sha1[20];
+	struct packed_item *head = NULL;
 
 	if (entries <= 0)
 		die("write-tree: no cache contents to write");
@@ -107,8 +98,12 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(active_cache, entries, "", 0, sha1, &head) != entries)
 		die("write-tree: internal error");
+	if (head) {
+		if (write_packed_buffer(head))
+			die("write_packed_buffer error");
+	}
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;
 }

^ permalink raw reply	[relevance 17%]

* Re: git and symlinks as tracked content
  @ 2005-05-05  1:20 19%       ` Kay Sievers
    0 siblings, 1 reply; 200+ results
From: Kay Sievers @ 2005-05-05  1:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git

Allow to store and track symlink in the repository. A symlink is stored
the same way as a regular file, but with the appropriate mode bits set.
The symlink target is stored in its own blob object. This will hopefully
make our udev repository fully functional. :)

Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
---

On Wed, May 04, 2005 at 04:16:22PM -0700, Junio C Hamano wrote:
> It seems to follow the original suggestion by Linus and looks
> good.  Some comments:
>
>  * It continues to assume that S_IFREG, S_IFDIR and S_IFLNK have
>    the same bit pattern everywhere.  In the same spirit as we
>    store mode bits in network byte order, it may be a good time
>    to introduce something like this:
...

>  * read-cache.c:cache_match_stat() needs to know about the
>    object type.  It was allowed to assume that anything thrown
>    at it was a file, but not anymore.  How about something like
>    this:

Both included and updated.

>   * (this is just a minor nit).  Since you have st here,
>     st.st_size can be used to see how big a buffer you need to
>     prepare for readlink() here:

Sounds nice, but is this reliable? I just remember some exotic filesystems
to reported bogus values here.

>   * Probably diff.c needs to be made aware of this change.

You already did this. :) Very nice.

Thanks,
Kay

--- a/cache.h
+++ b/cache.h
@@ -86,8 +86,19 @@ struct cache_entry {
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 #define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
 
+#define CE_IFREG  0100000
+#define CE_IFDIR  0040000
+#define CE_IFLNK  0120000
+#define CE_IFMASK 0770000
 #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
-#define create_ce_mode(mode) htonl(S_IFREG | ce_permissions(mode))
+static inline unsigned int create_ce_mode(unsigned int mode)
+{
+	if (S_ISREG(mode))
+		return htonl(S_IFREG | ce_permissions(mode));
+	if (S_ISLNK(mode))
+		return htonl(CE_IFLNK);
+	return 0;
+}
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
@@ -124,6 +135,7 @@ extern int index_fd(unsigned char *sha1,
 #define MODE_CHANGED    0x0008
 #define INODE_CHANGED   0x0010
 #define DATA_CHANGED    0x0020
+#define TYPE_CHANGED    0x0040
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *sha1_file_name(const unsigned char *sha1);
--- a/check-files.c
+++ b/check-files.c
@@ -28,8 +28,8 @@ static void check_file(const char *path)
 		die("preparing to update existing file '%s' not in cache", path);
 	ce = active_cache[pos];
 
-	if (fstat(fd, &st) < 0)
-		die("fstat(%s): %s", path, strerror(errno));
+	if (lstat(path, &st) < 0)
+		die("lstat(%s): %s", path, strerror(errno));
 
 	changed = cache_match_stat(ce, &st);
 	if (changed)
--- a/checkout-cache.c
+++ b/checkout-cache.c
@@ -72,23 +72,37 @@ static int write_entry(struct cache_entr
 	unsigned long size;
 	long wrote;
 	char type[20];
+	unsigned int mode;
 
 	new = read_sha1_file(ce->sha1, type, &size);
 	if (!new || strcmp(type, "blob")) {
 		return error("checkout-cache: unable to read sha1 file of %s (%s)",
 			path, sha1_to_hex(ce->sha1));
 	}
-	fd = create_file(path, ntohl(ce->ce_mode));
-	if (fd < 0) {
+	mode = ntohl(ce->ce_mode);
+	if (S_ISLNK(mode)) {
+		char target[1024];
+		memcpy(target, new, size);
+		target[size] = '\0';
+		if (symlink(target, path)) {
+			free(new);
+			return error("checkout-cache: unable to create link %s (%s)",
+				path, strerror(errno));
+		}
+		free(new);
+	} else {
+		fd = create_file(path, mode);
+		if (fd < 0) {
+			free(new);
+			return error("checkout-cache: unable to create file %s (%s)",
+				path, strerror(errno));
+		}
+		wrote = write(fd, new, size);
+		close(fd);
 		free(new);
-		return error("checkout-cache: unable to create %s (%s)",
-			path, strerror(errno));
+		if (wrote != size)
+			return error("checkout-cache: unable to write %s", path);
 	}
-	wrote = write(fd, new, size);
-	close(fd);
-	free(new);
-	if (wrote != size)
-		return error("checkout-cache: unable to write %s", path);
 	return 0;
 }
 
@@ -101,7 +115,7 @@ static int checkout_entry(struct cache_e
 	memcpy(path, base_dir, len);
 	strcpy(path + len, ce->name);
 
-	if (!stat(path, &st)) {
+	if (!lstat(path, &st)) {
 		unsigned changed = cache_match_stat(ce, &st);
 		if (!changed)
 			return 0;
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -24,7 +24,7 @@ static int get_stat_data(struct cache_en
 		static unsigned char no_sha1[20];
 		int changed;
 		struct stat st;
-		if (stat(ce->name, &st) < 0)
+		if (lstat(ce->name, &st) < 0)
 			return -1;
 		changed = cache_match_stat(ce, &st);
 		if (changed) {
--- a/diff.c
+++ b/diff.c
@@ -165,7 +165,7 @@ static void prepare_temp_file(const char
 		}
 		strcpy(temp->hex, sha1_to_hex(null_sha1));
 		sprintf(temp->mode, "%06o",
-			S_IFREG |ce_permissions(st.st_mode));
+			S_IFREG | ce_permissions(st.st_mode));
 	}
 	else {
 		int fd;
--- a/ls-files.c
+++ b/ls-files.c
@@ -199,7 +199,7 @@ static void show_files(void)
 			struct stat st;
 			if (excluded(ce->name) != show_ignored)
 				continue;
-			if (!stat(ce->name, &st))
+			if (!lstat(ce->name, &st))
 				continue;
 			printf("%s%c", ce->name, line_terminator);
 		}
--- a/read-cache.c
+++ b/read-cache.c
@@ -13,6 +13,16 @@ int cache_match_stat(struct cache_entry 
 {
 	unsigned int changed = 0;
 
+	switch (ntohl(ce->ce_mode) & CE_IFMASK) {
+	case CE_IFREG:
+		changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;
+		break;
+	case CE_IFLNK:
+		changed |= !S_ISLNK(st->st_mode) ? TYPE_CHANGED : 0;
+		break;
+	default:
+		die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
+	}
 	if (ce->ce_mtime.sec != htonl(st->st_mtime))
 		changed |= MTIME_CHANGED;
 	if (ce->ce_ctime.sec != htonl(st->st_ctime))
--- a/tree.c
+++ b/tree.c
@@ -13,7 +13,10 @@ static int read_one_entry(unsigned char 
 
 	memset(ce, 0, size);
 
-	ce->ce_mode = create_ce_mode(mode);
+	if (mode & S_IFMT)
+		ce->ce_mode = htonl(mode);
+	else
+		ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(baselen + len, stage);
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
--- a/update-cache.c
+++ b/update-cache.c
@@ -58,30 +58,37 @@ static int add_file_to_cache(char *path)
 	struct stat st;
 	int fd;
 
-	fd = open(path, O_RDONLY);
-	if (fd < 0) {
+	if (lstat(path, &st) < 0) {
 		if (errno == ENOENT || errno == ENOTDIR) {
 			if (allow_remove)
 				return remove_file_from_cache(path);
 		}
 		return -1;
 	}
-	if (fstat(fd, &st) < 0) {
-		close(fd);
-		return -1;
-	}
 	namelen = strlen(path);
 	size = cache_entry_size(namelen);
 	ce = xmalloc(size);
 	memset(ce, 0, size);
 	memcpy(ce->name, path, namelen);
 	fill_stat_cache_info(ce, &st);
-	ce->ce_mode = create_ce_mode(st.st_mode);
+	if (S_ISREG(st.st_mode)) {
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			return -1;
+		ce->ce_mode = create_ce_mode(st.st_mode);
+		if (index_fd(ce->sha1, fd, &st) < 0)
+			return -1;
+	} else if (S_ISLNK(st.st_mode)) {
+		unsigned int len;
+		char target[1024];
+		ce->ce_mode = htonl(S_IFLNK);
+		len = readlink(path, target, sizeof(target));
+		if (len == -1 || len+1 > sizeof(target))
+			return -1;
+		if (write_sha1_file(target, len, "blob", ce->sha1))
+			return -1;
+	}
 	ce->ce_flags = htons(namelen);
-
-	if (index_fd(ce->sha1, fd, &st) < 0)
-		return -1;
-
 	return add_cache_entry(ce, allow_add);
 }
 
@@ -137,7 +144,7 @@ static struct cache_entry *refresh_entry
 	struct cache_entry *updated;
 	int changed, size;
 
-	if (stat(ce->name, &st) < 0)
+	if (lstat(ce->name, &st) < 0)
 		return ERR_PTR(-errno);
 
 	changed = cache_match_stat(ce, &st);
@@ -145,10 +152,10 @@ static struct cache_entry *refresh_entry
 		return ce;
 
 	/*
-	 * If the mode has changed, there's no point in trying
+	 * If the mode or type has changed, there's no point in trying
 	 * to refresh the entry - it's not going to match
 	 */
-	if (changed & MODE_CHANGED)
+	if (changed & (MODE_CHANGED | TYPE_CHANGED))
 		return ERR_PTR(-EINVAL);
 
 	if (compare_data(ce, st.st_size))


^ permalink raw reply	[relevance 19%]

* Re: git and symlinks as tracked content
  @ 2005-05-05 12:38 19%           ` Kay Sievers
  0 siblings, 0 replies; 200+ results
From: Kay Sievers @ 2005-05-05 12:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git

Allow to store and track symlink in the repository. A symlink is stored
the same way as a regular file, only with the appropriate mode bits set.
The symlink target is therefore stored in a blob object.
This will hopefully make our udev repository fully functional. :)

Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
---

On Wed, May 04, 2005 at 07:13:43PM -0700, Junio C Hamano wrote:
> >>>>> "KS" == Kay Sievers <kay.sievers@vrfy.org> writes:

> I did not know if you are going to take CE_ type suggestion so 
> I left it as it was.
> 
> There are more.  "grep 'S_I[SF]' *.[ch] */*.[ch]" would tell us
> most if not all.  We probably would want to have CE_ISLNK() and
> friends, parallel to S_ISLNK() and friends if we go this route.

Hmm, how about this?

Thanks,
Kay

--- a/cache.h
+++ b/cache.h
@@ -87,7 +87,14 @@ struct cache_entry {
 #define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
 
 #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
-#define create_ce_mode(mode) htonl(S_IFREG | ce_permissions(mode))
+static inline unsigned int create_ce_mode(unsigned int mode)
+{
+	if (S_ISREG(mode))
+		return htonl(S_IFREG | ce_permissions(mode));
+	if (S_ISLNK(mode))
+		return htonl(S_IFLNK);
+	return htonl(mode);
+}
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
@@ -124,6 +131,7 @@ extern int index_fd(unsigned char *sha1,
 #define MODE_CHANGED    0x0008
 #define INODE_CHANGED   0x0010
 #define DATA_CHANGED    0x0020
+#define TYPE_CHANGED    0x0040
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *sha1_file_name(const unsigned char *sha1);
--- a/check-files.c
+++ b/check-files.c
@@ -28,8 +28,8 @@ static void check_file(const char *path)
 		die("preparing to update existing file '%s' not in cache", path);
 	ce = active_cache[pos];
 
-	if (fstat(fd, &st) < 0)
-		die("fstat(%s): %s", path, strerror(errno));
+	if (lstat(path, &st) < 0)
+		die("lstat(%s): %s", path, strerror(errno));
 
 	changed = cache_match_stat(ce, &st);
 	if (changed)
--- a/checkout-cache.c
+++ b/checkout-cache.c
@@ -72,23 +72,41 @@ static int write_entry(struct cache_entr
 	unsigned long size;
 	long wrote;
 	char type[20];
+	char target[1024];
 
 	new = read_sha1_file(ce->sha1, type, &size);
 	if (!new || strcmp(type, "blob")) {
 		return error("checkout-cache: unable to read sha1 file of %s (%s)",
 			path, sha1_to_hex(ce->sha1));
 	}
-	fd = create_file(path, ntohl(ce->ce_mode));
-	if (fd < 0) {
+	switch (ntohl(ce->ce_mode) & S_IFMT) {
+	case S_IFREG:
+		fd = create_file(path, ntohl(ce->ce_mode));
+		if (fd < 0) {
+			free(new);
+			return error("checkout-cache: unable to create file %s (%s)",
+				path, strerror(errno));
+		}
+		wrote = write(fd, new, size);
+		close(fd);
+		free(new);
+		if (wrote != size)
+			return error("checkout-cache: unable to write file %s", path);
+		break;
+	case S_IFLNK:
+		memcpy(target, new, size);
+		target[size] = '\0';
+		if (symlink(target, path)) {
+			free(new);
+			return error("checkout-cache: unable to create symlink %s (%s)",
+				path, strerror(errno));
+		}
+		free(new);
+		break;
+	default:
 		free(new);
-		return error("checkout-cache: unable to create %s (%s)",
-			path, strerror(errno));
+		return error("checkout-cache: unknown file mode for %s", path);
 	}
-	wrote = write(fd, new, size);
-	close(fd);
-	free(new);
-	if (wrote != size)
-		return error("checkout-cache: unable to write %s", path);
 	return 0;
 }
 
@@ -101,7 +119,7 @@ static int checkout_entry(struct cache_e
 	memcpy(path, base_dir, len);
 	strcpy(path + len, ce->name);
 
-	if (!stat(path, &st)) {
+	if (!lstat(path, &st)) {
 		unsigned changed = cache_match_stat(ce, &st);
 		if (!changed)
 			return 0;
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -24,7 +24,7 @@ static int get_stat_data(struct cache_en
 		static unsigned char no_sha1[20];
 		int changed;
 		struct stat st;
-		if (stat(ce->name, &st) < 0)
+		if (lstat(ce->name, &st) < 0)
 			return -1;
 		changed = cache_match_stat(ce, &st);
 		if (changed) {
--- a/ls-files.c
+++ b/ls-files.c
@@ -199,7 +199,7 @@ static void show_files(void)
 			struct stat st;
 			if (excluded(ce->name) != show_ignored)
 				continue;
-			if (!stat(ce->name, &st))
+			if (!lstat(ce->name, &st))
 				continue;
 			printf("%s%c", ce->name, line_terminator);
 		}
--- a/read-cache.c
+++ b/read-cache.c
@@ -13,6 +13,16 @@ int cache_match_stat(struct cache_entry 
 {
 	unsigned int changed = 0;
 
+	switch (ntohl(ce->ce_mode) & S_IFMT) {
+	case S_IFREG:
+		changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;
+		break;
+	case S_IFLNK:
+		changed |= !S_ISLNK(st->st_mode) ? TYPE_CHANGED : 0;
+		break;
+	default:
+		die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
+	}
 	if (ce->ce_mtime.sec != htonl(st->st_mtime))
 		changed |= MTIME_CHANGED;
 	if (ce->ce_ctime.sec != htonl(st->st_ctime))
--- a/update-cache.c
+++ b/update-cache.c
@@ -57,19 +57,16 @@ static int add_file_to_cache(char *path)
 	struct cache_entry *ce;
 	struct stat st;
 	int fd;
+	unsigned int len;
+	char target[1024];
 
-	fd = open(path, O_RDONLY);
-	if (fd < 0) {
+	if (lstat(path, &st) < 0) {
 		if (errno == ENOENT || errno == ENOTDIR) {
 			if (allow_remove)
 				return remove_file_from_cache(path);
 		}
 		return -1;
 	}
-	if (fstat(fd, &st) < 0) {
-		close(fd);
-		return -1;
-	}
 	namelen = strlen(path);
 	size = cache_entry_size(namelen);
 	ce = xmalloc(size);
@@ -78,10 +75,24 @@ static int add_file_to_cache(char *path)
 	fill_stat_cache_info(ce, &st);
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
-
-	if (index_fd(ce->sha1, fd, &st) < 0)
+	switch (st.st_mode & S_IFMT) {
+	case S_IFREG:
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			return -1;
+		if (index_fd(ce->sha1, fd, &st) < 0)
+			return -1;
+		break;
+	case S_IFLNK:
+		len = readlink(path, target, sizeof(target));
+		if (len == -1 || len+1 > sizeof(target))
+			return -1;
+		if (write_sha1_file(target, len, "blob", ce->sha1))
+			return -1;
+		break;
+	default:
 		return -1;
-
+	}
 	return add_cache_entry(ce, allow_add);
 }
 
@@ -137,7 +148,7 @@ static struct cache_entry *refresh_entry
 	struct cache_entry *updated;
 	int changed, size;
 
-	if (stat(ce->name, &st) < 0)
+	if (lstat(ce->name, &st) < 0)
 		return ERR_PTR(-errno);
 
 	changed = cache_match_stat(ce, &st);
@@ -145,10 +156,10 @@ static struct cache_entry *refresh_entry
 		return ce;
 
 	/*
-	 * If the mode has changed, there's no point in trying
+	 * If the mode or type has changed, there's no point in trying
 	 * to refresh the entry - it's not going to match
 	 */
-	if (changed & MODE_CHANGED)
+	if (changed & (MODE_CHANGED | TYPE_CHANGED))
 		return ERR_PTR(-EINVAL);
 
 	if (compare_data(ce, st.st_size))


^ permalink raw reply	[relevance 19%]

* [PATCH] Remove unused sha1_file_directory variable.
@ 2005-05-06 23:33 19% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-06 23:33 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Now all the users have gone.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h     |    1 -
 sha1_file.c |    3 ---
 2 files changed, 4 deletions(-)

--- a/cache.h
+++ b/cache.h
@@ -96,7 +96,6 @@ static inline unsigned int create_ce_mod
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
-const char *sha1_file_directory;
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc;
 
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -9,8 +9,6 @@
 #include <stdarg.h>
 #include "cache.h"
 
-const char *sha1_file_directory = NULL;
-
 #ifndef O_NOATIME
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
 #define O_NOATIME 01000000
----------------------------------------------------------------


^ permalink raw reply	[relevance 19%]

* [PATCH] Introduce SHA1_FILE_DIRECTORIES
@ 2005-05-06 23:35 13% Junio C Hamano
    0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2005-05-06 23:35 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

A new environment variable, SHA1_FILE_DIRECTORIES, is
introduced.  This affects the routines that read existing
objects from the object database, but not creation of new
objects.

The environment variable, when exists, is a colon separated list of
directories.  If an object is not found in the usual location
SHA1_FILE_DIRECTORY (or .git/objects), this list is consulted and if
object is found there it is returned.

This is an implementation of the idea floated on the GIT list a couple
of days ago to archive really old history on a separate directory, even
on a read-only DVD ROM media.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

cache.h     |    5 +-
sha1_file.c |  113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 112 insertions(+), 6 deletions(-)

--- a/cache.h
+++ b/cache.h
@@ -101,8 +101,7 @@ unsigned int active_nr, active_alloc;
 
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
-
-#define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
+#define ALTERNATE_DB_ENVIRONMENT "SHA1_FILE_DIRECTORIES"
 
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define DEFAULT_INDEX_ENVIRONMENT ".git/index"
@@ -130,7 +129,7 @@ extern int index_fd(unsigned char *sha1,
 #define DATA_CHANGED    0x0020
 #define TYPE_CHANGED    0x0040
 
-/* Return a statically allocated filename matching the sha1 signature */
+/* Return a statically allocated filename matching the sha1 signature. */
 extern char *sha1_file_name(const unsigned char *sha1);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -100,10 +100,19 @@ char * sha1_to_hex(const unsigned char *
 	return buffer;
 }
 
+static const char *get_object_directory(void)
+{
+	return getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+}
+
 /*
  * NOTE! This returns a statically allocated buffer, so you have to be
  * careful about using it. Do a "strdup()" if you need to save the
  * filename.
+ *
+ * Also note that this returns the location for creating.  Reading
+ * SHA1 file can happen from any alternate directory listed in the
+ * SHA1_FILE_DIRECTORIES environment variable.
  */
 char *sha1_file_name(const unsigned char *sha1)
 {
@@ -130,6 +139,99 @@ char *sha1_file_name(const unsigned char
 	return base;
 }
 
+static char *find_sha1_file(const unsigned char *sha1)
+{
+	struct stat st;
+	char *name = sha1_file_name(sha1);
+	static struct {
+		int pfxlen;
+		char *buf;
+	} *alternates = NULL;
+	static int num_alt = -1;
+	int i;
+
+	if (num_alt < 0) {
+		int cnt;
+		int totlen;
+		const char *cp, *last;
+		const char *alt = getenv(ALTERNATE_DB_ENVIRONMENT);
+		void *buf;
+		char *op;
+
+		if (!alt || !alt[0]) {
+			num_alt = 0;
+			return name;
+		}
+
+		for (last = cp = alt, totlen = cnt = 0; *cp; cp++) {
+			/* We could strip the empty path which would result
+			 * in /xx/xxxxx from the filesystem root level,
+			 * but who cares.  We are only constructing list of
+			 * paths to attempt to read not write.
+			 */
+			if (*cp == ':') {
+				/* 40 bytes plus two / and terminating NUL */
+				totlen += cp - last + 43;
+				cnt++;
+				last = cp + 1;
+			}
+		}
+		if (cp != last) {
+			totlen += cp - last + 43;
+			cnt++;
+		}
+
+		if (!cnt) {
+			num_alt = 0;
+			return name;
+		}
+		num_alt = cnt;
+
+		buf = xmalloc(sizeof(*alternates) * (cnt + 1) + totlen);
+		alternates = buf;
+		alternates[num_alt].pfxlen = 0;
+		alternates[num_alt].buf = NULL;
+		op = (char*) (&alternates[cnt+1]);
+		for (last = cp = alt, i = 0; i < num_alt; cp++) {
+			if (*cp == ':' || *cp == 0) {
+				alternates[i].buf = op;
+				alternates[i].pfxlen = cp - last;
+				memcpy(op, last, cp - last);
+				op[cp - last] = 0;
+				op += (cp - last + 1);
+				last = cp + 1;
+				i++;
+			}
+		}
+		if (cp != last) {
+			alternates[i].buf = op;
+			alternates[i].pfxlen = last - cp;
+			memcpy(op, last, last - cp);
+			op[last-cp] = 0;
+		}
+	}
+	if (!stat(name, &st))
+		return name;
+	for (i = 0; i < num_alt; i++) {
+		char *alt = alternates[i].buf;
+		int len = alternates[i].pfxlen;
+		char *name = alt + len;
+		alt[len] = '/';
+		alt[len+3] = '/';
+		name = alt + len + 1;
+		for (i = 0; i < 20; i++) {
+			static char hex[] = "0123456789abcdef";
+			unsigned int val = sha1[i];
+			char *pos = name + i*2 + (i > 0);
+			*pos++ = hex[val >> 4];
+			*pos = hex[val & 0xf];
+		}
+		if (!stat(alt, &st))
+			return alt;
+	}
+	return NULL;
+}
+
 int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
 	char header[100];
@@ -145,10 +247,14 @@ int check_sha1_signature(unsigned char *
 
 void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 {
-	char *filename = sha1_file_name(sha1);
 	struct stat st;
 	void *map;
 	int fd;
+	char *filename = find_sha1_file(sha1);
+	if (!filename) {
+		error("cannot map sha1 file %s", sha1_to_hex(sha1));
+		return NULL;
+	}
 
 	fd = open(filename, O_RDONLY | sha1_file_open_flag);
 	if (fd < 0) {
@@ -442,8 +548,10 @@ int write_sha1_from_fd(const unsigned ch
 
 int has_sha1_file(const unsigned char *sha1)
 {
-	char *filename = sha1_file_name(sha1);
 	struct stat st;
+	char *filename = find_sha1_file(sha1);
+	if (!filename)
+		return 0;
 
 	if (!stat(filename, &st))
 		return 1;
----------------------------------------------------------------


^ permalink raw reply	[relevance 13%]

* Re: [PATCH] Introduce SHA1_FILE_DIRECTORIES
  @ 2005-05-07 19:51 16%         ` Junio C Hamano
    0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2005-05-07 19:51 UTC (permalink / raw)
  To: Sean; +Cc: Junio C Hamano, Linus Torvalds, git

>>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes:
>>>>> "S" == Sean  <seanlkml@sympatico.ca> writes:

S> Perhaps I'm just missing something in your code,...
JCH> Thankfully I think Linus had rejected this part in the series.
JCH> I'll fix it up.

Here is the fixed one.  The previous one was ugly and
inconvenient to use (thanks for noticing, Sean).

I'll keep it in the git-jc repository until Linus returns.

------------

Author: Junio C Hamano <junkio@cox.net>
Date:   Sat May 7 00:38:04 2005 -0700
    
Introduce SHA1_FILE_DIRECTORIES to support multiple object databases.

SHA1_FILE_DIRECTORIES environment variable is a colon separated paths
used when looking for SHA1 files not found in the usual place for
reading.  Creating a new SHA1 file does not use this alternate object
database location mechanism.  This is useful to archive older, rarely
used objects into separate directories.

Signed-off-by: Junio C Hamano <junkio@cox.net>

--- a/cache.h
+++ b/cache.h
@@ -101,6 +101,7 @@ unsigned int active_nr, active_alloc, ac
 
 #define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
+#define ALTERNATE_DB_ENVIRONMENT "SHA1_FILE_DIRECTORIES"
 
 #define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
 
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -306,7 +306,7 @@ int main(int argc, char **argv)
 			usage("fsck-cache [--tags] [[--unreachable] [--cache] <head-sha1>*]");
 	}
 
-	sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+	sha1_dir = get_object_directory();
 	for (i = 0; i < 256; i++) {
 		static char dir[4096];
 		sprintf(dir, "%s/%02x", sha1_dir, i);
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -100,18 +100,34 @@ char * sha1_to_hex(const unsigned char *
 	return buffer;
 }
 
+static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
+{
+	int i;
+	for (i = 0; i < 20; i++) {
+		static char hex[] = "0123456789abcdef";
+		unsigned int val = sha1[i];
+		char *pos = pathbuf + i*2 + (i > 0);
+		*pos++ = hex[val >> 4];
+		*pos = hex[val & 0xf];
+	}
+}
+
 /*
  * NOTE! This returns a statically allocated buffer, so you have to be
  * careful about using it. Do a "strdup()" if you need to save the
  * filename.
+ *
+ * Also note that this returns the location for creating.  Reading
+ * SHA1 file can happen from any alternate directory listed in the
+ * SHA1_FILE_DIRECTORIES environment variable if it is not found in
+ * the primary object database.
  */
 char *sha1_file_name(const unsigned char *sha1)
 {
-	int i;
 	static char *name, *base;
 
 	if (!base) {
-		char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
+		char *sha1_file_directory = get_object_directory();
 		int len = strlen(sha1_file_directory);
 		base = xmalloc(len + 60);
 		memcpy(base, sha1_file_directory, len);
@@ -120,16 +136,74 @@ char *sha1_file_name(const unsigned char
 		base[len+3] = '/';
 		name = base + len + 1;
 	}
-	for (i = 0; i < 20; i++) {
-		static char hex[] = "0123456789abcdef";
-		unsigned int val = sha1[i];
-		char *pos = name + i*2 + (i > 0);
-		*pos++ = hex[val >> 4];
-		*pos = hex[val & 0xf];
-	}
+	fill_sha1_path(name, sha1);
 	return base;
 }
 
+static struct alternate_object_database
+{
+	char *base;
+	char *name;
+} *alt_odb;
+
+static void prepare_alt_odb(void)
+{
+	int pass, totlen, i;
+	void *buf;
+	const char *cp, *last;
+	char *op = 0;
+	const char *alt = getenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
+
+	for (totlen = pass = 0; pass < 2; pass++) {
+		last = alt;
+		i = 0;
+		do {
+			cp = strchr(last, ':') ? : last + strlen(last);
+			if (last != cp) {
+				/* 43 = 40-byte + 2 '/' + terminating NUL */
+				int pfxlen = cp - last;
+				int entlen = pfxlen + 43;
+				if (pass == 0)
+					totlen += entlen;
+				else {
+					alt_odb[i].base = op;
+					alt_odb[i].name = op + pfxlen + 1;
+					memcpy(op, last, pfxlen);
+					op[pfxlen] = op[pfxlen + 3] = '/';
+					op[entlen-1] = 0;
+					op += entlen;
+				}
+				i++;
+			}
+			while (*cp && *cp == ':')
+				cp++;
+			last = cp;
+		} while (*cp);
+		if (pass)
+			break;
+		alt_odb = buf = xmalloc(sizeof(*alt_odb) * (i + 1) + totlen);
+		alt_odb[i].base = alt_odb[i].name = 0;
+		op = (char*)(&alt_odb[i+1]);
+	}
+}
+
+static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
+{
+	int i;
+	char *name = sha1_file_name(sha1);
+
+	if (!stat(name, st))
+		return name;
+	if (!alt_odb)
+		prepare_alt_odb();
+	for (i = 0; (name = alt_odb[i].name) != NULL; i++) {
+		fill_sha1_path(name, sha1);
+		if (!stat(alt_odb[i].base, st))
+			return alt_odb[i].base;
+	}
+	return NULL;
+}
+
 int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
 	char header[100];
@@ -145,10 +219,15 @@ int check_sha1_signature(unsigned char *
 
 void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 {
-	char *filename = sha1_file_name(sha1);
 	struct stat st;
 	void *map;
 	int fd;
+	char *filename = find_sha1_file(sha1, &st);
+
+	if (!filename) {
+		error("cannot map sha1 file %s", sha1_to_hex(sha1));
+		return NULL;
+	}
 
 	fd = open(filename, O_RDONLY | sha1_file_open_flag);
 	if (fd < 0) {
@@ -167,10 +246,6 @@ void *map_sha1_file(const unsigned char 
 		/* If it failed once, it will probably fail again. Stop using O_NOATIME */
 		sha1_file_open_flag = 0;
 	}
-	if (fstat(fd, &st) < 0) {
-		close(fd);
-		return NULL;
-	}
 	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
 	if (-1 == (int)(long)map)
@@ -315,6 +390,7 @@ int write_sha1_file(char *buf, unsigned 
 	}
 
 	snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
+
 	fd = mkstemp(tmpfile);
 	if (fd < 0) {
 		fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
@@ -442,12 +518,8 @@ int write_sha1_from_fd(const unsigned ch
 
 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;
+	return !!find_sha1_file(sha1, &st);
 }
 
 int index_fd(unsigned char *sha1, int fd, struct stat *st)





^ permalink raw reply	[relevance 16%]

* [RFC] Renaming environment variables.
  @ 2005-05-09 20:05  9%                     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-09 20:05 UTC (permalink / raw)
  To: git; +Cc: H. Peter Anvin, Sean, Linus Torvalds

H. Peter Anvin mentioned that using SHA1_whatever as an
environment variable name is not nice and we should instead use
names starting with "GIT_" prefix to avoid conflicts.

Here is a patch, requesting for comments.

 - Renames the following environment variables:

    New name                Old Name

    GIT_AUTHOR_DATE         AUTHOR_DATE
    GIT_AUTHOR_EMAIL        AUTHOR_EMAIL
    GIT_AUTHOR_NAME         AUTHOR_NAME
    GIT_COMMIT_AUTHOR_EMAIL COMMIT_AUTHOR_EMAIL
    GIT_COMMIT_AUTHOR_NAME  COMMIT_AUTHOR_NAME
    GIT_ALTERNATE_OBJECTS   SHA1_FILE_DIRECTORIES
    GIT_OBJECTS             SHA1_FILE_DIRECTORY

 - Changes all users of the environment variable to fetch
   environment variable with the new name.

 - Introduces a compatibility macro, gitenv(), which does an
   getenv() and if it fails calls gitenv_bc(), which in turn
   picks up the value from old name while giving a warning about
   using an old name.

I've also updated the documentation and scripts shipped with
Linus GIT distribution.

The transition plan is as follows:

 - We will keep the backward compatibility list used by gitenv()
   for now, so the current scripts and user environments
   continue to work as before.  The users will get warnings when
   they have old name but not new name in their environment to
   the stderr.

 - The Porcelain layers should start using new names.  However,
   just in case it ends up calling old Plumbing layer
   implementation, they should also export old names, taking
   values from the corresponding new names, during the
   transition period.

 - After a couple of weeks or so, we would drop the
   compatibility support and drop gitenv().  Revert the callers
   to directly call getenv() but keep using the new names.

   The last part is probably optional and the transition
   duration needs to be set to a reasonable value.

Not-quite-signed-off-yet-by: Junio C Hamano <junkio@cox.net>
------------

Documentation/core-git.txt |   17 +++++-----
Makefile                   |    3 +
README                     |    2 -
cache.h                    |   15 +++++++--
commit-tree.c              |   10 +++---
diff.c                     |   10 +++---
git-prune-script           |    8 +++--
gitenv.c                   |   70 +++++++++++++++++++++++++++++++++++++++++++++
init-db.c                  |    7 ++--
rsh.c                      |    4 +-
sha1_file.c                |    8 ++---
11 files changed, 120 insertions(+), 34 deletions(-)

# - HEAD: Fix git-update-cache --cacheinfo error message.
# + 7: Rename Environment Variables
--- a/Documentation/core-git.txt
+++ b/Documentation/core-git.txt
@@ -210,15 +210,16 @@ Environment Variables
 ---------------------
 Various git commands use the following environment variables:
 
-- 'AUTHOR_NAME'
-- 'AUTHOR_EMAIL'
-- 'AUTHOR_DATE'
-- 'COMMIT_AUTHOR_NAME'
-- 'COMMIT_AUTHOR_EMAIL'
+- 'GIT_AUTHOR_NAME'
+- 'GIT_AUTHOR_EMAIL'
+- 'GIT_AUTHOR_DATE'
+- 'GIT_COMMIT_AUTHOR_NAME'
+- 'GIT_COMMIT_AUTHOR_EMAIL'
 - 'GIT_DIFF_OPTS'
 - 'GIT_EXTERNAL_DIFF'
 - 'GIT_INDEX_FILE'
-- 'SHA1_FILE_DIRECTORY'
+- 'GIT_OBJECTS'
+- 'GIT_ALTERNATE_OBJECTS'
 
 
 NAME
@@ -876,7 +877,7 @@ sha1 mismatch <object>::
 Environment Variables
 ---------------------
 
-SHA1_FILE_DIRECTORY::
+GIT_OBJECTS::
 	used to specify the object database root (usually .git/objects)
 
 GIT_INDEX_FILE::
@@ -918,7 +919,7 @@ DESCRIPTION
 This simply creates an empty git object database - basically a `.git`
 directory and `.git/object/??/` directories.
 
-If the object storage directory is specified via the 'SHA1_FILE_DIRECTORY'
+If the object storage directory is specified via the 'GIT_OBJECTS'
 environment variable then the sha1 directories are created underneath -
 otherwise the default `.git/objects` directory is used.
 
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,8 @@ LIB_OBJS += strbuf.o
 LIB_H += diff.h
 LIB_OBJS += diff.o
 
+LIB_OBJS += gitenv.o
+
 LIBS = $(LIB_FILE)
 LIBS += -lz
 
@@ -116,6 +118,7 @@ sha1_file.o: $(LIB_H)
 usage.o: $(LIB_H)
 diff.o: $(LIB_H)
 strbuf.o: $(LIB_H)
+gitenv.o: $(LIB_H)
 
 clean:
 	rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROG) $(LIB_FILE)
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ There are two object abstractions: the "
 
 
 
-	The Object Database (SHA1_FILE_DIRECTORY)
+	The Object Database (GIT_OBJECTS)
 
 
 The object database is literally just a content-addressable collection
--- a/cache.h
+++ b/cache.h
@@ -31,6 +31,13 @@
 #endif
 
 /*
+ * Environment variables transition.
+ * We accept older names for now but warn.
+ */
+extern char *gitenv_bc(const char *);
+#define gitenv(e) (getenv(e) ? : gitenv_bc(e))
+
+/*
  * Basic data structures for the directory cache
  *
  * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
@@ -99,16 +106,16 @@ static inline unsigned int create_ce_mod
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc, active_cache_changed;
 
-#define DB_ENVIRONMENT "SHA1_FILE_DIRECTORY"
+#define DB_ENVIRONMENT "GIT_OBJECTS"
 #define DEFAULT_DB_ENVIRONMENT ".git/objects"
-#define ALTERNATE_DB_ENVIRONMENT "SHA1_FILE_DIRECTORIES"
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECTS"
 
-#define get_object_directory() (getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
+#define get_object_directory() (gitenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
 
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define DEFAULT_INDEX_ENVIRONMENT ".git/index"
 
-#define get_index_file() (getenv(INDEX_ENVIRONMENT) ? : DEFAULT_INDEX_ENVIRONMENT)
+#define get_index_file() (gitenv(INDEX_ENVIRONMENT) ? : DEFAULT_INDEX_ENVIRONMENT)
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -146,11 +146,11 @@ int main(int argc, char **argv)
 	datestamp(realdate, sizeof(realdate));
 	strcpy(date, realdate);
 
-	commitgecos = getenv("COMMIT_AUTHOR_NAME") ? : realgecos;
-	commitemail = getenv("COMMIT_AUTHOR_EMAIL") ? : realemail;
-	gecos = getenv("AUTHOR_NAME") ? : realgecos;
-	email = getenv("AUTHOR_EMAIL") ? : realemail;
-	audate = getenv("AUTHOR_DATE");
+	commitgecos = gitenv("GIT_COMMIT_AUTHOR_NAME") ? : realgecos;
+	commitemail = gitenv("GIT_COMMIT_AUTHOR_EMAIL") ? : realemail;
+	gecos = gitenv("GIT_AUTHOR_NAME") ? : realgecos;
+	email = gitenv("GIT_AUTHOR_EMAIL") ? : realemail;
+	audate = gitenv("GIT_AUTHOR_DATE");
 	if (audate)
 		parse_date(audate, date, sizeof(date));
 
--- a/diff.c
+++ b/diff.c
@@ -8,11 +8,11 @@
 #include "cache.h"
 #include "diff.h"
 
-static char *diff_opts = "-pu";
+static const char *diff_opts = "-pu";
 
 static const char *external_diff(void)
 {
-	static char *external_diff_cmd = NULL;
+	static const char *external_diff_cmd = NULL;
 	static int done_preparing = 0;
 
 	if (done_preparing)
@@ -26,11 +26,11 @@ static const char *external_diff(void)
 	 *
 	 * GIT_DIFF_OPTS="-c";
 	 */
-	if (getenv("GIT_EXTERNAL_DIFF"))
-		external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
+	if (gitenv("GIT_EXTERNAL_DIFF"))
+		external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF");
 
 	/* In case external diff fails... */
-	diff_opts = getenv("GIT_DIFF_OPTS") ? : diff_opts;
+	diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts;
 
 	done_preparing = 1;
 	return external_diff_cmd;
--- a/git-prune-script
+++ b/git-prune-script
@@ -28,9 +28,13 @@ sed -ne '/unreachable /{
     s/unreachable [^ ][^ ]* //
     s|\(..\)|\1/|p
 }' | {
-	case "$SHA1_FILE_DIRECTORY" in
+	for d in "$GIT_OBJECTS" "$SHA1_FILE_DIRECTORY" ''
+	do
+		test "$d" != "" && test -d "$d" && break
+	done
+	case "$d" in
 	'') cd .git/objects/ ;;
-	*) cd "$SHA1_FILE_DIRECTORY" ;;
+	*) cd "$d" ;;
 	esac || exit
 	xargs -r $dryrun rm -f
 }
Created: gitenv.c (mode:100644)
--- /dev/null
+++ b/gitenv.c
@@ -0,0 +1,70 @@
+#include "cache.h"
+
+/*
+ * This array must be sorted by its canonical name, because
+ * we do look-up by binary search.
+ */
+static struct backward_compatible_env {
+	const char *canonical;
+	const char *old;
+} bc_name[] = {
+	{ "GIT_ALTERNATE_OBJECTS", "SHA1_FILE_DIRECTORIES" },
+	{ "GIT_AUTHOR_DATE", "AUTHOR_DATE" },
+	{ "GIT_AUTHOR_EMAIL", "AUTHOR_EMAIL" },
+	{ "GIT_AUTHOR_NAME", "AUTHOR_NAME" }, 
+	{ "GIT_COMMIT_AUTHOR_EMAIL", "COMMIT_AUTHOR_EMAIL" },
+	{ "GIT_COMMIT_AUTHOR_NAME", "COMMIT_AUTHOR_NAME" },
+	{ "GIT_OBJECTS", "SHA1_FILE_DIRECTORY" },
+};
+
+static void warn_old_environment(void)
+{
+	int i;
+	static int warned = 0;
+	if (warned)
+		return;
+
+	warned = 1;
+	fprintf(stderr,
+		"warning: GIT environment variables have been renamed.\n"
+		"warning: Please adjust your scripts and environment.\n");
+	for (i = 0; i < sizeof(bc_name) / sizeof(bc_name[0]); i++) {
+		/* warning is needed only when old name is there and
+		 * new name is not.
+		 */
+		if (!getenv(bc_name[i].canonical) && getenv(bc_name[i].old))
+			fprintf(stderr, "warning: old %s => new %s\n",
+				bc_name[i].old, bc_name[i].canonical);
+	}
+}
+
+char *gitenv_bc(const char *e)
+{
+	int first, last;
+	char *val = getenv(e);
+	if (val)
+		/* inefficient.  caller should use gitenv() not gitenv_bc() */
+		return val;
+
+	first = 0;
+	last = sizeof(bc_name) / sizeof(bc_name[0]);
+	while (last > first) {
+		int next = (last + first) >> 1;
+		int cmp = strcmp(e, bc_name[next].canonical);
+		if (!cmp) {
+			val = getenv(bc_name[next].old);
+			/* If the user has only old name, warn.
+			 * otherwise stay silent.
+			 */
+			if (val)
+				warn_old_environment();
+			return val;
+		}
+		if (cmp < 0) {
+			last = next;
+			continue;
+		}
+		first = next+1;
+	}
+	return NULL;
+}
--- a/init-db.c
+++ b/init-db.c
@@ -5,7 +5,7 @@
  */
 #include "cache.h"
 
-void safe_create_dir(char *dir)
+void safe_create_dir(const char *dir)
 {
 	if (mkdir(dir, 0755) < 0) {
 		if (errno != EEXIST) {
@@ -23,12 +23,13 @@ void safe_create_dir(char *dir)
  */
 int main(int argc, char **argv)
 {
-	char *sha1_dir, *path;
+	const char *sha1_dir;
+	char *path;
 	int len, i;
 
 	safe_create_dir(".git");
 
-	sha1_dir = getenv(DB_ENVIRONMENT);
+	sha1_dir = gitenv(DB_ENVIRONMENT);
 	if (!sha1_dir) {
 		sha1_dir = DEFAULT_DB_ENVIRONMENT;
 		fprintf(stderr, "defaulting to local storage area\n");
--- a/rsh.c
+++ b/rsh.c
@@ -36,8 +36,8 @@ int setup_connection(int *fd_in, int *fd
 	*(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);
+		 "cd /%s; %s=objects %s",
+		 path, DB_ENVIRONMENT, remote_prog);
 	posn = command + strlen(command);
 	for (i = 0; i < rmt_argc; i++) {
 		*(posn++) = ' ';
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -120,7 +120,7 @@ static void fill_sha1_path(char *pathbuf
  *
  * Also note that this returns the location for creating.  Reading
  * SHA1 file can happen from any alternate directory listed in the
- * SHA1_FILE_DIRECTORIES environment variable if it is not found in
+ * DB_ENVIRONMENT environment variable if it is not found in
  * the primary object database.
  */
 char *sha1_file_name(const unsigned char *sha1)
@@ -128,7 +128,7 @@ char *sha1_file_name(const unsigned char
 	static char *name, *base;
 
 	if (!base) {
-		char *sha1_file_directory = get_object_directory();
+		const char *sha1_file_directory = get_object_directory();
 		int len = strlen(sha1_file_directory);
 		base = xmalloc(len + 60);
 		memcpy(base, sha1_file_directory, len);
@@ -151,7 +151,7 @@ static struct alternate_object_database 
  * alt_odb points at an array of struct alternate_object_database.
  * This array is terminated with an element that has both its base
  * and name set to NULL.  alt_odb[n] comes from n'th non-empty
- * element from colon separated $SHA1_FILE_DIRECTORIES environment
+ * element from colon separated ALTERNATE_DB_ENVIRONMENT environment
  * variable, and its base points at a statically allocated buffer
  * that contains "/the/directory/corresponding/to/.git/objects/...",
  * while its name points just after the slash at the end of
@@ -167,7 +167,7 @@ static void prepare_alt_odb(void)
 	int pass, totlen, i;
 	const char *cp, *last;
 	char *op = 0;
-	const char *alt = getenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
+	const char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
 
 	/* The first pass counts how large an area to allocate to
 	 * hold the entire alt_odb structure, including array of


^ permalink raw reply	[relevance 9%]

* Introducing GIT_DIR environment variable.
  @ 2005-05-10  6:25 11%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-10  6:25 UTC (permalink / raw)
  To: Petr Baudis, Daniel Barkalow; +Cc: git

Ok, following the mailing list discussion, I've done GIT_DIR and
pushed it out to the usual git-jc repository, at:

    http://members.cox.net/junkio/git-jc.git/

Author: Junio C Hamano <junkio@cox.net>
Date:   Mon May 9 22:57:58 2005 -0700
    
    Introduce GIT_DIR environment variable.
    
    During the mailing list discussion on renaming GIT_ environment
    variables, people felt that having one environment that lets the
    user (or Porcelain) specify both SHA1_FILE_DIRECTORY (now
    GIT_OBJECT_DIRECTORY) and GIT_INDEX_FILE for the default layout
    would be handy.  This change introduces GIT_DIR environment
    variable, from which the defaults for GIT_INDEX_FILE and
    GIT_OBJECT_DIRECTORY are derived.  When GIT_DIR is not defined,
    it defaults to ".git".  GIT_INDEX_FILE defaults to
    "$GIT_DIR/index" and GIT_OBJECT_DIRECTORY defaults to
    "$GIT_DIR/objects".
    
    Special thanks for ideas and discussions go to Petr Baudis and
    Daniel Barkalow.  Bugs are mine ;-)
    
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
--- a/cache.h
+++ b/cache.h
@@ -106,16 +106,15 @@ static inline unsigned int create_ce_mod
 struct cache_entry **active_cache;
 unsigned int active_nr, active_alloc, active_cache_changed;
 
+#define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
-#define DEFAULT_DB_ENVIRONMENT ".git/objects"
-#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
-
-#define get_object_directory() (gitenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT)
-
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
-#define DEFAULT_INDEX_ENVIRONMENT ".git/index"
 
-#define get_index_file() (gitenv(INDEX_ENVIRONMENT) ? : DEFAULT_INDEX_ENVIRONMENT)
+extern char *get_object_directory(void);
+extern char *get_index_file(void);
+
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
--- a/git-prune-script
+++ b/git-prune-script
@@ -11,6 +11,9 @@ do
     shift;
 done
 
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="${SHA1_FILE_DIRECTORY-"$GIT_DIR/objects"}"}
+
 # Defaulting to include .git/refs/*/* may be debatable from the
 # purist POV but power users can always give explicit parameters
 # to the script anyway.
@@ -19,7 +22,8 @@ case "$#" in
 0)
     x_40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
     x_40="$x_40$x_40$x_40$x_40$x_40$x_40$x_40$x_40"
-    set x $(sed -ne "/^$x_40\$/p" .git/HEAD .git/refs/*/* 2>/dev/null)
+    set x $(sed -ne "/^$x_40\$/p" \
+	"$GIT_DIR"/HEAD "$GIT_DIR"/refs/*/* /dev/null 2>/dev/null)
     shift ;;
 esac
 
@@ -28,13 +32,7 @@ sed -ne '/unreachable /{
     s/unreachable [^ ][^ ]* //
     s|\(..\)|\1/|p
 }' | {
-	for d in "$GIT_OBJECT_DIRECTORY" "$SHA1_FILE_DIRECTORY" ''
-	do
-		test "$d" != "" && test -d "$d" && break
-	done
-	case "$d" in
-	'') cd .git/objects/ ;;
-	*) cd "$d" ;;
-	esac || exit
+	cd "$GIT_OBJECT_DIRECTORY" || exit
 	xargs -r $dryrun rm -f
 }
+
--- a/git-pull-script
+++ b/git-pull-script
@@ -3,6 +3,9 @@
 merge_repo=$1
 merge_name=${2:-HEAD}
 
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="${SHA1_FILE_DIRECTORY-"$GIT_DIR/objects"}"}
+
 download_one () {
 	# remote_path="$1" local_file="$2"
 	case "$1" in
@@ -25,16 +28,19 @@ download_objects () {
 		git-local-pull -l -a "$2" "$1/"
 		;;
 	*)
-		rsync -avz --ignore-existing "$1/objects/." \
-			${SHA_FILE_DIRECTORY:-.git/objects}/.
+		rsync -avz --ignore-existing \
+			"$1/objects/." "$GIT_OBJECT_DIRECTORY"/.
 		;;
 	esac
 }
 
 echo "Getting remote $merge_name"
-download_one "$merge_repo/$merge_name" .git/MERGE_HEAD
+download_one "$merge_repo/$merge_name" "$GIT_DIR"/MERGE_HEAD
 
 echo "Getting object database"
-download_objects "$merge_repo" "$(cat .git/MERGE_HEAD)"
+download_objects "$merge_repo" "$(cat "$GIT_DIR"/MERGE_HEAD)"
 
-git-resolve-script "$(cat .git/HEAD)" "$(cat .git/MERGE_HEAD)" "$merge_repo"
+git-resolve-script \
+	"$(cat "$GIT_DIR"/HEAD)" \
+	"$(cat "$GIT_DIR"/MERGE_HEAD)" \
+	"$merge_repo"
--- a/git-resolve-script
+++ b/git-resolve-script
@@ -1,14 +1,19 @@
 #!/bin/sh
 #
+# Copyright (c) 2005 Linus Torvalds
+#
 # Resolve two trees.
 #
 head="$1"
 merge="$2"
 merge_repo="$3"
 
-rm -f .git/MERGE_HEAD .git/ORIG_HEAD
-echo $head > .git/ORIG_HEAD
-echo $merge > .git/MERGE_HEAD
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="${SHA1_FILE_DIRECTORY-"$GIT_DIR/objects"}"}
+
+rm -f "$GIT_DIR"/MERGE_HEAD "$GIT_DIR"/ORIG_HEAD
+echo $head > "$GIT_DIR"/ORIG_HEAD
+echo $merge > "$GIT_DIR"/MERGE_HEAD
 
 #
 # The remote name is just used for the message,
@@ -35,7 +40,7 @@ if [ "$common" == "$head" ]; then
 	echo "Kill me within 3 seconds.."
 	sleep 3
 	git-read-tree -m $merge && git-checkout-cache -f -a && git-update-cache --refresh
-	echo $merge > .git/HEAD
+	echo $merge > "$GIT_DIR"/HEAD
 	git-diff-tree -p ORIG_HEAD HEAD | diffstat -p1
 	exit 0
 fi
@@ -51,6 +56,6 @@ if [ $? -ne 0 ]; then
 fi
 result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree -p $head -p $merge)
 echo "Committed merge $result_commit"
-echo $result_commit > .git/HEAD
+echo $result_commit > "$GIT_DIR"/HEAD
 git-checkout-cache -f -a && git-update-cache --refresh
 git-diff-tree -p ORIG_HEAD HEAD | diffstat -p1
--- a/git-tag-script
+++ b/git-tag-script
@@ -1,5 +1,9 @@
 #!/bin/sh
-object=${2:-$(cat .git/HEAD)}
+# Copyright (c) 2005 Linus Torvalds
+
+: ${GIT_DIR=.git}
+
+object=${2:-$(cat "$GIT_DIR"/HEAD)}
 type=$(git-cat-file -t $object) || exit 1
 ( echo -e "object $object\ntype $type\ntag $1\n"; cat ) > .tmp-tag
 rm -f .tmp-tag.asc
--- a/init-db.c
+++ b/init-db.c
@@ -27,11 +27,12 @@ int main(int argc, char **argv)
 	char *path;
 	int len, i;
 
-	safe_create_dir(".git");
-
-	sha1_dir = gitenv(DB_ENVIRONMENT);
-	if (!sha1_dir) {
-		sha1_dir = DEFAULT_DB_ENVIRONMENT;
+	sha1_dir = get_object_directory();
+	if (!gitenv(DB_ENVIRONMENT) && !gitenv(GIT_DIR_ENVIRONMENT)) {
+		/* We create leading paths only when we fall back
+		 * to local .git/objects, at least for now.
+		 */
+		safe_create_dir(DEFAULT_GIT_DIR_ENVIRONMENT);
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
 	len = strlen(sha1_dir);
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -59,6 +59,38 @@ int get_sha1_file(const char *path, unsi
 	return get_sha1_hex(buffer, result);
 }
 
+static char *git_dir, *git_object_dir, *git_index_file;
+static void setup_git_env(void)
+{
+	git_dir = gitenv(GIT_DIR_ENVIRONMENT);
+	if (!git_dir)
+		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+	git_object_dir = gitenv(DB_ENVIRONMENT);
+	if (!git_object_dir) {
+		git_object_dir = xmalloc(strlen(git_dir) + 9);
+		sprintf(git_object_dir, "%s/objects", git_dir);
+	}
+	git_index_file = gitenv(INDEX_ENVIRONMENT);
+	if (!git_index_file) {
+		git_index_file = xmalloc(strlen(git_dir) + 7);
+		sprintf(git_index_file, "%s/index", git_dir);
+	}
+}
+
+char *get_object_directory(void)
+{
+	if (!git_object_dir)
+		setup_git_env();
+	return git_object_dir;
+}
+
+char *get_index_file(void)
+{
+	if (!git_index_file)
+		setup_git_env();
+	return git_index_file;
+}
+
 int get_sha1(const char *str, unsigned char *sha1)
 {
 	static char pathname[PATH_MAX];
@@ -70,15 +102,16 @@ int get_sha1(const char *str, unsigned c
 		"refs/snap",
 		NULL
 	};
-	const char *gitdir;
 	const char **p;
 
 	if (!get_sha1_hex(str, sha1))
 		return 0;
 
-	gitdir = ".git";
+	if (!git_dir)
+		setup_git_env();
 	for (p = prefix; *p; p++) {
-		snprintf(pathname, sizeof(pathname), "%s/%s/%s", gitdir, *p, str);
+		snprintf(pathname, sizeof(pathname), "%s/%s/%s",
+			 git_dir, *p, str);
 		if (!get_sha1_file(pathname, sha1))
 			return 0;
 	}




^ permalink raw reply	[relevance 11%]

* [PATCH] Support symlinks in git-ls-files --others.
@ 2005-05-12  7:48 16% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-12  7:48 UTC (permalink / raw)
  To: pasky, Kay Sievers; +Cc: git

It is kind of surprising that this was missed in the last round,
but the work tree scanner in git-ls-files is still deliberately
ignoring symlinks.  This patch fixes it.

This depends on the test suite infrastructure I sent in earlier.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

Petr, I am not CCing Linus and you know what I mean by it ;-).

cache.h             |    1 +
ls-files.c          |    8 +++++---
t/t0400-ls-files.sh |   29 +++++++++++++++++++++++++++++
3 files changed, 35 insertions(+), 3 deletions(-)
t/t0400-ls-files.sh (. --> 100755)

--- a/cache.h
+++ b/cache.h
@@ -27,6 +27,7 @@
 #define DT_UNKNOWN	0
 #define DT_DIR		1
 #define DT_REG		2
+#define DT_LNK		3
 #define DTYPE(de)	DT_UNKNOWN
 #endif
 
--- a/ls-files.c
+++ b/ls-files.c
@@ -109,8 +109,9 @@
 
 /*
  * Read a directory tree. We currently ignore anything but
- * directories and regular files. That's because git doesn't
- * handle them at all yet. Maybe that will change some day.
+ * directories, regular files and symlinks. That's because git
+ * doesn't handle them at all yet. Maybe that will change some
+ * day.
  *
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
@@ -141,7 +142,7 @@
 			case DT_UNKNOWN:
 				if (lstat(fullname, &st))
 					continue;
-				if (S_ISREG(st.st_mode))
+				if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
 					break;
 				if (!S_ISDIR(st.st_mode))
 					continue;
@@ -152,6 +153,7 @@
 					       baselen + len + 1);
 				continue;
 			case DT_REG:
+			case DT_LNK:
 				break;
 			}
 			add_name(fullname, baselen + len);
--- a/t/t0400-ls-files.sh
+++ b/t/t0400-ls-files.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+. ./test-lib.sh
+test_description "$@" 'git-ls-files test.
+
+This test runs git-ls-files --others with the following on the
+filesystem.
+
+    path0       - a file
+    path1	- a symlink
+    path2/file2 - a file in a directory
+'
+
+date >path0
+ln -s xyzzy path1
+mkdir path2
+date >path2/file2
+git-ls-files --others >.output
+cat >.expected <<EOF
+path0
+path1
+path2/file2
+EOF
+
+test_expect_success 'diff .output .expected'
+test_done
------------------------------------------------

Compilation finished at Thu May 12 00:43:56


^ permalink raw reply	[relevance 16%]

* [PATCH 2/3] Support symlinks in git-ls-files --others.
@ 2005-05-13  0:16 18% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-13  0:16 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

It is kind of surprising that this was missed in the last round,
but the work tree scanner in git-ls-files was still deliberately
ignoring symlinks.  This patch fixes it, so that --others will
correctly report unregistered symlinks.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

cache.h    |    1 +
ls-files.c |    8 +++++---
2 files changed, 6 insertions(+), 3 deletions(-)

--- a/cache.h
+++ b/cache.h
@@ -27,6 +27,7 @@
 #define DT_UNKNOWN	0
 #define DT_DIR		1
 #define DT_REG		2
+#define DT_LNK		3
 #define DTYPE(de)	DT_UNKNOWN
 #endif
 
--- a/ls-files.c
+++ b/ls-files.c
@@ -109,8 +109,9 @@
 
 /*
  * Read a directory tree. We currently ignore anything but
- * directories and regular files. That's because git doesn't
- * handle them at all yet. Maybe that will change some day.
+ * directories, regular files and symlinks. That's because git
+ * doesn't handle them at all yet. Maybe that will change some
+ * day.
  *
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
@@ -141,7 +142,7 @@
 			case DT_UNKNOWN:
 				if (lstat(fullname, &st))
 					continue;
-				if (S_ISREG(st.st_mode))
+				if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
 					break;
 				if (!S_ISDIR(st.st_mode))
 					continue;
@@ -152,6 +153,7 @@
 					       baselen + len + 1);
 				continue;
 			case DT_REG:
+			case DT_LNK:
 				break;
 			}
 			add_name(fullname, baselen + len);
------------------------------------------------


^ permalink raw reply	[relevance 18%]

* [PATCH 1/4] Support for refs directory
  @ 2005-05-13  6:53 19% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-05-13  6:53 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git, Linus Torvalds

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

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
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];


^ permalink raw reply	[relevance 19%]

* Re: speeding up cg-log -u
  @ 2005-05-14  8:13 15% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-14  8:13 UTC (permalink / raw)
  To: Zack Brown; +Cc: git

>>>>> "ZB" == Zack Brown <zbrown@tumblerings.org> writes:

ZB> Would it be faster to handle this on the git side, telling git to only
ZB> retrieve the logs that match the specified query? If feasible, this might
ZB> speed up various web interfaces into git repositories.

Here are two places you can add a simple hook.  Implementation
of author_match() function is left as an exercise for you ;-).
Let us know if you get speed improvements, please.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
$ jit-diff
# - 9: (Anonymous snapshot)
# + (working tree)
--- a/cache.h
+++ b/cache.h
@@ -178,6 +178,7 @@ extern void *read_object_with_reference(
 const char *show_date(unsigned long time, int timezone);
 void parse_date(char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
+int author_match(struct commit *, const char *);
 
 static inline void *xmalloc(int size)
 {
--- a/rev-list.c
+++ b/rev-list.c
@@ -11,6 +11,7 @@ int main(int argc, char **argv)
 	unsigned long max_age = -1;
 	unsigned long min_age = -1;
 	int max_count = -1;
+	const char *author = NULL;
 
 	for (i = 1 ; i < argc; i++) {
 		char *arg = argv[i];
@@ -21,6 +22,8 @@ int main(int argc, char **argv)
 			max_age = atoi(arg + 10);
 		} else if (!strncmp(arg, "--min-age=", 10)) {
 			min_age = atoi(arg + 10);
+		} else if (!strncmp(arg, "--author=", 9)) {
+			author = arg + 9;
 		} else {
 			commit_arg = arg;
 		}
@@ -28,6 +31,7 @@ int main(int argc, char **argv)
 
 	if (!commit_arg || get_sha1(commit_arg, sha1))
 		usage("usage: rev-list [OPTION] commit-id\n"
+		      "  --author=author\n"
 		      "  --max-count=nr\n"
 		      "  --max-age=epoch\n"
 		      "  --min-age=epoch\n");
@@ -44,6 +48,8 @@ int main(int argc, char **argv)
 			continue;
 		if (max_age != -1 && (commit->date < max_age))
 			break;
+		if (!author_match(commit, author))
+			continue;
 		if (max_count != -1 && !max_count--)
 			break;
 		printf("%s\n", sha1_to_hex(commit->object.sha1));
--- a/rev-tree.c
+++ b/rev-tree.c
@@ -64,7 +64,7 @@ void process_commit(unsigned char *sha1)
 }
 
 /*
- * Usage: rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id2>]
+ * Usage: rev-tree [--edges] [--author <author>] [--cache <cache-file>] <commit-id> [<commit-id2>]
  *
  * The cache-file can be quite important for big trees. This is an
  * expensive operation if you have to walk the whole chain of
@@ -75,6 +75,7 @@ int main(int argc, char **argv)
 	int i;
 	int nr = 0;
 	unsigned char sha1[MAX_COMMITS][20];
+	const char *author = NULL; 
 
 	/*
 	 * First - pick up all the revisions we can (both from
@@ -83,6 +84,11 @@ int main(int argc, char **argv)
 	for (i = 1; i < argc ; i++) {
 		char *arg = argv[i];
 
+		if (!strcmp(arg, "--author")) {
+			author = argv[++i];
+			continue;
+		}
+
 		if (!strcmp(arg, "--cache")) {
 			read_cache_file(argv[++i]);
 			continue;
@@ -98,7 +104,7 @@ int main(int argc, char **argv)
 			basemask |= 1<<nr;
 		}
 		if (nr >= MAX_COMMITS || get_sha1(arg, sha1[nr]))
-			usage("rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]");
+			usage("rev-tree [--edges] [--author <author>] [--cache <cache-file>] <commit-id> [<commit-id>]");
 		process_commit(sha1[nr]);
 		nr++;
 	}
@@ -125,6 +131,9 @@ int main(int argc, char **argv)
 		if (!interesting(commit))
 			continue;
 
+		if (!author_match(commit, author))
+			continue;
+
 		printf("%lu %s:%d", commit->date, sha1_to_hex(obj->sha1), 
 		       obj->flags);
 		p = commit->parents;




^ permalink raw reply	[relevance 15%]

* git-rev-list  in local commit order
@ 2005-05-14 21:44 13% Sean
  0 siblings, 0 replies; 200+ results
From: Sean @ 2005-05-14 21:44 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 1317 bytes --]

Attached is a preliminary hackish patch to sort git-rev-list in local
commit order.   While I don't know how useful this really is, it's
presented as an alternative to the repo-id proposal.  This will work even
if the branch happens to be from a single repository, where repo-id will
not.  However, shared commit objects can cause problems so for best
results use private commit objects for each repository.

For purposes of testing, this patch changes the Cogito default of linking
objects to copying, for local repository pull operations.   This patch
will work with _existing_ repositories where local commit times have been
maintained.

Also attached, is a little test script that demonstrates the local commit
time order.  After running the test script, you can use the cg-log command
in each of the M and R directories to see the difference even though the
two repositories share a head commit.

This patch is not nearly ready for inclusion anywhere just meant for
comment.  It is based off Petr's cogito tree (commit
fa6e9eb368e949e78c4e66217461cf624b52b0a2).

 cache.h     |    1
 cg-pull     |    4 -
 commit.c    |  121
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 commit.h    |    6 ++
 rev-list.c  |    2
 sha1_file.c |    8 +++
 6 files changed, 137 insertions(+), 5 deletions(-)

Sean


[-- Attachment #2: local-rev-list-v1.patch --]
[-- Type: application/octet-stream, Size: 6552 bytes --]

Index: cache.h
===================================================================
--- a/cache.h  (mode:100644)
+++ b/cache.h  (mode:100644)
@@ -157,6 +157,7 @@
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
 
 extern int has_sha1_file(const unsigned char *sha1);
+extern unsigned long sha1_local_date(const unsigned char *sha1);
 
 /* Convert to/from hex/sha1 representation */
 extern int get_sha1(const char *str, unsigned char *sha1);
Index: cg-pull
===================================================================
--- a/cg-pull  (mode:100755)
+++ b/cg-pull  (mode:100755)
@@ -143,7 +143,7 @@
 	[ "$1" = "-i" ] && shift
 	[ "$1" = "-s" ] && shift
 
-	cp_flags_l="-va"
+	cp_flags_l="-vdR"
 	if [ "$1" = "-u" ]; then
 		cp_flags_l="$cp_flags_l -lu"
 		shift
@@ -163,7 +163,7 @@
 }
 
 pull_local () {
-	git-local-pull -a -l -v "$(cat "$_git/refs/heads/$1")" "$2"
+	git-local-pull -a -v "$(cat "$_git/refs/heads/$1")" "$2"
 }
 
 if echo "$uri" | grep -q "^http://"; then
Index: commit.c
===================================================================
--- a/commit.c  (mode:100644)
+++ b/commit.c  (mode:100644)
@@ -2,6 +2,7 @@
 #include "cache.h"
 #include <string.h>
 #include <limits.h>
+#include <stdlib.h>
 
 const char *commit_type = "commit";
 
@@ -13,6 +14,7 @@
 		memset(ret, 0, sizeof(struct commit));
 		created_object(sha1, &ret->object);
 		ret->object.type = commit_type;
+		ret->local_date = sha1_local_date(sha1);
 		return ret;
 	}
 	if (obj->type != commit_type) {
@@ -41,6 +43,18 @@
 	return date;
 }
 
+static void insert_by_local_date(struct commit_list **list, struct commit *item)
+{
+	struct commit_list **pp = list;
+	struct commit_list *p;
+	while ((p = *pp) != NULL) {
+		if (p->item->local_date > item->local_date) 
+			break;
+		pp = &p->next;
+	}
+	commit_list_insert(item, pp);
+}
+
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 {
 	void *bufptr = buffer;
@@ -58,12 +72,13 @@
 	       !get_sha1_hex(bufptr + 7, parent)) {
 		struct commit *new_parent = lookup_commit(parent);
 		if (new_parent) {
-			commit_list_insert(new_parent, &item->parents);
+ 			insert_by_local_date(&item->parents, new_parent);
 			add_ref(&item->object, &new_parent->object);
 		}
 		bufptr += 48;
 	}
 	item->date = parse_commit_date(bufptr);
+	item->merge_nodes = NULL;
 	return 0;
 }
 
@@ -152,3 +167,107 @@
 	}
 	return ret;
 }
+
+struct commit_list *copy_commit_list(struct commit_list *list)
+{
+	struct commit_list *copy = NULL;
+	while (list) {
+		commit_list_insert(list->item, &copy); 
+		list = list->next;
+	}
+	return copy;
+}
+
+int found_on_list(struct commit *item, struct commit_list *list)
+{
+	while (list) {
+		if (list->item == item)
+			return 1;
+		list = list->next;
+	}
+	return 0;
+}
+
+static struct commit *process_local_list(struct commit_list **list_p, 
+					int this_mark, int other_mark)
+{
+	struct commit *item = (*list_p)->item;
+
+	if (item->object.flags & other_mark) {
+		return item;
+	} else {
+		pop_most_recent_commit(list_p, this_mark);
+	}
+	return NULL;
+}
+
+struct commit *common_local_ancestor(struct commit *rev1, struct commit *rev2)
+{
+	struct commit_list *rev1list = NULL;
+	struct commit_list *rev2list = NULL;
+
+	commit_list_insert(rev1, &rev1list); rev1->object.flags |= 0x1;
+	commit_list_insert(rev2, &rev2list); rev2->object.flags |= 0x2;
+	parse_commit(rev1); parse_commit(rev2);
+
+	while (rev1list || rev2list) {
+		struct commit *ret;
+		if (!rev1list) {
+			// process 2
+			ret = process_local_list(&rev2list, 0x2, 0x1);
+		} else if (!rev2list) {
+			// process 1
+			ret = process_local_list(&rev1list, 0x1, 0x2);
+		} else if (rev1list->item->local_date 
+				< rev2list->item->local_date) {
+			// process 2
+			ret = process_local_list(&rev2list, 0x2, 0x1);
+		} else {
+			// process 1
+			ret = process_local_list(&rev1list, 0x1, 0x2);
+		}
+		if (ret) {
+			free_commit_list(rev1list);
+			free_commit_list(rev2list);
+			return ret;
+		}
+	}
+	return NULL;
+}
+
+void insert_merge_nodes(struct commit_list *plist,
+			struct commit_list *stop,
+			struct commit *node)
+{
+	struct commit_list *p;
+	for (p=plist; p != stop; p=p->next)
+		commit_list_insert(	common_local_ancestor(node, p->item),
+					&node->merge_nodes);
+}
+
+struct commit *pop_newest_local_commit(	struct commit_list **list,
+					unsigned int mark)
+{
+	struct commit *ret = (*list)->item;
+	struct commit_list *parents = ret->parents;
+	struct commit_list *old = *list;
+	struct commit_list *prev = ret->merge_nodes;
+
+	*list = (*list)->next;
+	free(old);
+
+	/* Loop expects parents to be ordered oldest to newest on local time */
+	while (parents) {
+		struct commit *commit = parents->item;
+		parse_commit(commit);
+		if (!((commit->object.flags & mark) | 
+                       found_on_list(commit, ret->merge_nodes))) {
+			commit->object.flags |= mark;
+			prev = commit->merge_nodes = copy_commit_list(prev);
+			insert_merge_nodes(ret->parents, parents, commit);
+			commit_list_insert(commit, list);
+		}
+		parents = parents->next;
+	}
+	return ret;
+}
Index: commit.h
===================================================================
--- a/commit.h  (mode:100644)
+++ b/commit.h  (mode:100644)
@@ -11,8 +11,9 @@
 
 struct commit {
 	struct object object;
-	unsigned long date;
+	unsigned long date, local_date;
 	struct commit_list *parents;
+	struct commit_list *merge_nodes;
 	struct tree *tree;
 };
 
@@ -36,4 +37,7 @@
 struct commit *pop_most_recent_commit(struct commit_list **list, 
 				      unsigned int mark);
 
+struct commit *pop_newest_local_commit(	struct commit_list **list,
+					unsigned int mark);
+
 #endif /* COMMIT_H */
Index: rev-list.c
===================================================================
--- a/rev-list.c  (mode:100644)
+++ b/rev-list.c  (mode:100644)
@@ -38,7 +38,7 @@
 
 	commit_list_insert(commit, &list);
 	do {
-		struct commit *commit = pop_most_recent_commit(&list, 0x1);
+		struct commit *commit = pop_newest_local_commit(&list, 0x4);
 
 		if (min_age != -1 && (commit->date > min_age))
 			continue;
Index: sha1_file.c
===================================================================
--- a/sha1_file.c  (mode:100644)
+++ b/sha1_file.c  (mode:100644)
@@ -577,6 +577,14 @@
 	return !!find_sha1_file(sha1, &st);
 }
 
+unsigned long sha1_local_date(const unsigned char *sha1)
+{
+	struct stat st;
+	if (find_sha1_file(sha1, &st))
+		return st.st_mtime;
+	return 0;
+}
+
 int index_fd(unsigned char *sha1, int fd, struct stat *st)
 {
 	unsigned long size = st->st_size;

[-- Attachment #3: test-local-rev-list-v1.sh --]
[-- Type: application/octet-stream, Size: 921 bytes --]

#!/bin/bash
die() { echo "death: $*" ; exit 1; }
mkdir R && cd R || die "on mkdir R"
cg-init < /dev/null || die "R init"

touch one ; cg-add one || die "adding Rn-3"
echo "Rn-3" | cg-commit || die "committing Rn-3"

cd .. || die "cd base"
cg-clone R M || die "cloning"

cd M || die "cd M"
touch two; cg-add two || die "adding Mn-1"
echo "Mn-1" | cg-commit || die "committing Mn-1"

cd ../R || die "cd ../R"
touch three; cg-add three || die "adding Rn-2"
echo "Rn-2" | cg-commit || die "committing Rn-2"

cd ../M || die "cd ../M"
touch four; cg-add four || die "adding Mn"
echo "Mn" | cg-commit || die "committing Mn"

cd ../R || die "cd ../R"
touch five; cg-add five || die "adding Rn-1"
echo "Rn-1" | cg-commit || die "committing Rn-1"

sleep 1
cg-branch-add M ../M/.git || die "adding M branch"
echo "Rn" | cg-update M || die "merging M"

sleep 1
cd ../M || die "cd ../M"
cg-update origin || die "fast forwarding to R"

^ permalink raw reply	[relevance 13%]

* [PATCH] Implement git-checkout-cache -u to update stat information in the cache.
@ 2005-05-15  8:36 19% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-15  8:36 UTC (permalink / raw)
  To: pasky; +Cc: git, torvalds

With -u flag, git-checkout-cache picks up the stat information
from newly created files and updates the cache.  This removes the
need to run git-update-cache --refresh immediately after running
git-checkout-cache.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

Documentation/git-checkout-cache.txt |    6 +++
Makefile                             |    2 -
cache.h                              |    9 +++++
checkout-cache.c                     |   35 ++++++++++++++++++++-
index.c                              |   58 +++++++++++++++++++++++++++++++++++
read-cache.c                         |   20 ++++++++++++
t/t2002-checkout-cache-u.sh          |   35 +++++++++++++++++++++
update-cache.c                       |   48 ++--------------------------
8 files changed, 166 insertions(+), 47 deletions(-)
index.c (. --> 100644)
t/t0110-environment-names-old.sh (100644 --> 100755)
t/t1000-read-tree-m-3way.sh (100644 --> 100755)
t/t2002-checkout-cache-u.sh (. --> 100755)
t/t4000-diff-format.sh (100644 --> 100755)

--- a/Documentation/git-checkout-cache.txt
+++ b/Documentation/git-checkout-cache.txt
@@ -9,7 +9,7 @@
 
 SYNOPSIS
 --------
-'git-checkout-cache' [-q] [-a] [-f] [-n] [--prefix=<string>]
+'git-checkout-cache' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
 	           [--] <file>...
 
 DESCRIPTION
@@ -19,6 +19,10 @@
 
 OPTIONS
 -------
+-u::
+	update stat information for the checked out entries in
+	the cache file.
+
 -q::
 	be quiet if files exist or are not in the cache
 
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@
 	$(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 index.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h
 
--- a/cache.h
+++ b/cache.h
@@ -131,6 +131,15 @@
 extern int same_name(struct cache_entry *a, struct cache_entry *b);
 extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
+
+struct cache_file {
+	struct cache_file *next;
+	char lockfile[PATH_MAX];
+};
+extern int hold_index_file_for_update(struct cache_file *, const char *path);
+extern int commit_index_file(struct cache_file *);
+extern void rollback_index_file(struct cache_file *);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
--- a/checkout-cache.c
+++ b/checkout-cache.c
@@ -36,7 +36,7 @@
 #include <dirent.h>
 #include "cache.h"
 
-static int force = 0, quiet = 0, not_new = 0;
+static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;
 
 static void create_directories(const char *path)
 {
@@ -154,6 +154,12 @@
 		free(new);
 		return error("checkout-cache: unknown file mode for %s", path);
 	}
+
+	if (refresh_cache) {
+		struct stat st;
+		lstat(ce->name, &st);
+		fill_stat_cache_info(ce, &st);
+	}
 	return 0;
 }
 
@@ -224,6 +230,8 @@
 {
 	int i, force_filename = 0;
 	const char *base_dir = "";
+	struct cache_file cache_file;
+	int newfd = -1;
 
 	if (read_cache() < 0) {
 		die("invalid cache");
@@ -252,12 +260,37 @@
 				not_new = 1;
 				continue;
 			}
+			if (!strcmp(arg, "-u")) {
+				refresh_cache = 1;
+				if (newfd < 0)
+					newfd = hold_index_file_for_update
+						(&cache_file,
+						 get_index_file());
+				if (newfd < 0)
+					die("cannot open index.lock file.");
+				continue;
+			}
 			if (!memcmp(arg, "--prefix=", 9)) {
 				base_dir = arg+9;
 				continue;
 			}
 		}
+		if (base_dir[0]) {
+			/* when --prefix is specified we do not
+			 * want to update cache.
+			 */
+			if (refresh_cache) {
+				close(newfd); newfd = -1;
+				rollback_index_file(&cache_file);
+			}
+			refresh_cache = 0;
+		}
 		checkout_file(arg, base_dir);
 	}
+
+	if (0 <= newfd &&
+	    (write_cache(newfd, active_cache, active_nr) ||
+	     commit_index_file(&cache_file)))
+		die("Unable to write new cachefile");
 	return 0;
 }
--- a/index.c
+++ b/index.c
@@ -0,0 +1,58 @@
+/*
+ * GIT - The information manager from hell
+ * Cache-file locking management.
+ *
+ * Copyright (c) 2005 Junio C Hamano.
+ */
+#include <signal.h>
+#include "cache.h"
+
+static struct cache_file *cache_file_list = NULL;
+
+static void remove_lock_file(void)
+{
+	while (cache_file_list) {
+		if (cache_file_list->lockfile[0])
+			unlink(cache_file_list->lockfile);
+		cache_file_list = cache_file_list->next;
+	}
+}
+
+static void remove_lock_file_on_signal(int signo)
+{
+	remove_lock_file();
+}
+
+int commit_index_file(struct cache_file *cf)
+{
+	int i;
+	char indexfile[PATH_MAX];
+
+	strcpy(indexfile, cf->lockfile);
+	i = strlen(indexfile);
+	indexfile[i - 5] = 0; /* .lock */
+	i = rename(cf->lockfile, indexfile);
+	cf->lockfile[0] = 0;
+	return i;
+}
+
+void rollback_index_file(struct cache_file *cf)
+{
+	unlink(cf->lockfile);
+	cf->lockfile[0] = 0;
+}
+
+int hold_index_file_for_update(struct cache_file *cf, const char *path)
+{
+	int newfd;
+
+	sprintf(cf->lockfile, "%s.lock", path);
+	cf->next = cache_file_list;
+	cache_file_list = cf;
+	newfd = open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0600);
+	if (!cf->next) {
+		signal(SIGINT, remove_lock_file_on_signal);
+		atexit(remove_lock_file);
+	}
+	return newfd;
+}
--- a/read-cache.c
+++ b/read-cache.c
@@ -9,6 +9,26 @@
 struct cache_entry **active_cache = NULL;
 unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 
+/*
+ * This only updates the "non-critical" parts of the directory
+ * cache, ie the parts that aren't tracked by GIT, and only used
+ * to validate the cache.
+ */
+void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
+{
+	ce->ce_ctime.sec = htonl(st->st_ctime);
+	ce->ce_mtime.sec = htonl(st->st_mtime);
+#ifdef NSEC
+	ce->ce_ctime.nsec = htonl(st->st_ctim.tv_nsec);
+	ce->ce_mtime.nsec = htonl(st->st_mtim.tv_nsec);
+#endif
+	ce->ce_dev = htonl(st->st_dev);
+	ce->ce_ino = htonl(st->st_ino);
+	ce->ce_uid = htonl(st->st_uid);
+	ce->ce_gid = htonl(st->st_gid);
+	ce->ce_size = htonl(st->st_size);
+}
+
 int cache_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
--- a/t/t2002-checkout-cache-u.sh
+++ b/t/t2002-checkout-cache-u.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-checkout-cache -u test.
+
+With -u flag, git-checkout-cache internally runs the equivalent of
+git-update-cache --refresh on the checked out entry.'
+
+. ./test-lib.sh
+
+test_expect_success \
+'preparation' '
+echo frotz >path0 &&
+git-update-cache --add path0 &&
+t=$(git-write-tree)'
+
+test_expect_failure \
+'without -u, git-checkout-cache smudges stat information.' '
+rm -f path0 &&
+git-read-tree $t &&
+git-checkout-cache -f -a &&
+git-diff-files | diff - /dev/null'
+
+test_expect_success \
+'with -u, git-checkout-cache picks up stat information from new files.' '
+rm -f path0 &&
+git-read-tree $t &&
+git-checkout-cache -u -f -a &&
+git-diff-files | diff - /dev/null'
+
+
+
+
--- a/update-cache.c
+++ b/update-cache.c
@@ -3,7 +3,6 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include <signal.h>
 #include "cache.h"
 
 /*
@@ -31,26 +30,6 @@
 	return (unsigned long)ptr > (unsigned long)-1000L;
 }
 
-/*
- * This only updates the "non-critical" parts of the directory
- * cache, ie the parts that aren't tracked by GIT, and only used
- * to validate the cache.
- */
-static void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
-{
-	ce->ce_ctime.sec = htonl(st->st_ctime);
-	ce->ce_mtime.sec = htonl(st->st_mtime);
-#ifdef NSEC
-	ce->ce_ctime.nsec = htonl(st->st_ctim.tv_nsec);
-	ce->ce_mtime.nsec = htonl(st->st_mtim.tv_nsec);
-#endif
-	ce->ce_dev = htonl(st->st_dev);
-	ce->ce_ino = htonl(st->st_ino);
-	ce->ce_uid = htonl(st->st_uid);
-	ce->ce_gid = htonl(st->st_gid);
-	ce->ce_size = htonl(st->st_size);
-}
-
 static int add_file_to_cache(char *path)
 {
 	int size, namelen, option, status;
@@ -313,36 +292,17 @@
 	return add_cache_entry(ce, option);
 }
 
-static const char *lockfile_name = NULL;
-
-static void remove_lock_file(void)
-{
-	if (lockfile_name)
-		unlink(lockfile_name);
-}
-
-static void remove_lock_file_on_signal(int signo)
-{
-	remove_lock_file();
-}
+struct cache_file cache_file;
 
 int main(int argc, char **argv)
 {
 	int i, newfd, entries, has_errors = 0;
 	int allow_options = 1;
-	static char lockfile[MAXPATHLEN+1];
-	const char *indexfile = get_index_file();
-
-	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
-	newfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600);
+	newfd = hold_index_file_for_update(&cache_file, get_index_file());
 	if (newfd < 0)
 		die("unable to create new cachefile");
 
-	signal(SIGINT, remove_lock_file_on_signal);
-	atexit(remove_lock_file);
-	lockfile_name = lockfile;
-
 	entries = read_cache();
 	if (entries < 0)
 		die("cache corrupted");
@@ -401,9 +361,9 @@
 		if (add_file_to_cache(path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(newfd, active_cache, active_nr) ||
+	    commit_index_file(&cache_file))
 		die("Unable to write new cachefile");
 
-	lockfile_name = NULL;
 	return has_errors ? 1 : 0;
 }
------------------------------------------------


^ permalink raw reply	[relevance 19%]

* Re: Darcs-git: a few notes for Git hackers
       [not found]     <Pine.LNX.4.44.0505141851340.2136-200000@bellevue.puremagic.com>
@ 2005-05-15  9:11  9% ` Brad Roberts
  0 siblings, 0 replies; 200+ results
From: Brad Roberts @ 2005-05-15  9:11 UTC (permalink / raw)
  To: git, Petr Baudis; +Cc: Juliusz Chroboczek

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2652 bytes --]

Resending, I left off the mailing list on the to list last time.

> > I wasn't able to finish redoing these against linus tip, but I got most of
> > it done (patches 1-14 of the original 19):
> >
> >   http://gameboy2.puremagic.com:8090/
> >   rsync://gameboy2.puremagic.com/git/
> >
> > The second, third, and forth to last changes need a careful review,
> > they're direct applications of the original patches which were lightly
> > tested during the first round and nothing other than compile tested in
> > this round.
> >
> > I suspect the remaining parts of the original patch series will go in
> > fairly smoothly.  If no one gets to them before tonight I'll finish
> > it up after work.
> >
> > Later,
> > Brad
>
> I've completed the re-merge, and moved to tip of git-pb.git rather than
> tip of git.git.  Unfortunatly that merge was also somewhat intrusive and
> my individual diffs along the way are somewhat useless now.  The entire
> history is available about the above locations still.  Attached is the
> full diff vs git-pb @ 902b92e00e491a60d55c4b2bce122903b8347f34.
>
> The unit tests that are being added are a wonderful thing, thanks so much
> for doing them Junio.
>
> These changes feel rough to me still.  Some areas to discuss / think
> about:
>
> 1) The hunks that change the merge routines from pointer based to index
> based could have been left much less intruded upon by adding a
> get_cache_entry_array(cache) api.
>
> 2) Should the index changing areas be constructing a new index instead of
> shuffling bits within the current index?
>
> 3) The vocabulary and code is inconsistent between cache and index.
>
> 4) read-cache.c does much more than reading.
>
> 5) Like before, cleaning up memory for the cache is a rarity, preferring
> to let the end of the process garbage collect everything.
>
>  cache.h          |   52 ++++++-------
>  check-files.c    |   12 +--
>  checkout-cache.c |   26 +++---
>  diff-cache.c     |   60 ++++++++-------
>  diff-files.c     |   31 ++++---
>  diff-helper.c    |    6 -
>  diff-tree.c      |   50 ++++++------
>  diff.c           |   36 +++++----
>  diff.h           |   11 +-
>  fsck-cache.c     |    6 -
>  local-pull.c     |    2
>  ls-files.c       |   47 ++++++-----
>  merge-cache.c    |   29 +++----
>  read-cache.c     |  217 ++++++++++++++++++++++++++++++++++---------------------
>  read-tree.c      |   65 +++++++++-------
>  sha1_file.c      |    4 -
>  tree.c           |   15 ++-
>  update-cache.c   |   45 +++++------
>  write-tree.c     |   29 ++++---
>  19 files changed, 416 insertions(+), 327 deletions(-)
>
> Signed-off-by: Brad Roberts <braddr@puremagic.com>
>
>


[-- Attachment #2: diff-vs-git-pb --]
[-- Type: TEXT/PLAIN, Size: 63306 bytes --]

Index: cache.h
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/cache.h  (mode:100644)
+++ uncommitted/cache.h  (mode:100644)
@@ -40,19 +40,8 @@
 
 /*
  * Basic data structures for the directory cache
- *
- * NOTE NOTE NOTE! This is all in the native CPU byte format. It's
- * not even trying to be portable. It's trying to be efficient. It's
- * just a cache, after all.
  */
 
-#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
-struct cache_header {
-	unsigned int hdr_signature;
-	unsigned int hdr_version;
-	unsigned int hdr_entries;
-};
-
 /*
  * The "cache_time" is just the low 32 bits of the
  * time. It doesn't matter if it overflows - we only
@@ -89,6 +78,9 @@
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
 
+extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
+extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
+
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
 #define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
@@ -104,9 +96,6 @@
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
-extern struct cache_entry **active_cache;
-extern unsigned int active_nr, active_alloc, active_cache_changed;
-
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
@@ -120,17 +109,19 @@
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
-extern int read_cache(void);
-extern int write_cache(int newfd, struct cache_entry **cache, int entries);
-extern int cache_name_pos(const char *name, int namelen);
+extern struct cache *new_cache(void);
+extern struct cache *read_cache(void);
+extern int write_cache(struct cache *cache, int newfd);
+extern void free_cache(struct cache *cache);
+extern int cache_name_pos(struct cache *cache, const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
-extern int add_cache_entry(struct cache_entry *ce, int option);
-extern int remove_entry_at(int pos);
-extern int remove_file_from_cache(char *path);
-extern int same_name(struct cache_entry *a, struct cache_entry *b);
-extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern int add_cache_entry(struct cache *cache, struct cache_entry *ce, int option);
+extern int remove_file_from_cache(struct cache *cache, char *path);
+extern int get_num_cache_entries(struct cache *cache);
+extern struct cache_entry *get_cache_entry(struct cache *cache, int pos);
+extern void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos);
+extern int remove_cache_entry_at(struct cache *cache, int pos);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
@@ -148,11 +139,12 @@
 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 long len, const char *type, unsigned char *return_sha1);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
 
 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 read_tree(struct cache *cache, void *buffer, unsigned long size, int stage);
 
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
 
@@ -179,7 +171,7 @@
 void parse_date(char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
 
-static inline void *xmalloc(int size)
+static inline void *xmalloc(size_t size)
 {
 	void *ret = malloc(size);
 	if (!ret)
@@ -187,7 +179,7 @@
 	return ret;
 }
 
-static inline void *xrealloc(void *ptr, int size)
+static inline void *xrealloc(void *ptr, size_t size)
 {
 	void *ret = realloc(ptr, size);
 	if (!ret)
@@ -195,4 +187,12 @@
 	return ret;
 }
 
+static inline void *xcalloc(size_t nmemb, size_t size)
+{
+	void *ret = calloc(nmemb, size);
+	if (!ret)
+		die("Out of memory, calloc failed");
+	return ret;
+}
+
 #endif /* CACHE_H */
Index: check-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/check-files.c  (mode:100644)
+++ uncommitted/check-files.c  (mode:100644)
@@ -8,7 +8,7 @@
  */
 #include "cache.h"
 
-static void check_file(const char *path)
+static void check_file(struct cache *cache, const char *path)
 {
 	int fd = open(path, O_RDONLY);
 	struct cache_entry *ce;
@@ -23,15 +23,15 @@
 	}
 
 	/* Exists but is not in the cache is not fine */
-	pos = cache_name_pos(path, strlen(path));
+	pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		die("preparing to update existing file '%s' not in cache", path);
-	ce = active_cache[pos];
+	ce = get_cache_entry(cache, pos);
 
 	if (lstat(path, &st) < 0)
 		die("lstat(%s): %s", path, strerror(errno));
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (changed)
 		die("preparing to update file '%s' not uptodate in cache", path);
 }
@@ -39,9 +39,9 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache = read_cache();
 
-	read_cache();
 	for (i = 1; i < argc ; i++)
-		check_file(argv[i]);
+		check_file(cache, argv[i]);
 	return 0;
 }
Index: checkout-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/checkout-cache.c  (mode:100644)
+++ uncommitted/checkout-cache.c  (mode:100644)
@@ -167,7 +167,7 @@
 	strcpy(path + len, ce->name);
 
 	if (!lstat(path, &st)) {
-		unsigned changed = cache_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st);
 		if (!changed)
 			return 0;
 		if (!force) {
@@ -188,30 +188,30 @@
 	return write_entry(ce, path);
 }
 
-static int checkout_file(const char *name, const char *base_dir)
+static int checkout_file(struct cache *cache, const char *name, const char *base_dir)
 {
-	int pos = cache_name_pos(name, strlen(name));
+	int pos = cache_name_pos(cache, name, strlen(name));
 	if (pos < 0) {
 		if (!quiet) {
 			pos = -pos - 1;
 			fprintf(stderr,
 				"checkout-cache: %s is %s.\n",
 				name,
-				(pos < active_nr &&
-				 !strcmp(active_cache[pos]->name, name)) ?
+				(pos < get_num_cache_entries(cache) &&
+				 !strcmp(get_cache_entry(cache, pos)->name, name)) ?
 				"unmerged" : "not in the cache");
 		}
 		return -1;
 	}
-	return checkout_entry(active_cache[pos], base_dir);
+	return checkout_entry(get_cache_entry(cache, pos), base_dir);
 }
 
-static int checkout_all(const char *base_dir)
+static int checkout_all(struct cache *cache, const char *base_dir)
 {
 	int i;
 
-	for (i = 0; i < active_nr ; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache) ; i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_stage(ce))
 			continue;
 		if (checkout_entry(ce, base_dir) < 0)
@@ -225,15 +225,15 @@
 	int i, force_filename = 0;
 	const char *base_dir = "";
 
-	if (read_cache() < 0) {
+	struct cache *cache = read_cache();
+	if (!cache) 
 		die("invalid cache");
-	}
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!force_filename) {
 			if (!strcmp(arg, "-a")) {
-				checkout_all(base_dir);
+				checkout_all(cache, base_dir);
 				continue;
 			}
 			if (!strcmp(arg, "--")) {
@@ -257,7 +257,7 @@
 				continue;
 			}
 		}
-		checkout_file(arg, base_dir);
+		checkout_file(cache, arg, base_dir);
 	}
 	return 0;
 }
Index: diff-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-cache.c  (mode:100644)
+++ uncommitted/diff-cache.c  (mode:100644)
@@ -7,10 +7,10 @@
 static int line_termination = '\n';
 
 /* A file entry went away or appeared */
-static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
+static void show_file(struct cache *cache, const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
 {
 	if (generate_patch)
-		diff_addremove(prefix[0], ntohl(mode), sha1, ce->name, NULL);
+		diff_addremove(cache, prefix[0], ntohl(mode), sha1, ce->name, NULL);
 	else
 		printf("%s%06o\tblob\t%s\t%s%c", prefix, ntohl(mode),
 		       sha1_to_hex(sha1), ce->name, line_termination);
@@ -33,7 +33,7 @@
 			}
 			return -1;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (changed) {
 			mode = create_ce_mode(st.st_mode);
 			sha1 = no_sha1;
@@ -45,7 +45,7 @@
 	return 0;
 }
 
-static void show_new_file(struct cache_entry *new)
+static void show_new_file(struct cache *cache, struct cache_entry *new)
 {
 	unsigned char *sha1;
 	unsigned int mode;
@@ -54,10 +54,11 @@
 	if (get_stat_data(new, &sha1, &mode) < 0)
 		return;
 
-	show_file("+", new, sha1, mode);
+	show_file(cache, "+", new, sha1, mode);
 }
 
-static int show_modified(struct cache_entry *old,
+static int show_modified(struct cache *cache,
+			 struct cache_entry *old,
 			 struct cache_entry *new,
 			 int report_missing)
 {
@@ -67,7 +68,7 @@
 
 	if (get_stat_data(new, &sha1, &mode) < 0) {
 		if (report_missing)
-			show_file("-", old, old->sha1, old->ce_mode);
+			show_file(cache, "-", old, old->sha1, old->ce_mode);
 		return -1;
 	}
 
@@ -79,7 +80,7 @@
 	oldmode = ntohl(oldmode);
 
 	if (generate_patch)
-		diff_change(oldmode, mode,
+		diff_change(cache, oldmode, mode,
 			    old->sha1, sha1, old->name, NULL);
 	else {
 		strcpy(old_sha1_hex, sha1_to_hex(old->sha1));
@@ -90,30 +91,34 @@
 	return 0;
 }
 
-static int diff_cache(struct cache_entry **ac, int entries)
+static int diff_cache(struct cache *cache)
 {
-	while (entries) {
-		struct cache_entry *ce = *ac;
-		int same = (entries > 1) && same_name(ce, ac[1]);
+	int pos = 0, num = get_num_cache_entries(cache);
+
+	while (pos < num) {
+		struct cache_entry *ce = get_cache_entry(cache, pos);
+		struct cache_entry *ce_next = ((pos+1) < num) ?
+			get_cache_entry(cache, pos+1) : NULL;
+		int same = ce_next && ce_same_name(ce, ce_next);
 
 		switch (ce_stage(ce)) {
 		case 0:
 			/* No stage 1 entry? That means it's a new file */
 			if (!same) {
-				show_new_file(ce);
+				show_new_file(cache, ce);
 				break;
 			}
 			/* Show difference between old and new */
-			show_modified(ac[1], ce, 1);
+			show_modified(cache, ce_next, ce, 1);
 			break;
 		case 1:
 			/* No stage 3 (merge) entry? That means it's been deleted */
 			if (!same) {
-				show_file("-", ce, ce->sha1, ce->ce_mode);
+				show_file(cache, "-", ce, ce->sha1, ce->ce_mode);
 				break;
 			}
 			/* We come here with ce pointing at stage 1
-			 * (original tree) and ac[1] pointing at stage
+			 * (original tree) and ce_next pointing at stage
 			 * 3 (unmerged).  show-modified with
 			 * report-mising set to false does not say the
 			 * file is deleted but reports true if work
@@ -122,12 +127,12 @@
 			 * Otherwise, we show the differences between
 			 * the original tree and the work tree.
 			 */
-			if (!cached_only && !show_modified(ce, ac[1], 0))
+			if (!cached_only && !show_modified(cache, ce, ce_next, 0))
 				break;
 			/* fallthru */
 		case 3:
 			if (generate_patch)
-				diff_unmerge(ce->name);
+				diff_unmerge(cache, ce->name);
 			else
 				printf("U %s%c", ce->name, line_termination);
 			break;
@@ -141,9 +146,8 @@
 		 * we've handled the relevant cases now.
 		 */
 		do {
-			ac++;
-			entries--;
-		} while (entries && same_name(ce, ac[0]));
+			pos++;
+		} while (pos < num && ce_same_name(ce, get_cache_entry(cache, pos)));
 	}
 	return 0;
 }
@@ -153,11 +157,11 @@
  * when we read in the new tree (into "stage 1"), we won't lose sight
  * of the fact that we had unmerged entries.
  */
-static void mark_merge_entries(void)
+static void mark_merge_entries(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
 		ce->ce_flags |= htons(CE_STAGEMASK);
@@ -172,8 +176,8 @@
 	unsigned char tree_sha1[20];
 	void *tree;
 	unsigned long size;
+	struct cache * cache = read_cache();
 
-	read_cache();
 	while (argc > 2) {
 		char *arg = argv[1];
 		argv++;
@@ -204,13 +208,13 @@
 	if (argc != 2 || get_sha1(argv[1], tree_sha1))
 		usage(diff_cache_usage);
 
-	mark_merge_entries();
+	mark_merge_entries(cache);
 
 	tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
 	if (!tree)
 		die("bad tree object %s", argv[1]);
-	if (read_tree(tree, size, 1))
+	if (read_tree(cache, tree, size, 1))
 		die("unable to read tree object %s", argv[1]);
 
-	return diff_cache(active_cache, active_nr);
+	return diff_cache(cache);
 }
Index: diff-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-files.c  (mode:100644)
+++ uncommitted/diff-files.c  (mode:100644)
@@ -28,18 +28,18 @@
 	return 0;
 }
 
-static void show_unmerge(const char *path)
+static void show_unmerge(struct cache *cache, const char *path)
 {
 	if (generate_patch)
-		diff_unmerge(path);
+		diff_unmerge(cache, path);
 	else
 		printf("U %s%c", path, line_termination);
 }
 
-static void show_file(int pfx, struct cache_entry *ce)
+static void show_file(struct cache *cache, int pfx, struct cache_entry *ce)
 {
 	if (generate_patch)
-		diff_addremove(pfx, ntohl(ce->ce_mode), ce->sha1,
+		diff_addremove(cache, pfx, ntohl(ce->ce_mode), ce->sha1,
 			       ce->name, NULL);
 	else
 		printf("%c%06o\t%s\t%s\t%s%c",
@@ -47,7 +47,7 @@
 		       sha1_to_hex(ce->sha1), ce->name, line_termination);
 }
 
-static void show_modified(int oldmode, int mode,
+static void show_modified(struct cache *cache, int oldmode, int mode,
 			  const char *old_sha1, const char *sha1,
 			  char *path)
 {
@@ -55,7 +55,7 @@
 	strcpy(old_sha1_hex, sha1_to_hex(old_sha1));
 
 	if (generate_patch)
-		diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
+		diff_change(cache, oldmode, mode, old_sha1, sha1, path, NULL);
 	else
 		printf("*%06o->%06o\tblob\t%s->%s\t%s%c",
 		       oldmode, mode, old_sha1_hex, sha1_to_hex(sha1), path,
@@ -65,7 +65,8 @@
 int main(int argc, char **argv)
 {
 	static const char null_sha1[20] = { 0, };
-	int entries = read_cache();
+	struct cache *cache = read_cache();
+	int entries;
 	int i;
 
 	while (1 < argc && argv[1][0] == '-') {
@@ -87,15 +88,17 @@
 	/* At this point, if argc == 1, then we are doing everything.
 	 * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
 	 */
-	if (entries < 0) {
+	if (!cache) {
 		perror("read_cache");
 		exit(1);
 	}
 
+	entries = get_num_cache_entries(cache);
+
 	for (i = 0; i < entries; i++) {
 		struct stat st;
 		unsigned int oldmode, mode;
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		int changed;
 
 		if (1 < argc &&
@@ -103,9 +106,9 @@
 			continue;
 
 		if (ce_stage(ce)) {
-			show_unmerge(ce->name);
+			show_unmerge(cache, ce->name);
 			while (i < entries &&
-			       !strcmp(ce->name, active_cache[i]->name))
+			       !strcmp(ce->name, get_cache_entry(cache, i)->name))
 				i++;
 			i--; /* compensate for loop control increments */
 			continue;
@@ -118,10 +121,10 @@
 			}	
 			if (silent)
 				continue;
-			show_file('-', ce);
+			show_file(cache, '-', ce);
 			continue;
 		}
-		changed = cache_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st);
 		if (!changed)
 			continue;
 
@@ -129,7 +132,7 @@
 		mode = (S_ISLNK(st.st_mode) ? S_IFLNK :
 			S_IFREG | ce_permissions(st.st_mode));
 
-		show_modified(oldmode, mode, ce->sha1, null_sha1,
+		show_modified(cache, oldmode, mode, ce->sha1, null_sha1,
 			      ce->name);
 	}
 	return 0;
Index: diff-helper.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-helper.c  (mode:100644)
+++ uncommitted/diff-helper.c  (mode:100644)
@@ -56,7 +56,7 @@
 	switch (*cp++) {
 	case 'U':
 		if (!cnt || matches_pathspec(cp + 1, spec, cnt))
-			diff_unmerge(cp + 1);
+			diff_unmerge(NULL, cp + 1);
 		return 0;
 	case '+':
 		old.file_valid = 0;
@@ -102,9 +102,9 @@
 	}
 	if (!cnt || matches_pathspec(path, spec, cnt)) {
 		if (reverse)
-			run_external_diff(path, &new, &old);
+			run_external_diff(NULL, path, &new, &old);
 		else
-			run_external_diff(path, &old, &new);
+			run_external_diff(NULL, path, &old, &new);
 	}
 	return 0;
 }
Index: diff-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff-tree.c  (mode:100644)
+++ uncommitted/diff-tree.c  (mode:100644)
@@ -17,7 +17,7 @@
 static char **paths = NULL;
 static int *pathlens = NULL;
 
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base);
+static int diff_tree_sha1(struct cache *cache, const unsigned char *old, const unsigned char *new, const char *base);
 
 static void update_tree_entry(void **bufp, unsigned long *sizep)
 {
@@ -53,19 +53,19 @@
 	return newbase;
 }
 
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base);
+static void show_file(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base);
 
 /* A whole sub-tree went away or appeared */
-static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base)
+static void show_tree(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base)
 {
 	while (size) {
-		show_file(prefix, tree, size, base);
+		show_file(cache, prefix, tree, size, base);
 		update_tree_entry(&tree, &size);
 	}
 }
 
 /* A file entry went away or appeared */
-static void show_file(const char *prefix, void *tree, unsigned long size, const char *base)
+static void show_file(struct cache *cache, const char *prefix, void *tree, unsigned long size, const char *base)
 {
 	unsigned mode;
 	const char *path;
@@ -89,7 +89,7 @@
 		if (!tree || strcmp(type, "tree"))
 			die("corrupt tree sha %s", sha1_to_hex(sha1));
 
-		show_tree(prefix, tree, size, newbase);
+		show_tree(cache, prefix, tree, size, newbase);
 		
 		free(tree);
 		free(newbase);
@@ -98,7 +98,7 @@
 
 	if (generate_patch) {
 		if (!S_ISDIR(mode))
-			diff_addremove(prefix[0], mode, sha1, base, path);
+			diff_addremove(cache, prefix[0], mode, sha1, base, path);
 	}
 	else
 		printf("%s%06o\t%s\t%s\t%s%s%c", prefix, mode,
@@ -107,7 +107,7 @@
 		       line_termination);
 }
 
-static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
+static int compare_tree_entry(struct cache *cache, void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
 {
 	unsigned mode1, mode2;
 	const char *path1, *path2;
@@ -122,11 +122,11 @@
 	pathlen2 = strlen(path2);
 	cmp = cache_name_compare(path1, pathlen1, path2, pathlen2);
 	if (cmp < 0) {
-		show_file("-", tree1, size1, base);
+		show_file(cache, "-", tree1, size1, base);
 		return -1;
 	}
 	if (cmp > 0) {
-		show_file("+", tree2, size2, base);
+		show_file(cache, "+", tree2, size2, base);
 		return 1;
 	}
 	if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
@@ -137,15 +137,15 @@
 	 * file, we need to consider it a remove and an add.
 	 */
 	if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-		show_file("-", tree1, size1, base);
-		show_file("+", tree2, size2, base);
+		show_file(cache, "-", tree1, size1, base);
+		show_file(cache, "+", tree2, size2, base);
 		return 0;
 	}
 
 	if (recursive && S_ISDIR(mode1)) {
 		int retval;
 		char *newbase = malloc_base(base, path1, pathlen1);
-		retval = diff_tree_sha1(sha1, sha2, newbase);
+		retval = diff_tree_sha1(cache, sha1, sha2, newbase);
 		free(newbase);
 		return retval;
 	}
@@ -159,7 +159,7 @@
 
 	if (generate_patch) {
 		if (!S_ISDIR(mode1))
-			diff_change(mode1, mode2, sha1, sha2, base, path1);
+			diff_change(cache, mode1, mode2, sha1, sha2, base, path1);
 	}
 	else {
 		strcpy(old_sha1_hex, sha1_to_hex(sha1));
@@ -217,7 +217,7 @@
 	return 0; /* No matches */
 }
 
-static int diff_tree(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
+static int diff_tree(struct cache *cache, void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)
 {
 	while (size1 | size2) {
 		if (nr_paths && size1 && !interesting(tree1, size1, base)) {
@@ -229,16 +229,16 @@
 			continue;
 		}
 		if (!size1) {
-			show_file("+", tree2, size2, base);
+			show_file(cache, "+", tree2, size2, base);
 			update_tree_entry(&tree2, &size2);
 			continue;
 		}
 		if (!size2) {
-			show_file("-", tree1, size1, base);
+			show_file(cache, "-", tree1, size1, base);
 			update_tree_entry(&tree1, &size1);
 			continue;
 		}
-		switch (compare_tree_entry(tree1, size1, tree2, size2, base)) {
+		switch (compare_tree_entry(cache, tree1, size1, tree2, size2, base)) {
 		case -1:
 			update_tree_entry(&tree1, &size1);
 			continue;
@@ -254,7 +254,7 @@
 	return 0;
 }
 
-static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base)
+static int diff_tree_sha1(struct cache *cache, const unsigned char *old, const unsigned char *new, const char *base)
 {
 	void *tree1, *tree2;
 	unsigned long size1, size2;
@@ -266,7 +266,7 @@
 	tree2 = read_object_with_reference(new, "tree", &size2, 0);
 	if (!tree2)
 		die("unable to read destination tree (%s)", sha1_to_hex(new));
-	retval = diff_tree(tree1, size1, tree2, size2, base);
+	retval = diff_tree(cache, tree1, size1, tree2, size2, base);
 	free(tree1);
 	free(tree2);
 	return retval;
@@ -342,7 +342,7 @@
 	return this_header;
 }
 
-static int diff_tree_stdin(char *line)
+static int diff_tree_stdin(struct cache *cache, char *line)
 {
 	int len = strlen(line);
 	unsigned char commit[20], parent[20];
@@ -360,7 +360,7 @@
 		line[81] = 0;
 		sprintf(this_header, "%s (from %s)\n", line, line+41);
 		header = this_header;
-		return diff_tree_sha1(parent, commit, "");
+		return diff_tree_sha1(cache, parent, commit, "");
 	}
 	buf = read_object_with_reference(commit, "commit", &size, NULL);
 	if (!buf)
@@ -378,7 +378,7 @@
 		if (get_sha1_hex(buf + offset + 7, parent))
 			return -1;
 		header = generate_header(line, sha1_to_hex(parent), buf, size);
-		diff_tree_sha1(parent, commit, "");
+		diff_tree_sha1(cache, parent, commit, "");
 		if (!header && verbose_header)
 			header_prefix = "\ndiff-tree ";
 		offset += 48;
@@ -458,10 +458,10 @@
 	}
 
 	if (!read_stdin)
-		return diff_tree_sha1(old, new, "");
+		return diff_tree_sha1(NULL, old, new, "");
 
 	while (fgets(line, sizeof(line), stdin))
-		diff_tree_stdin(line);
+		diff_tree_stdin(NULL, line);
 
 	return 0;
 }
Index: diff.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff.c  (mode:100644)
+++ uncommitted/diff.c  (mode:100644)
@@ -147,7 +147,7 @@
  * the work tree has that object contents, return true, so that
  * prepare_temp_file() does not have to inflate and extract.
  */
-static int work_tree_matches(const char *name, const unsigned char *sha1)
+static int work_tree_matches(struct cache *cache, const char *name, const unsigned char *sha1)
 {
 	struct cache_entry *ce;
 	struct stat st;
@@ -165,17 +165,17 @@
 	 * by diff-cache --cached, which does read the cache before
 	 * calling us.
 	 */ 
-	if (!active_cache)
+	if (!get_num_cache_entries(cache))
 		return 0;
 
 	len = strlen(name);
-	pos = cache_name_pos(name, len);
+	pos = cache_name_pos(cache, name, len);
 	if (pos < 0)
 		return 0;
-	ce = active_cache[pos];
+	ce = get_cache_entry(cache, pos);
 	if ((lstat(name, &st) < 0) ||
 	    !S_ISREG(st.st_mode) ||
-	    cache_match_stat(ce, &st) ||
+	    ce_match_stat(ce, &st) ||
 	    memcmp(sha1, ce->sha1, 20))
 		return 0;
 	return 1;
@@ -202,7 +202,8 @@
 	sprintf(temp->mode, "%06o", mode);
 }
 
-static void prepare_temp_file(const char *name,
+static void prepare_temp_file(struct cache *cache,
+			      const char *name,
 			      struct diff_tempfile *temp,
 			      struct diff_spec *one)
 {
@@ -222,7 +223,7 @@
 
 	if (one->sha1_valid &&
 	    (!memcmp(one->blob_sha1, null_sha1, sizeof(null_sha1)) ||
-	     work_tree_matches(name, one->blob_sha1)))
+	     work_tree_matches(cache, name, one->blob_sha1)))
 		use_work_tree = 1;
 
 	if (!one->sha1_valid || use_work_tree) {
@@ -293,7 +294,8 @@
  *               infile2 infile2-sha1 infile2-mode.
  *
  */
-void run_external_diff(const char *name,
+void run_external_diff(struct cache *cache,
+		       const char *name,
 		       struct diff_spec *one,
 		       struct diff_spec *two)
 {
@@ -303,8 +305,8 @@
 	static int atexit_asked = 0;
 
 	if (one && two) {
-		prepare_temp_file(name, &temp[0], one);
-		prepare_temp_file(name, &temp[1], two);
+		prepare_temp_file(cache, name, &temp[0], one);
+		prepare_temp_file(cache, name, &temp[1], two);
 		if (! atexit_asked &&
 		    (temp[0].name == temp[0].tmp_path ||
 		     temp[1].name == temp[1].tmp_path)) {
@@ -357,7 +359,8 @@
 	remove_tempfile();
 }
 
-void diff_addremove(int addremove, unsigned mode,
+void diff_addremove(struct cache *cache,
+		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
 		    const char *base, const char *path)
 {
@@ -379,10 +382,11 @@
 		strcpy(concatpath, base);
 		strcat(concatpath, path);
 	}
-	run_external_diff(path ? concatpath : base, one, two);
+	run_external_diff(cache, path ? concatpath : base, one, two);
 }
 
-void diff_change(unsigned old_mode, unsigned new_mode,
+void diff_change(struct cache *cache,
+		 unsigned old_mode, unsigned new_mode,
 		 const unsigned char *old_sha1,
 		 const unsigned char *new_sha1,
 		 const char *base, const char *path) {
@@ -400,10 +404,10 @@
 		strcpy(concatpath, base);
 		strcat(concatpath, path);
 	}
-	run_external_diff(path ? concatpath : base, &spec[0], &spec[1]);
+	run_external_diff(cache, path ? concatpath : base, &spec[0], &spec[1]);
 }
 
-void diff_unmerge(const char *path)
+void diff_unmerge(struct cache *cache, const char *path)
 {
-	run_external_diff(path, NULL, NULL);
+	run_external_diff(cache, path, NULL, NULL);
 }
Index: diff.h
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/diff.h  (mode:100644)
+++ uncommitted/diff.h  (mode:100644)
@@ -4,18 +4,20 @@
 #ifndef DIFF_H
 #define DIFF_H
 
-extern void diff_addremove(int addremove,
+extern void diff_addremove(struct cache *cache,
+			   int addremove,
 			   unsigned mode,
 			   const unsigned char *sha1,
 			   const char *base,
 			   const char *path);
 
-extern void diff_change(unsigned mode1, unsigned mode2,
+extern void diff_change(struct cache *cache,
+			     unsigned mode1, unsigned mode2,
 			     const unsigned char *sha1,
 			     const unsigned char *sha2,
 			     const char *base, const char *path);
 
-extern void diff_unmerge(const char *path);
+extern void diff_unmerge(struct cache *cache, const char *path);
 
 /* These are for diff-helper */
 
@@ -31,7 +33,8 @@
 	unsigned file_valid : 1; /* if false the file does not even exist */
 };
 
-extern void run_external_diff(const char *name,
+extern void run_external_diff(struct cache *cache,
+			      const char *name,
 			      struct diff_spec *, struct diff_spec *);
 
 #endif /* DIFF_H */
Index: fsck-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/fsck-cache.c  (mode:100644)
+++ uncommitted/fsck-cache.c  (mode:100644)
@@ -356,9 +356,9 @@
 
 	if (keep_cache_objects) {
 		int i;
-		read_cache();
-		for (i = 0; i < active_nr; i++) {
-			struct blob *blob = lookup_blob(active_cache[i]->sha1);
+		struct cache *cache = read_cache();
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct blob *blob = lookup_blob(get_cache_entry(cache, i)->sha1);
 			struct object *obj;
 			if (!blob)
 				continue;
Index: local-pull.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/local-pull.c  (mode:100644)
+++ uncommitted/local-pull.c  (mode:100644)
@@ -61,7 +61,7 @@
 		}
 		map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, ifd, 0);
 		close(ifd);
-		if (-1 == (int)(long)map) {
+		if (MAP_FAILED == map) {
 			fprintf(stderr, "cannot mmap %s\n", filename);
 			return -1;
 		}
Index: ls-files.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/ls-files.c  (mode:100644)
+++ uncommitted/ls-files.c  (mode:100644)
@@ -98,11 +98,11 @@
 static int nr_dir;
 static int dir_alloc;
 
-static void add_name(const char *pathname, int len)
+static void add_name(struct cache *cache, const char *pathname, int len)
 {
 	struct nond_on_fs *ent;
 
-	if (cache_name_pos(pathname, len) >= 0)
+	if (cache_name_pos(cache, pathname, len) >= 0)
 		return;
 
 	if (nr_dir == dir_alloc) {
@@ -124,7 +124,7 @@
  * Also, we currently ignore all names starting with a dot.
  * That likely will not change.
  */
-static void read_directory(const char *path, const char *base, int baselen)
+static void read_directory(struct cache *cache, const char *path, const char *base, int baselen)
 {
 	DIR *dir = opendir(path);
 
@@ -157,14 +157,14 @@
 				/* fallthrough */
 			case DT_DIR:
 				memcpy(fullname + baselen + len, "/", 2);
-				read_directory(fullname, fullname,
+				read_directory(cache, fullname, fullname,
 					       baselen + len + 1);
 				continue;
 			case DT_REG:
 			case DT_LNK:
 				break;
 			}
-			add_name(fullname, baselen + len);
+			add_name(cache, fullname, baselen + len);
 		}
 		closedir(dir);
 	}
@@ -179,7 +179,7 @@
 				  e2->name, e2->len);
 }
 
-static void show_killed_files()
+static void show_killed_files(struct cache *cache)
 {
 	int i;
 	for (i = 0; i < nr_dir; i++) {
@@ -193,28 +193,28 @@
 				/* If ent->name is prefix of an entry in the
 				 * cache, it will be killed.
 				 */
-				pos = cache_name_pos(ent->name, ent->len);
+				pos = cache_name_pos(cache, ent->name, ent->len);
 				if (0 <= pos)
 					die("bug in show-killed-files");
 				pos = -pos - 1;
-				while (pos < active_nr &&
-				       ce_stage(active_cache[pos]))
+				while (pos < get_num_cache_entries(cache) &&
+				       ce_stage(get_cache_entry(cache, pos)))
 					pos++; /* skip unmerged */
-				if (active_nr <= pos)
+				if (get_num_cache_entries(cache) <= pos)
 					break;
 				/* pos points at a name immediately after
 				 * ent->name in the cache.  Does it expect
 				 * ent->name to be a directory?
 				 */
-				len = ce_namelen(active_cache[pos]);
+				len = ce_namelen(get_cache_entry(cache, pos));
 				if ((ent->len < len) &&
-				    !strncmp(active_cache[pos]->name,
+				    !strncmp(get_cache_entry(cache, pos)->name,
 					     ent->name, ent->len) &&
-				    active_cache[pos]->name[ent->len] == '/')
+				    get_cache_entry(cache, pos)->name[ent->len] == '/')
 					killed = 1;
 				break;
 			}
-			if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
+			if (0 <= cache_name_pos(cache, ent->name, sp - ent->name)) {
 				/* If any of the leading directories in
 				 * ent->name is registered in the cache,
 				 * ent->name will be killed.
@@ -230,13 +230,13 @@
 	}
 }
 
-static void show_files(void)
+static void show_files(struct cache *cache)
 {
 	int i;
 
 	/* For cached/deleted files we don't need to even do the readdir */
 	if (show_others || show_killed) {
-		read_directory(".", "", 0);
+		read_directory(cache, ".", "", 0);
 		qsort(dir, nr_dir, sizeof(struct nond_on_fs *), cmp_name);
 		if (show_others)
 			for (i = 0; i < nr_dir; i++)
@@ -244,11 +244,11 @@
 				       dir[i]->len, dir[i]->name,
 				       line_terminator);
 		if (show_killed)
-			show_killed_files();
+			show_killed_files(cache);
 	}
 	if (show_cached | show_stage) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			if (excluded(ce->name) != show_ignored)
 				continue;
 			if (show_unmerged && !ce_stage(ce))
@@ -269,8 +269,8 @@
 		}
 	}
 	if (show_deleted) {
-		for (i = 0; i < active_nr; i++) {
-			struct cache_entry *ce = active_cache[i];
+		for (i = 0; i < get_num_cache_entries(cache); i++) {
+			struct cache_entry *ce = get_cache_entry(cache, i);
 			struct stat st;
 			if (excluded(ce->name) != show_ignored)
 				continue;
@@ -289,6 +289,7 @@
 int main(int argc, char **argv)
 {
 	int i;
+	struct cache *cache;
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
@@ -341,7 +342,7 @@
 	if (!(show_stage | show_deleted | show_others | show_unmerged | show_killed))
 		show_cached = 1;
 
-	read_cache();
-	show_files();
+	cache = read_cache();
+	show_files(cache);
 	return 0;
 }
Index: merge-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/merge-cache.c  (mode:100644)
+++ uncommitted/merge-cache.c  (mode:100644)
@@ -34,11 +34,11 @@
 	}
 }
 
-static int merge_entry(int pos, const char *path)
+static int merge_entry(struct cache *cache, int pos, const char *path)
 {
 	int found;
 	
-	if (pos >= active_nr)
+	if (pos >= get_num_cache_entries(cache))
 		die("merge-cache: %s not in the cache", path);
 	arguments[0] = pgm;
 	arguments[1] = "";
@@ -52,7 +52,7 @@
 	do {
 		static char hexbuf[4][60];
 		static char ownbuf[4][60];
-		struct cache_entry *ce = active_cache[pos];
+		struct cache_entry *ce = get_cache_entry(cache, pos);
 		int stage = ce_stage(ce);
 
 		if (strcmp(ce->name, path))
@@ -62,44 +62,45 @@
 		sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
 		arguments[stage] = hexbuf[stage];
 		arguments[stage + 4] = ownbuf[stage];
-	} while (++pos < active_nr);
+	} while (++pos < get_num_cache_entries(cache));
 	if (!found)
 		die("merge-cache: %s not in the cache", path);
 	run_program();
 	return found;
 }
 
-static void merge_file(const char *path)
+static void merge_file(struct cache *cache, const char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 
 	/*
 	 * If it already exists in the cache as stage0, it's
 	 * already merged and there is nothing to do.
 	 */
 	if (pos < 0)
-		merge_entry(-pos-1, path);
+		merge_entry(cache, -pos-1, path);
 }
 
-static void merge_all(void)
+static void merge_all(struct cache *cache)
 {
 	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (!ce_stage(ce))
 			continue;
-		i += merge_entry(i, ce->name)-1;
+		i += merge_entry(cache, i, ce->name)-1;
 	}
 }
 
 int main(int argc, char **argv)
 {
 	int i, force_file = 0;
+	struct cache *cache;
 
 	if (argc < 3)
 		usage("merge-cache [-o] <merge-program> (-a | <filename>*)");
 
-	read_cache();
+	cache = read_cache();
 
 	i = 1;
 	if (!strcmp(argv[1], "-o")) {
@@ -115,12 +116,12 @@
 				continue;
 			}
 			if (!strcmp(arg, "-a")) {
-				merge_all();
+				merge_all(cache);
 				continue;
 			}
 			die("merge-cache: unknown option %s", arg);
 		}
-		merge_file(arg);
+		merge_file(cache, arg);
 	}
 	if (err)
 		die("merge program failed");
Index: read-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/read-cache.c  (mode:100644)
+++ uncommitted/read-cache.c  (mode:100644)
@@ -6,10 +6,49 @@
 #include <stdarg.h>
 #include "cache.h"
 
-struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
+/*
+ * Basic data structures for the directory cache
+ */
+
+#define CACHE_SIGNATURE 0x44495243	/* "DIRC" */
+struct cache_header {
+	unsigned int hdr_signature;
+	unsigned int hdr_version;
+	unsigned int hdr_entries;
+};
+
+struct mmap_holder {
+	void * ptr;
+	size_t size;
+};
+
+struct cache {
+	struct mmap_holder   map;
+	struct cache_header *header;
+	struct cache_entry **entries;
+	unsigned int num_entries;
+	unsigned int allocated_entries;
+	unsigned int active_cache_changed;
+};
+
+struct cache * new_cache()
+{
+	struct cache *cache = xcalloc(1, sizeof(struct cache));
+
+	cache->map.ptr = MAP_FAILED;
+
+	return cache;
+}
+
+void free_cache(struct cache *cache)
+{
+	if (cache->map.ptr != MAP_FAILED)
+		munmap(cache->map.ptr, cache->map.size);
+
+	free(cache);
+}
 
-int cache_match_stat(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
 
@@ -75,15 +114,15 @@
 	return 0;
 }
 
-int cache_name_pos(const char *name, int namelen)
+int cache_name_pos(struct cache *cache, const char *name, int namelen)
 {
 	int first, last;
 
 	first = 0;
-	last = active_nr;
+	last = cache->num_entries;
 	while (last > first) {
 		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
+		struct cache_entry *ce = get_cache_entry(cache, next);
 		int cmp = cache_name_compare(name, namelen, ce->name, htons(ce->ce_flags));
 		if (!cmp)
 			return next;
@@ -97,27 +136,27 @@
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-int remove_entry_at(int pos)
+int remove_cache_entry_at(struct cache *cache, int pos)
 {
-	active_cache_changed = 1;
-	active_nr--;
-	if (pos >= active_nr)
+	cache->active_cache_changed = 1;
+	cache->num_entries--;
+	if (pos >= cache->num_entries)
 		return 0;
-	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
+	memmove(cache->entries + pos, cache->entries + pos + 1, (cache->num_entries - pos) * sizeof(struct cache_entry *));
 	return 1;
 }
 
-int remove_file_from_cache(char *path)
+int remove_file_from_cache(struct cache *cache, char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
+	int pos = cache_name_pos(cache, path, strlen(path));
 	if (pos < 0)
 		pos = -pos-1;
-	while (pos < active_nr && !strcmp(active_cache[pos]->name, path))
-		remove_entry_at(pos);
+	while (pos < get_num_cache_entries(cache) && !strcmp(get_cache_entry(cache, pos)->name, path))
+		remove_cache_entry_at(cache, pos);
 	return 0;
 }
 
-int same_name(struct cache_entry *a, struct cache_entry *b)
+int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 {
 	int len = ce_namelen(a);
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
@@ -132,7 +171,8 @@
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
  */
-static int check_file_directory_conflict(const struct cache_entry *ce,
+static int check_file_directory_conflict(struct cache *cache,
+					 const struct cache_entry *ce,
 					 int ok_to_replace)
 {
 	int pos, replaced = 0;
@@ -155,7 +195,7 @@
 		if (!ep)
 			break;
 		*ep = 0;    /* first cut it at slash */
-		pos = cache_name_pos(pathbuf,
+		pos = cache_name_pos(cache, pathbuf,
 				     htons(create_ce_flags(ep-cp, stage)));
 		if (0 <= pos) {
 			/* Our leading path component is registered as a file,
@@ -167,7 +207,7 @@
 				return -1;
 			}
 			fprintf(stderr, "removing file '%s' to replace it with a directory to create '%s'.\n", pathbuf, path);
-			remove_entry_at(pos);
+			remove_cache_entry_at(cache, pos);
 			replaced = 1;
 		}
 		*ep = '/';  /* then restore it and go downwards */
@@ -179,7 +219,7 @@
 	 * of it?  That is, are we creating a file where they already expect
 	 * a directory there?
 	 */
-	pos = cache_name_pos(path,
+	pos = cache_name_pos(cache, path,
 			     htons(create_ce_flags(namelen, stage)));
 
 	/* (0 <= pos) cannot happen because add_cache_entry()
@@ -206,8 +246,8 @@
 	 * path of an existing entry anymore.
 	 */
 
-	while (pos < active_nr) {
-		struct cache_entry *other = active_cache[pos];
+	while (pos < get_num_cache_entries(cache)) {
+		struct cache_entry *other = get_cache_entry(cache, pos);
 		if (strncmp(other->name, path, namelen))
 			break; /* it is not our "subdirectory" anymore */
 		if ((ce_stage(other) == stage) &&
@@ -215,7 +255,7 @@
 			if (!ok_to_replace)
 				return -1;
 			fprintf(stderr, "removing file '%s' under '%s' to be replaced with a file\n", other->name, path);
-			remove_entry_at(pos);
+			remove_cache_entry_at(cache, pos);
 			replaced = 1;
 			continue; /* cycle without updating pos */
 		}
@@ -224,17 +264,35 @@
 	return replaced;
 }
 
-int add_cache_entry(struct cache_entry *ce, int option)
+void set_cache_entry(struct cache *cache, struct cache_entry *ce, int pos)
+{
+	cache->active_cache_changed = 1;
+	cache->entries[pos] = ce;
+}
+
+int get_num_cache_entries(struct cache *cache)
+{
+	return cache->num_entries;
+}
+
+struct cache_entry *get_cache_entry(struct cache *cache, int pos)
+{
+ 	/* You can NOT just free cache->entries[pos] here, since it
+  	 * might not be necessarily malloc()ed but can also come
+  	 * from mmap(). */
+	return cache->entries[pos];
+}
+
+int add_cache_entry(struct cache *cache, struct cache_entry *ce, int option)
 {
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
-	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+	pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 
 	/* existing match? Just replace it */
 	if (pos >= 0) {
-		active_cache_changed = 1;
-		active_cache[pos] = ce;
+		set_cache_entry(cache, ce, pos);
 		return 0;
 	}
 	pos = -pos-1;
@@ -243,10 +301,10 @@
 	 * Inserting a merged entry ("stage 0") into the index
 	 * will always replace all non-merged entries..
 	 */
-	if (pos < active_nr && ce_stage(ce) == 0) {
-		while (same_name(active_cache[pos], ce)) {
+	if (pos < get_num_cache_entries(cache) && ce_stage(ce) == 0) {
+		while (ce_same_name(get_cache_entry(cache, pos), ce)) {
 			ok_to_add = 1;
-			if (!remove_entry_at(pos))
+			if (!remove_cache_entry_at(cache, pos))
 				break;
 		}
 	}
@@ -254,25 +312,24 @@
 	if (!ok_to_add)
 		return -1;
 
-	if (check_file_directory_conflict(ce, ok_to_replace)) {
+	if (check_file_directory_conflict(cache, ce, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
-		pos = cache_name_pos(ce->name, htons(ce->ce_flags));
+		pos = cache_name_pos(cache, ce->name, htons(ce->ce_flags));
 		pos = -pos-1;
 	}
 
 	/* Make sure the array is big enough .. */
-	if (active_nr == active_alloc) {
-		active_alloc = alloc_nr(active_alloc);
-		active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+	if (cache->num_entries == cache->allocated_entries) {
+		cache->allocated_entries = alloc_nr(cache->allocated_entries);
+		cache->entries = xrealloc(cache->entries, cache->allocated_entries * sizeof(struct cache_entry *));
 	}
 
 	/* Add it in.. */
-	active_nr++;
-	if (active_nr > pos)
-		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
-	active_cache_changed = 1;
+	cache->num_entries++;
+	if (cache->num_entries > pos)
+		memmove(cache->entries + pos + 1, cache->entries + pos, (cache->num_entries - pos - 1) * sizeof(ce));
+	set_cache_entry(cache, ce, pos);
 	return 0;
 }
 
@@ -293,54 +350,56 @@
 	return 0;
 }
 
-int read_cache(void)
+struct cache *read_cache(void)
 {
 	int fd, i;
 	struct stat st;
-	unsigned long size, offset;
-	void *map;
-	struct cache_header *hdr;
-
-	errno = EBUSY;
-	if (active_cache)
-		return error("more than one cachefile");
+	unsigned long offset;
+	struct cache *cache = new_cache();
+
 	errno = ENOENT;
 	fd = open(get_index_file(), O_RDONLY);
-	if (fd < 0)
-		return (errno == ENOENT) ? 0 : error("open failed");
+	if (fd < 0) {
+		if (errno == ENOENT)
+			return cache;
+		else {
+			free_cache(cache);
+			return NULL;
+		}
+	}
 
-	size = 0; // avoid gcc warning
-	map = (void *)-1;
 	if (!fstat(fd, &st)) {
-		size = st.st_size;
+		cache->map.size = st.st_size;
 		errno = EINVAL;
-		if (size >= sizeof(struct cache_header) + 20)
-			map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+		if (cache->map.size >= sizeof(struct cache_header) + 20)
+			cache->map.ptr = mmap(NULL, cache->map.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 	}
 	close(fd);
-	if (-1 == (int)(long)map)
-		return error("mmap failed");
+	if (MAP_FAILED == cache->map.ptr) {
+		error("mmap failed");
+		free_cache(cache);
+		return NULL;
+	}
 
-	hdr = map;
-	if (verify_hdr(hdr, size) < 0)
-		goto unmap;
-
-	active_nr = ntohl(hdr->hdr_entries);
-	active_alloc = alloc_nr(active_nr);
-	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
-
-	offset = sizeof(*hdr);
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = map + offset;
-		offset = offset + ce_size(ce);
-		active_cache[i] = ce;
+	cache->header = cache->map.ptr;
+	if (verify_hdr(cache->header, cache->map.size) < 0) {
+		free_cache(cache);
+		errno = EINVAL;
+		error("verify header failed");
+		return NULL;
 	}
-	return active_nr;
 
-unmap:
-	munmap(map, size);
-	errno = EINVAL;
-	return error("verify header failed");
+	cache->num_entries = ntohl(cache->header->hdr_entries);
+	cache->allocated_entries = alloc_nr(cache->num_entries);
+	cache->entries = xcalloc(cache->allocated_entries, sizeof(struct cache_entry *));
+
+	offset = sizeof(*cache->header);
+	for (i = 0; i < cache->num_entries; i++) {
+		struct cache_entry *ce = cache->map.ptr + offset;
+		offset = offset + ce_size(ce);
+		cache->entries[i] = ce;
+	}
+	return cache;
 }
 
 #define WRITE_BUFFER_SIZE 8192
@@ -386,7 +445,7 @@
 	return 0;
 }
 
-int write_cache(int newfd, struct cache_entry **cache, int entries)
+int write_cache(struct cache *cache, int newfd)
 {
 	SHA_CTX c;
 	struct cache_header hdr;
@@ -394,14 +453,14 @@
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(entries);
+	hdr.hdr_entries = htonl(get_num_cache_entries(cache));
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
Index: read-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/read-tree.c  (mode:100644)
+++ uncommitted/read-tree.c  (mode:100644)
@@ -7,7 +7,7 @@
 
 static int stage = 0;
 
-static int unpack_tree(unsigned char *sha1)
+static int unpack_tree(struct cache *cache, unsigned char *sha1)
 {
 	void *buffer;
 	unsigned long size;
@@ -16,7 +16,7 @@
 	buffer = read_object_with_reference(sha1, "tree", &size, 0);
 	if (!buffer)
 		return -1;
-	ret = read_tree(buffer, size, stage);
+	ret = read_tree(cache, buffer, size, stage);
 	free(buffer);
 	return ret;
 }
@@ -93,26 +93,30 @@
 	return NULL;
 }
 
-static void trivially_merge_cache(struct cache_entry **src, int nr)
+/* rather than doing the 'right' thing of deleting entries as we merge,
+ * walk dst through the cache, overwriting entries as we go and at the
+ * end truncate the size of the cache */
+static void trivially_merge_cache(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce, *result;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
-		if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) {
+		if ((src < (nr - 2)) &&
+		    (result = merge_entries(ce,
+					    get_cache_entry(cache, src + 1),
+					    get_cache_entry(cache, src + 2))) != NULL) {
 			/*
 			 * See if we can re-use the old CE directly?
 			 * That way we get the uptodate stat info.
@@ -122,40 +126,46 @@
 			ce = result;
 			ce->ce_flags &= ~htons(CE_STAGEMASK);
 			src += 2;
-			nr -= 2;
-			active_nr -= 2;
 		}
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
-static void merge_stat_info(struct cache_entry **src, int nr)
+static void merge_stat_info(struct cache *cache)
 {
 	static struct cache_entry null_entry;
-	struct cache_entry **dst = src;
 	struct cache_entry *old = &null_entry;
+	int src = 0, dst = 0, nr = get_num_cache_entries(cache);
 
-	while (nr) {
+	while (src < nr) {
 		struct cache_entry *ce;
 
-		ce = src[0];
+		ce = get_cache_entry(cache, src);
 
 		/* We throw away original cache entries except for the stat information */
 		if (!ce_stage(ce)) {
 			old = ce;
 			src++;
-			nr--;
-			active_nr--;
 			continue;
 		}
 		if (path_matches(ce, old) && same(ce, old))
 			*ce = *old;
 		ce->ce_flags &= ~htons(CE_STAGEMASK);
-		*dst++ = ce;
+		set_cache_entry(cache, ce, dst);
+		dst++;
 		src++;
+	}
+	/* this could be replaced by a truncate api */
+	while (nr > dst) {
 		nr--;
+		remove_cache_entry_at(cache, nr);
 	}
 }
 
@@ -167,6 +177,7 @@
 	unsigned char sha1[20];
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct cache *cache = NULL;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -185,9 +196,9 @@
 			int i;
 			if (stage)
 				die("-m needs to come first");
-			read_cache();
-			for (i = 0; i < active_nr; i++) {
-				if (ce_stage(active_cache[i]))
+			cache = read_cache();
+			for (i = 0; i < get_num_cache_entries(cache); i++) {
+				if (ce_stage(get_cache_entry(cache, i)))
 					die("you need to resolve your current index first");
 			}
 			stage = 1;
@@ -198,23 +209,25 @@
 			usage(read_tree_usage);
 		if (stage > 3)
 			usage(read_tree_usage);
-		if (unpack_tree(sha1) < 0)
+		if (!cache)
+			cache = new_cache();
+		if (unpack_tree(cache, sha1) < 0)
 			die("failed to unpack tree object %s", arg);
 		stage++;
 	}
 	if (merge) {
 		switch (stage) {
 		case 4:	/* Three-way merge */
-			trivially_merge_cache(active_cache, active_nr);
+			trivially_merge_cache(cache);
 			break;
 		case 2:	/* Just read a tree, merge with old cache contents */
-			merge_stat_info(active_cache, active_nr);
+			merge_stat_info(cache);
 			break;
 		default:
 			die("just how do you expect me to merge %d trees?", stage-1);
 		}
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(cache, newfd) || rename(lockfile, indexfile))
 		die("unable to write new index file");
 	lockfile_name = NULL;
 	return 0;
Index: sha1_file.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/sha1_file.c  (mode:100644)
+++ uncommitted/sha1_file.c  (mode:100644)
@@ -302,7 +302,7 @@
 	}
 	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if (-1 == (int)(long)map)
+	if (MAP_FAILED == map)
 		return NULL;
 	*size = st.st_size;
 	return map;
@@ -587,7 +587,7 @@
 	if (size)
 		buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
-	if ((int)(long)buf == -1)
+	if (buf == MAP_FAILED)
 		return -1;
 
 	ret = write_sha1_file(buf, size, "blob", sha1);
Index: tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/tree.c  (mode:100644)
+++ uncommitted/tree.c  (mode:100644)
@@ -5,7 +5,8 @@
 
 const char *tree_type = "tree";
 
-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry(struct cache *cache, unsigned char *sha1, const char *base,
+		          int baselen, const char *pathname, unsigned mode, int stage)
 {
 	int len = strlen(pathname);
 	unsigned int size = cache_entry_size(baselen + len);
@@ -18,10 +19,10 @@
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(cache, ce, ADD_CACHE_OK_TO_ADD);
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
+static int read_tree_recursive(struct cache* cache, void *buffer, unsigned long size,
 			       const char *base, int baselen, int stage)
 {
 	while (size) {
@@ -53,7 +54,7 @@
 			memcpy(newbase, base, baselen);
 			memcpy(newbase + baselen, path, pathlen);
 			newbase[baselen + pathlen] = '/';
-			retval = read_tree_recursive(eltbuf, eltsize,
+			retval = read_tree_recursive(cache, eltbuf, eltsize,
 						     newbase,
 						     baselen + pathlen + 1, stage);
 			free(eltbuf);
@@ -62,15 +63,15 @@
 				return -1;
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
+		if (read_one_entry(cache, sha1, base, baselen, path, mode, stage) < 0)
 			return -1;
 	}
 	return 0;
 }
 
-int read_tree(void *buffer, unsigned long size, int stage)
+int read_tree(struct cache *cache, void *buffer, unsigned long size, int stage)
 {
-	return read_tree_recursive(buffer, size, "", 0, stage);
+	return read_tree_recursive(cache, buffer, size, "", 0, stage);
 }
 
 struct tree *lookup_tree(unsigned char *sha1)
Index: update-cache.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/update-cache.c  (mode:100644)
+++ uncommitted/update-cache.c  (mode:100644)
@@ -51,7 +51,7 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-static int add_file_to_cache(char *path)
+static int add_file_to_cache(struct cache *cache, char *path)
 {
 	int size, namelen, option, status;
 	struct cache_entry *ce;
@@ -71,7 +71,7 @@
 		 */
 		if (status == 0 || (errno == ENOENT || errno == ENOTDIR)) {
 			if (allow_remove)
-				return remove_file_from_cache(path);
+				return remove_file_from_cache(cache, path);
 		}
 		return error("open(\"%s\"): %s", path, strerror(errno));
 	}
@@ -106,7 +106,7 @@
 	}
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
-	return add_cache_entry(ce, option);
+	return add_cache_entry(cache, ce, option);
 }
 
 static int match_data(int fd, void *buffer, unsigned long size)
@@ -191,7 +191,7 @@
 	if (lstat(ce->name, &st) < 0)
 		return ERR_PTR(-errno);
 
-	changed = cache_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st);
 	if (!changed)
 		return ce;
 
@@ -222,19 +222,19 @@
 	return updated;
 }
 
-static int refresh_cache(void)
+static int refresh_cache(struct cache *cache)
 {
 	int i;
 	int has_errors = 0;
 
-	for (i = 0; i < active_nr; i++) {
+	for (i = 0; i < get_num_cache_entries(cache); i++) {
 		struct cache_entry *ce, *new;
-		ce = active_cache[i];
+		ce = get_cache_entry(cache, i);
 		if (ce_stage(ce)) {
 			printf("%s: needs merge\n", ce->name);
 			has_errors = 1;
-			while ((i < active_nr) &&
-			       ! strcmp(active_cache[i]->name, ce->name))
+			while ((i < get_num_cache_entries(cache)) &&
+			       ! strcmp(get_cache_entry(cache, i)->name, ce->name))
 				i++;
 			i--;
 			continue;
@@ -248,11 +248,7 @@
 			}
 			continue;
 		}
-		active_cache_changed = 1;
-		/* You can NOT just free active_cache[i] here, since it
-		 * might not be necessarily malloc()ed but can also come
-		 * from mmap(). */
-		active_cache[i] = new;
+		set_cache_entry(cache, new, i);
 	}
 	return has_errors;
 }
@@ -285,7 +281,7 @@
 	}
 }
 
-static int add_cacheinfo(char *arg1, char *arg2, char *arg3)
+static int add_cacheinfo(struct cache *cache, char *arg1, char *arg2, char *arg3)
 {
 	int size, len, option;
 	unsigned int mode;
@@ -310,7 +306,7 @@
 	ce->ce_mode = create_ce_mode(mode);
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
-	return add_cache_entry(ce, option);
+	return add_cache_entry(cache, ce, option);
 }
 
 static const char *lockfile_name = NULL;
@@ -328,10 +324,11 @@
 
 int main(int argc, char **argv)
 {
-	int i, newfd, entries, has_errors = 0;
+	int i, newfd, has_errors = 0;
 	int allow_options = 1;
 	static char lockfile[MAXPATHLEN+1];
 	const char *indexfile = get_index_file();
+	struct cache *cache = NULL;
 
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
@@ -343,8 +340,8 @@
 	atexit(remove_lock_file);
 	lockfile_name = lockfile;
 
-	entries = read_cache();
-	if (entries < 0)
+	cache = read_cache();
+	if (!cache)
 		die("cache corrupted");
 
 	for (i = 1 ; i < argc; i++) {
@@ -368,13 +365,13 @@
 				continue;
 			}
 			if (!strcmp(path, "--refresh")) {
-				has_errors |= refresh_cache();
+				has_errors |= refresh_cache(cache);
 				continue;
 			}
 			if (!strcmp(path, "--cacheinfo")) {
 				if (i+3 >= argc)
 					die("update-cache: --cacheinfo <mode> <sha1> <path>");
-				if (add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))
+				if (add_cacheinfo(cache, argv[i+1], argv[i+2], argv[i+3]))
 					die("update-cache: --cacheinfo cannot add %s", argv[i+3]);
 				i += 3;
 				continue;
@@ -382,7 +379,7 @@
 			if (!strcmp(path, "--force-remove")) {
 				if (argc <= i + 1)
 					die("update-cache: --force-remove <path>");
-				if (remove_file_from_cache(argv[i+1]))
+				if (remove_file_from_cache(cache, argv[i+1]))
 					die("update-cache: --force-remove cannot remove %s", argv[i+1]);
 				i++;
 				continue;
@@ -398,10 +395,10 @@
 			fprintf(stderr, "Ignoring path %s\n", argv[i]);
 			continue;
 		}
-		if (add_file_to_cache(path))
+		if (add_file_to_cache(cache, path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(cache, newfd) || rename(lockfile, indexfile))
 		die("Unable to write new cachefile");
 
 	lockfile_name = NULL;
Index: write-tree.c
===================================================================
--- c8c77f67ea85ee65a0f055f2cb76e6059eaa0776/write-tree.c  (mode:100644)
+++ uncommitted/write-tree.c  (mode:100644)
@@ -17,7 +17,7 @@
 	return ret;
 }
 
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
+static int write_tree(struct cache *cache, int start_pos, const char *base, int baselen, unsigned char *returnsha1)
 {
 	unsigned char subdir_sha1[20];
 	unsigned long size, offset;
@@ -30,8 +30,8 @@
 	offset = 0;
 
 	nr = 0;
-	while (nr < maxentries) {
-		struct cache_entry *ce = cachep[nr];
+	while ((start_pos + nr) < get_num_cache_entries(cache)) {
+		struct cache_entry *ce = get_cache_entry(cache, start_pos + nr);
 		const char *pathname = ce->name, *filename, *dirname;
 		int pathlen = ce_namelen(ce), entrylen;
 		unsigned char *sha1;
@@ -41,16 +41,13 @@
 		if (baselen >= pathlen || memcmp(base, pathname, baselen))
 			break;
 
-		sha1 = ce->sha1;
-		mode = ntohl(ce->ce_mode);
-
 		/* Do we have _further_ subdirectories? */
 		filename = pathname + baselen;
 		dirname = strchr(filename, '/');
 		if (dirname) {
 			int subdir_written;
 
-			subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
+			subdir_written = write_tree(cache, start_pos + nr, pathname, dirname-pathname+1, subdir_sha1);
 			nr += subdir_written;
 
 			/* Now we need to write out the directory entry into this tree.. */
@@ -60,6 +57,9 @@
 			/* ..but the directory entry doesn't count towards the total count */
 			nr--;
 			sha1 = subdir_sha1;
+		} else {
+			sha1 = ce->sha1;
+			mode = ntohl(ce->ce_mode);
 		}
 
 		if (check_valid_sha1(sha1) < 0)
@@ -85,16 +85,19 @@
 int main(int argc, char **argv)
 {
 	int i, funny;
-	int entries = read_cache();
+	struct cache *cache = read_cache();
+	int entries;
 	unsigned char sha1[20];
 
-	if (entries < 0)
+	if (!cache)
 		die("write-tree: error reading cache");
 
+	entries = get_num_cache_entries(cache);
+
 	/* Verify that the tree is merged */
 	funny = 0;
 	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = active_cache[i];
+		struct cache_entry *ce = get_cache_entry(cache, i);
 		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
 			if (10 < ++funny) {
 				fprintf(stderr, "...\n");
@@ -116,8 +119,8 @@
 		 * the cache is sorted.  Also path can appear only once,
 		 * which means conflicting one would immediately follow.
 		 */
-		const char *this_name = active_cache[i]->name;
-		const char *next_name = active_cache[i+1]->name;
+		const char *this_name = get_cache_entry(cache, i)->name;
+		const char *next_name = get_cache_entry(cache, i+1)->name;
 		int this_len = strlen(this_name);
 		if (this_len < strlen(next_name) &&
 		    strncmp(this_name, next_name, this_len) == 0 &&
@@ -134,7 +137,7 @@
 		die("write-tree: not able to write tree");
 
 	/* Ok, write it out */
-	if (write_tree(active_cache, entries, "", 0, sha1) != entries)
+	if (write_tree(cache, 0, "", 0, sha1) != entries)
 		die("write-tree: internal error");
 	printf("%s\n", sha1_to_hex(sha1));
 	return 0;

^ permalink raw reply	[relevance 9%]

* [PATCH 3/4] Implement git-checkout-cache -u to update stat information in the cache.
@ 2005-05-15 21:23 19% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-05-15 21:23 UTC (permalink / raw)
  To: pasky; +Cc: git, torvalds

With -u flag, git-checkout-cache picks up the stat information
from newly created file and updates the cache.  This removes the
need to run git-update-cache --refresh immediately after running
git-checkout-cache.
---

*** The one I posted earlier failed to add a couple of files
*** that the patch should have added.  Please discard it and
*** replace it with this one.  Thanks.

Documentation/git-checkout-cache.txt |    6 +++
Makefile                             |    2 -
cache.h                              |    9 +++++
checkout-cache.c                     |   35 ++++++++++++++++++++++-
index.c                              |   53 +++++++++++++++++++++++++++++++++++
read-cache.c                         |   20 +++++++++++++
t/t2002-checkout-cache-u.sh          |   31 ++++++++++++++++++++
update-cache.c                       |   48 ++-----------------------------
8 files changed, 157 insertions(+), 47 deletions(-)
index.c (. --> 100644)
t/t2002-checkout-cache-u.sh (. --> 100644)

--- a/Documentation/git-checkout-cache.txt
+++ b/Documentation/git-checkout-cache.txt
@@ -9,7 +9,7 @@
 
 SYNOPSIS
 --------
-'git-checkout-cache' [-q] [-a] [-f] [-n] [--prefix=<string>]
+'git-checkout-cache' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
 	           [--] <file>...
 
 DESCRIPTION
@@ -19,6 +19,10 @@
 
 OPTIONS
 -------
+-u::
+	update stat information for the checked out entries in
+	the cache file.
+
 -q::
 	be quiet if files exist or are not in the cache
 
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@
 	$(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 index.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h
 
--- a/cache.h
+++ b/cache.h
@@ -127,6 +127,15 @@
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
 extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
+
+struct cache_file {
+	struct cache_file *next;
+	char lockfile[PATH_MAX];
+};
+extern int hold_index_file_for_update(struct cache_file *, const char *path);
+extern int commit_index_file(struct cache_file *);
+extern void rollback_index_file(struct cache_file *);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
--- a/checkout-cache.c
+++ b/checkout-cache.c
@@ -36,7 +36,7 @@
 #include <dirent.h>
 #include "cache.h"
 
-static int force = 0, quiet = 0, not_new = 0;
+static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;
 
 static void create_directories(const char *path)
 {
@@ -154,6 +154,12 @@
 		free(new);
 		return error("checkout-cache: unknown file mode for %s", path);
 	}
+
+	if (refresh_cache) {
+		struct stat st;
+		lstat(ce->name, &st);
+		fill_stat_cache_info(ce, &st);
+	}
 	return 0;
 }
 
@@ -224,6 +230,8 @@
 {
 	int i, force_filename = 0;
 	const char *base_dir = "";
+	struct cache_file cache_file;
+	int newfd = -1;
 
 	if (read_cache() < 0) {
 		die("invalid cache");
@@ -252,12 +260,37 @@
 				not_new = 1;
 				continue;
 			}
+			if (!strcmp(arg, "-u")) {
+				refresh_cache = 1;
+				if (newfd < 0)
+					newfd = hold_index_file_for_update
+						(&cache_file,
+						 get_index_file());
+				if (newfd < 0)
+					die("cannot open index.lock file.");
+				continue;
+			}
 			if (!memcmp(arg, "--prefix=", 9)) {
 				base_dir = arg+9;
 				continue;
 			}
 		}
+		if (base_dir[0]) {
+			/* when --prefix is specified we do not
+			 * want to update cache.
+			 */
+			if (refresh_cache) {
+				close(newfd); newfd = -1;
+				rollback_index_file(&cache_file);
+			}
+			refresh_cache = 0;
+		}
 		checkout_file(arg, base_dir);
 	}
+
+	if (0 <= newfd &&
+	    (write_cache(newfd, active_cache, active_nr) ||
+	     commit_index_file(&cache_file)))
+		die("Unable to write new cachefile");
 	return 0;
 }
--- a/index.c
+++ b/index.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005, Junio C Hamano
+ */
+#include <signal.h>
+#include "cache.h"
+
+static struct cache_file *cache_file_list;
+
+static void remove_lock_file(void)
+{
+	while (cache_file_list) {
+		if (cache_file_list->lockfile[0])
+			unlink(cache_file_list->lockfile);
+		cache_file_list = cache_file_list->next;
+	}
+}
+
+static void remove_lock_file_on_signal(int signo)
+{
+	remove_lock_file();
+}
+
+int hold_index_file_for_update(struct cache_file *cf, const char *path)
+{
+	sprintf(cf->lockfile, "%s.lock", path);
+	cf->next = cache_file_list;
+	cache_file_list = cf;
+	if (!cf->next) {
+		signal(SIGINT, remove_lock_file_on_signal);
+		atexit(remove_lock_file);
+	}
+	return open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0600);
+}
+
+int commit_index_file(struct cache_file *cf)
+{
+	char indexfile[PATH_MAX];
+	int i;
+	strcpy(indexfile, cf->lockfile);
+	i = strlen(indexfile) - 5; /* .lock */
+	indexfile[i] = 0;
+	i = rename(cf->lockfile, indexfile);
+	cf->lockfile[0] = 0;
+	return i;
+}
+
+void rollback_index_file(struct cache_file *cf)
+{
+	if (cf->lockfile[0])
+		unlink(cf->lockfile);
+	cf->lockfile[0] = 0;
+}
+
--- a/read-cache.c
+++ b/read-cache.c
@@ -9,6 +9,26 @@
 struct cache_entry **active_cache = NULL;
 unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 
+/*
+ * This only updates the "non-critical" parts of the directory
+ * cache, ie the parts that aren't tracked by GIT, and only used
+ * to validate the cache.
+ */
+void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
+{
+	ce->ce_ctime.sec = htonl(st->st_ctime);
+	ce->ce_mtime.sec = htonl(st->st_mtime);
+#ifdef NSEC
+	ce->ce_ctime.nsec = htonl(st->st_ctim.tv_nsec);
+	ce->ce_mtime.nsec = htonl(st->st_mtim.tv_nsec);
+#endif
+	ce->ce_dev = htonl(st->st_dev);
+	ce->ce_ino = htonl(st->st_ino);
+	ce->ce_uid = htonl(st->st_uid);
+	ce->ce_gid = htonl(st->st_gid);
+	ce->ce_size = htonl(st->st_size);
+}
+
 int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
--- a/t/t2002-checkout-cache-u.sh
+++ b/t/t2002-checkout-cache-u.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-checkout-cache -u test.
+
+With -u flag, git-checkout-cache internally runs the equivalent of
+git-update-cache --refresh on the checked out entry.'
+
+. ./test-lib.sh
+
+test_expect_success \
+'preparation' '
+echo frotz >path0 &&
+git-update-cache --add path0 &&
+t=$(git-write-tree)'
+
+test_expect_failure \
+'without -u, git-checkout-cache smudges stat information.' '
+rm -f path0 &&
+git-read-tree $t &&
+git-checkout-cache -f -a &&
+git-diff-files | diff - /dev/null'
+
+test_expect_success \
+'with -u, git-checkout-cache picks up stat information from new files.' '
+rm -f path0 &&
+git-read-tree $t &&
+git-checkout-cache -u -f -a &&
+git-diff-files | diff - /dev/null'
--- a/update-cache.c
+++ b/update-cache.c
@@ -3,7 +3,6 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include <signal.h>
 #include "cache.h"
 
 /*
@@ -31,26 +30,6 @@
 	return (unsigned long)ptr > (unsigned long)-1000L;
 }
 
-/*
- * This only updates the "non-critical" parts of the directory
- * cache, ie the parts that aren't tracked by GIT, and only used
- * to validate the cache.
- */
-static void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
-{
-	ce->ce_ctime.sec = htonl(st->st_ctime);
-	ce->ce_mtime.sec = htonl(st->st_mtime);
-#ifdef NSEC
-	ce->ce_ctime.nsec = htonl(st->st_ctim.tv_nsec);
-	ce->ce_mtime.nsec = htonl(st->st_mtim.tv_nsec);
-#endif
-	ce->ce_dev = htonl(st->st_dev);
-	ce->ce_ino = htonl(st->st_ino);
-	ce->ce_uid = htonl(st->st_uid);
-	ce->ce_gid = htonl(st->st_gid);
-	ce->ce_size = htonl(st->st_size);
-}
-
 static int add_file_to_cache(char *path)
 {
 	int size, namelen, option, status;
@@ -313,36 +292,17 @@
 	return add_cache_entry(ce, option);
 }
 
-static const char *lockfile_name = NULL;
-
-static void remove_lock_file(void)
-{
-	if (lockfile_name)
-		unlink(lockfile_name);
-}
-
-static void remove_lock_file_on_signal(int signo)
-{
-	remove_lock_file();
-}
+struct cache_file cache_file;
 
 int main(int argc, char **argv)
 {
 	int i, newfd, entries, has_errors = 0;
 	int allow_options = 1;
-	static char lockfile[MAXPATHLEN+1];
-	const char *indexfile = get_index_file();
-
-	snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile);
 
-	newfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600);
+	newfd = hold_index_file_for_update(&cache_file, get_index_file());
 	if (newfd < 0)
 		die("unable to create new cachefile");
 
-	signal(SIGINT, remove_lock_file_on_signal);
-	atexit(remove_lock_file);
-	lockfile_name = lockfile;
-
 	entries = read_cache();
 	if (entries < 0)
 		die("cache corrupted");
@@ -401,9 +361,9 @@
 		if (add_file_to_cache(path))
 			die("Unable to add %s to database", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile))
+	if (write_cache(newfd, active_cache, active_nr) ||
+	    commit_index_file(&cache_file))
 		die("Unable to write new cachefile");
 
-	lockfile_name = NULL;
 	return has_errors ? 1 : 0;
 }



^ permalink raw reply	[relevance 19%]

* [PATCH] packed delta git
@ 2005-05-17 22:57 11% Chris Mason
  0 siblings, 0 replies; 200+ results
From: Chris Mason @ 2005-05-17 22:57 UTC (permalink / raw)
  To: git, Nicolas Pitre

Hello everyone,

Here's a new version of my packed git patch, diffed on top of Nicolas' 
delta code (link below to that).  It doesn't change the core git commands
to create packed/delta files, that is done via a new git-pack command.  The
git-pack usage is very simple:

git-pack [<reference_sha1>:]<target_sha1> [ <next_sha1> ... ]

If you use the ref:target notation, it will create a delta between those 
two objects and relink the target into the resulting packed file.  If you
don't provide a reference sha1, the sha1 file is relinked into the packed file.

A script is provided (git-pack-changes-script) that walks the rev-list output 
and puts your whole repository into packed/delta form.  This is just
a starting point, it needs more knobs for forward/reverse deltas,
max depth etc.  The script does delta tree files and packs both trees and 
commits in with the blobs.

git-diff-tree -t was added so that it will show the sha1 of subtrees that
differ while it processes things.

There is no way to unpack a file yet, so please use these with caution.

I did tests against the current 2.6 git tree (ext3)

                                      vanilla              delta+pack
.git size                          191M                62M
checkout-cache (cold)     2m13s              38.9s
checkout-cache (hot)      8s  (2s user)      14.9s (11.46s user)

2.6.11 without any changesets:
                                      unpacked          packed
.git size                           91M                  55M

Because the 2.6 kernel repo has 2.6.11 floating around in there as a tree
with no commit, you have to do a few steps in order to pack things in. 

# step one, pack all the files in 2.6.11 together
git-ls-tree -r v2.6.11 | awk '{print $3}' | xargs git-pack

# step two, make packed deltas between trees for 2.6.11 and 2.6.12-rc2
# (git-pack-changes-script -t only works with trees, not commits/tags)
git-pack-changes-script -t c39ae07f393806ccf406ef966e9a15afc43cc36a 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 | xargs git-pack

# step three, use git-pack-changes to walk whole rev-list and pack/delta
# everything else
git-pack-changes-script | xargs git-pack

And finally, here's the patch.  It is on top of Nicolas' code, which you
can grab here:

http://marc.theaimsgroup.com/?l=git&m=111587004902021&w=2

Signed-off-by: Chris Mason <mason@suse.com>
--

diff -urN linus.delta/cache.h linus/cache.h
--- linus.delta/cache.h	2005-05-17 16:51:51.410686192 -0400
+++ linus/cache.h	2005-05-17 15:17:16.015477408 -0400
@@ -77,6 +77,16 @@
 	char name[0];
 };
 
+struct packed_item {
+	/* length of compressed data */
+	unsigned long len;
+	struct packed_item *next;
+	/* sha1 of uncompressed data */
+	char sha1[20];
+	/* compressed data */
+	char *data;
+};
+
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_STAGESHIFT 12
@@ -135,8 +145,10 @@
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
+extern void * unpack_sha1_file(const unsigned char *sha1, void *map, unsigned long mapsize, char *type, unsigned long *size, const unsigned char *recur_sha1, int *chain);
+extern void * raw_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 void * read_sha1_delta_ref(const unsigned char *sha1, char *type, unsigned long *size, const unsigned char *, int *chain);
 extern int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
@@ -152,6 +164,10 @@
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
+extern int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+                            unsigned char *returnsha1, unsigned char *refsha1, 
+			    struct packed_item **, int max_depth);
+int write_packed_list(struct packed_item *head);
 
 /* General helper functions */
 extern void usage(const char *err);
Files linus.delta/.cache.h.swp and linus/.cache.h.swp differ
diff -urN linus.delta/diff-tree.c linus/diff-tree.c
--- linus.delta/diff-tree.c	2005-05-17 16:51:51.413685736 -0400
+++ linus/diff-tree.c	2005-05-16 20:08:41.000000000 -0400
@@ -5,6 +5,7 @@
 static int silent = 0;
 static int verbose_header = 0;
 static int ignore_merges = 1;
+static int show_tree_diffs = 0;
 static int recursive = 0;
 static int read_stdin = 0;
 static int line_termination = '\n';
@@ -114,6 +115,7 @@
 	const unsigned char *sha1, *sha2;
 	int cmp, pathlen1, pathlen2;
 	char old_sha1_hex[50];
+	int retval = 0;
 
 	sha1 = extract(tree1, size1, &path1, &mode1);
 	sha2 = extract(tree2, size2, &path2, &mode2);
@@ -143,11 +145,11 @@
 	}
 
 	if (recursive && S_ISDIR(mode1)) {
-		int retval;
 		char *newbase = malloc_base(base, path1, pathlen1);
 		retval = diff_tree_sha1(sha1, sha2, newbase);
 		free(newbase);
-		return retval;
+		if (!show_tree_diffs)
+			return retval;
 	}
 
 	if (header) {
@@ -155,7 +157,7 @@
 		header = NULL;
 	}
 	if (silent)
-		return 0;
+		return retval;
 
 	if (generate_patch) {
 		if (!S_ISDIR(mode1))
@@ -168,7 +170,7 @@
 		       old_sha1_hex, sha1_to_hex(sha2), base, path1,
 		       line_termination);
 	}
-	return 0;
+	return retval;
 }
 
 static int interesting(void *tree, unsigned long size, const char *base)
@@ -387,7 +389,7 @@
 }
 
 static char *diff_tree_usage =
-"diff-tree [-p] [-r] [-z] [--stdin] [-m] [-s] [-v] <tree sha1> <tree sha1>";
+"diff-tree [-p] [-r] [-z] [--stdin] [-m] [-s] [-v] [-t] <tree sha1> <tree sha1>";
 
 int main(int argc, char **argv)
 {
@@ -428,6 +430,10 @@
 			silent = 1;
 			continue;
 		}
+		if (!strcmp(arg, "-t")) {
+			show_tree_diffs = 1;
+			continue;
+		}
 		if (!strcmp(arg, "-v")) {
 			verbose_header = 1;
 			header_prefix = "diff-tree ";
diff -urN linus.delta/git-pack-changes-script linus/git-pack-changes-script
--- linus.delta/git-pack-changes-script	1969-12-31 19:00:00.000000000 -0500
+++ linus/git-pack-changes-script	2005-05-17 16:57:44.768967568 -0400
@@ -0,0 +1,161 @@
+#!/usr/bin/perl
+#
+# script to search through the rev-list output and generate delta history
+# you can specify either a start and stop commit or two trees to search.
+# with no command line args it searches the entire revision history.
+# output is suitable for piping to xargs git-pack
+
+use strict;
+
+my $ret;
+my $i;
+my @wanted = ();
+my $argc = scalar(@ARGV);
+my $commit;
+my $stop;
+my %delta = ();
+
+sub add_delta($$) {
+    my ($ref, $target) = @_;
+    if (defined($delta{$target})) {
+        return;
+    }
+    if ($target eq $delta{$ref}) {
+	print $ref;
+	return 1;
+    }
+    $delta{$target} = $ref;
+    print "$ref:$target\n";
+
+}
+sub print_usage() {
+    print STDERR "usage: pack-changes [-c commit] [-s stop commit] [-t tree1 tree2]\n";
+    exit(1);
+}
+
+sub find_tree($) {
+    my ($commit) = @_;
+    open(CM, "git-cat-file commit $commit|") || die "git-cat-file failed";
+    while(<CM>) {
+        chomp;
+	my @words = split;
+	if ($words[0] eq "tree") {
+	    return $words[1];
+	} elsif ($words[0] ne "parent") {
+	    last;
+	}
+    }
+    close(CM);
+    if ($? && ($ret = $? >> 8)) {
+        die "cat-file $commit failed with $ret";
+    }
+    return undef;
+}
+
+sub test_diff($$) {
+    my ($a, $b) = @_;
+    open(DT, "git-diff-tree -r -t $a $b|") || die "diff-tree failed";
+    while(<DT>) {
+        chomp;
+	my @words = split;
+	my $sha1 = $words[2];
+	my $change = $words[0];
+	if ($change =~ m/^\*/) {
+	    @words = split("->", $sha1);
+	    add_delta($words[0], $words[1]);
+	} elsif ($change =~ m/^\-/) {
+	    next;
+	} else {
+	    print "$sha1\n";
+	}
+    }
+    close(DT);
+    if ($? && ($ret = $? >> 8)) {
+	die "git-diff-tree failed with $ret";
+    }
+    return 0;
+}
+
+for ($i = 0 ; $i < $argc ; $i++)  {
+    if ($ARGV[$i] eq "-c") {
+    	if ($i == $argc - 1) {
+	    print_usage();
+	}
+	$commit = $ARGV[++$i];
+    } elsif ($ARGV[$i] eq "-s") {
+    	if ($i == $argc - 1) {
+	    print_usage();
+	}
+	$stop = $ARGV[++$i];
+    } elsif ($ARGV[$i] eq "-t") {
+        if ($argc != 3 || $i != 0) {
+	    print_usage();
+	}
+	if (test_diff($ARGV[1], $ARGV[2])) {
+	    die "test_diff failed\n";
+	}
+	add_delta($ARGV[1], $ARGV[2]);
+	exit(0);
+    }
+}
+
+if (!defined($commit)) {
+    $commit = `commit-id`;
+    if ($?) {
+    	print STDERR "commit-id failed, try using -c to specify a commit\n";
+	exit(1);
+    }
+    chomp $commit;
+}
+
+open(RL, "git-rev-list $commit|") || die "rev-list failed";
+while(<RL>) {
+    chomp;
+    my $cur = $_;
+    my $cur_tree;
+    my $parent_tree;
+    my $parent_commit = undef;
+    open(PARENT, "git-cat-file commit $cur|") || die "cat-file failed";
+    while(<PARENT>) {
+        chomp;
+	my @words = split;
+	if ($words[0] eq "tree") {
+	    $cur_tree = $words[1];
+	    next;
+	} elsif ($words[0] ne "parent") {
+	    last;
+	}
+	$parent_commit = $words[1];
+	my $next = <PARENT>;
+	# ignore merge sets for now
+	if ($next =~ m/^parent/) {
+	    last;
+	}
+	if (test_diff($words[1], $cur)) {
+	    die "test_diff failed\n";
+	}
+	$parent_tree = find_tree($words[1]);
+	if (!defined($parent_tree)) {
+	    die "failed to find tree for $words[1]\n";
+	}
+	add_delta($parent_tree, $cur_tree);
+	print "$cur\n";
+	last;
+    }
+    close(PARENT);
+    if (!defined($parent_commit)) {
+        print STDERR "parentless commit $cur\n";
+    }
+    if ($? && ($ret = $? >> 8)) {
+        die "cat-file failed with $ret";
+    }
+    if ($cur eq $stop) {
+        last;
+    }
+}
+close(RL);
+
+if ($? && ($ret = $? >> 8)) {
+    die "rev-list failed with $ret";
+}
+
diff -urN linus.delta/Makefile linus/Makefile
--- linus.delta/Makefile	2005-05-17 16:52:56.698760896 -0400
+++ linus/Makefile	2005-05-17 16:50:48.335275112 -0400
@@ -22,7 +22,7 @@
 	git-unpack-file git-export git-diff-cache git-convert-cache \
 	git-http-pull git-rpush git-rpull git-rev-list git-mktag \
 	git-diff-tree-helper git-tar-tree git-local-pull git-write-blob \
-	git-mkdelta
+	git-mkdelta git-pack
 
 all: $(PROG)
 
diff -urN linus.delta/mkdelta.c linus/mkdelta.c
--- linus.delta/mkdelta.c	2005-05-17 16:52:56.700760592 -0400
+++ linus/mkdelta.c	2005-05-16 17:21:37.000000000 -0400
@@ -95,7 +95,7 @@
 	unsigned long mapsize;
 	void *map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		void *buffer = unpack_sha1_file(map, mapsize, type, size);
+		void *buffer = raw_unpack_sha1_file(map, mapsize, type, size);
 		munmap(map, mapsize);
 		if (buffer)
 			return buffer;
diff -urN linus.delta/object.c linus/object.c
--- linus.delta/object.c	2005-05-17 16:51:51.419684824 -0400
+++ linus/object.c	2005-05-17 15:16:52.291084064 -0400
@@ -107,7 +107,7 @@
 		struct object *obj;
 		char type[100];
 		unsigned long size;
-		void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+		void *buffer = unpack_sha1_file(sha1, map, mapsize, type, &size, NULL, NULL);
 		munmap(map, mapsize);
 		if (!buffer)
 			return NULL;
diff -urN linus.delta/pack.c linus/pack.c
--- linus.delta/pack.c	1969-12-31 19:00:00.000000000 -0500
+++ linus/pack.c	2005-05-17 17:13:44.615048784 -0400
@@ -0,0 +1,122 @@
+/*
+ * pack and delta files in a GIT database
+ * (C) 2005 Chris Mason <mason@suse.com>
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "cache.h"
+#include "delta.h"
+
+static char *pack_usage = "pack [ --max-depth=N ] [<reference_sha1>:]<target_sha1> [ <next_sha1> ... ]";
+
+static int pack_sha1(unsigned char *sha1, unsigned char *refsha1, 
+		     struct packed_item **head, struct packed_item **tail, 
+		     unsigned long *packed_size, unsigned long *packed_nr, 
+		     int max_depth)
+{
+	struct packed_item *item;
+	char *buffer;
+	unsigned long size;
+	int ret;
+	char type[20];
+	unsigned char retsha1[20];
+
+	buffer = read_sha1_file(sha1, type, &size);
+	if (!buffer) {
+		fprintf(stderr, "failed to read %s\n", sha1_to_hex(sha1));
+		return -1;
+	}
+	ret = pack_sha1_buffer(buffer, size, type, retsha1, refsha1, &item, max_depth);
+	free(buffer);
+	if (memcmp(sha1, retsha1, 20)) {
+		fprintf(stderr, "retsha1 %s ", sha1_to_hex(retsha1));
+		fprintf(stderr, "sha1 %s\n", sha1_to_hex(sha1));
+		return -1;
+	}
+	if (memcmp(item->sha1, sha1, 20)) {
+		fprintf(stderr, "item sha1 %s ", sha1_to_hex(item->sha1));
+		fprintf(stderr, "sha1 %s\n", sha1_to_hex(sha1));
+		return -1;
+	}
+	if (ret)
+		return ret;
+	if (item) {
+		if (*tail)
+			(*tail)->next = item;
+		*tail = item;
+		if (!*head)
+			*head = item;
+		*packed_size += item->len;
+		(*packed_nr)++;
+		if (*packed_size > (512 * 1024) || *packed_nr > 1024) {
+			ret = write_packed_list(*head);
+			if (ret)
+				return ret;
+			*head = NULL;
+			*tail = NULL;
+			*packed_size = 0;
+			*packed_nr = 0;
+		}
+	}
+	return 0;
+}
+int main(int argc, char **argv)
+{
+	int i;
+	struct packed_item *head = NULL;
+	struct packed_item *tail = NULL;
+	unsigned long packed_size = 0;
+	unsigned long packed_nr = 0;
+	int verbose;
+	int depth_max = 16;
+	int ret;
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-v")) {
+			verbose = 1;
+		} else if (!strcmp(argv[i], "-d") && i+1 < argc) {
+			depth_max = atoi(argv[++i]);
+		} else if (!strncmp(argv[i], "--max-depth=", 12)) {
+			depth_max = atoi(argv[i]+12);
+		} else
+			break;
+	}
+	if (i == argc)
+		usage(pack_usage);
+	while(i < argc) {
+		unsigned char sha1[20];
+		unsigned char refsha1[20];
+		unsigned char *target;
+		unsigned char *ref = NULL;
+		target = strchr(argv[i], ':');
+		if (target) {
+			*target = '\0';
+			target++;
+			ref = argv[i];
+		} else {
+			target = argv[i];
+		}
+		if (get_sha1_hex(target, sha1)) {
+			fprintf(stderr, "unable to parse sha1 %s\n", argv[i]);
+			exit(1);
+		}
+		if (ref) {
+			if (get_sha1_hex(ref, refsha1)) {
+				fprintf(stderr, "unable to parse sha1 %s\n", argv[i]);
+				exit(1);
+			}
+			ref = refsha1;
+		}
+		ret = pack_sha1(sha1, ref, &head, &tail, &packed_size, &packed_nr, depth_max);
+		if (ret) {
+			fprintf(stderr, "pack_sha1 failed! %d\n", ret);
+			exit(1);
+		}
+		i++;
+	}
+
+	if (head)
+		write_packed_list(head);
+	return 0;
+}
diff -urN linus.delta/sha1_file.c linus/sha1_file.c
--- linus.delta/sha1_file.c	2005-05-17 16:52:56.697761048 -0400
+++ linus/sha1_file.c	2005-05-17 18:16:54.004973952 -0400
@@ -180,39 +180,132 @@
 	return map;
 }
 
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+/*
+ * looks through buf for the header entry corresponding to sha1.  returns
+ * 0 an entry is found and sets offset to the offset of the packed item
+ * in the file.  The offset is relative to the start of the packed items
+ * so you have to add in the length of the header before using it
+ * -1 is returned if the sha1 could not be found
+ */
+static int find_packed_header(const unsigned char *sha1, char *buf, unsigned long buf_len, unsigned long *offset)
+{
+	char *p;
+	p = buf;
+
+	*offset = 0;
+	while(p < buf + buf_len) {
+		unsigned long item_len;
+		unsigned char item_sha[20];
+		memcpy(item_sha, p, 20);
+		sscanf(p + 20, "%lu", &item_len);
+		p += 20 + strlen(p + 20) + 1;
+		if (memcmp(item_sha, sha1, 20) == 0)
+			return 0;
+		*offset += item_len;
+	}
+	return -1;
+}
+
+
+/*
+ * uncompresses a data segment without any extra delta/packed processing
+ */
+static void * _unpack_sha1_file(z_stream *stream, void *map, 
+                                unsigned long mapsize, char *type, 
+				unsigned long *size)
 {
 	int ret, bytes;
-	z_stream stream;
 	char buffer[8192];
 	char *buf;
 
 	/* Get the data stream */
-	memset(&stream, 0, sizeof(stream));
-	stream.next_in = map;
-	stream.avail_in = mapsize;
-	stream.next_out = buffer;
-	stream.avail_out = sizeof(buffer);
-
-	inflateInit(&stream);
-	ret = inflate(&stream, 0);
-	if (ret < Z_OK)
+	memset(stream, 0, sizeof(*stream));
+	stream->next_in = map;
+	stream->avail_in = mapsize;
+	stream->next_out = buffer;
+	stream->avail_out = sizeof(buffer);
+
+	inflateInit(stream);
+	ret = inflate(stream, 0);
+	if (ret < Z_OK) {
 		return NULL;
-	if (sscanf(buffer, "%10s %lu", type, size) != 2)
+	}
+	if (sscanf(buffer, "%10s %lu", type, size) != 2) {
 		return NULL;
-
+	}
 	bytes = strlen(buffer) + 1;
 	buf = xmalloc(*size);
 
-	memcpy(buf, buffer + bytes, stream.total_out - bytes);
-	bytes = stream.total_out - bytes;
+	memcpy(buf, buffer + bytes, stream->total_out - bytes);
+	bytes = stream->total_out - bytes;
 	if (bytes < *size && ret == Z_OK) {
-		stream.next_out = buf + bytes;
-		stream.avail_out = *size - bytes;
-		while (inflate(&stream, Z_FINISH) == Z_OK)
+		stream->next_out = buf + bytes;
+		stream->avail_out = *size - bytes;
+		while (inflate(stream, Z_FINISH) == Z_OK)
 			/* nothing */;
 	}
-	inflateEnd(&stream);
+	inflateEnd(stream);
+	return buf;
+}
+
+void * raw_unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+{
+	z_stream stream;
+	return _unpack_sha1_file(&stream, map, mapsize, type, size);
+}
+
+void * unpack_sha1_file(const unsigned char *sha1, void *map, 
+			unsigned long mapsize, char *type, unsigned long *size, 
+			const unsigned char *recur_sha1,
+			int *chain)
+{
+	z_stream stream;
+	char *buf;
+	unsigned long offset;
+	unsigned long header_len;
+	buf = _unpack_sha1_file(&stream, map, mapsize, type, size);
+	if (!buf)
+		return buf;
+	if (!strcmp(type, "delta")) {
+		char *delta_ref;
+		unsigned long delta_size;
+		char *newbuf;
+		unsigned long newsize;
+		if (recur_sha1 && memcmp(buf, recur_sha1, 20) == 0) {
+			free(buf);
+			return NULL;
+		}
+		if (chain)
+			*chain += 1;
+		delta_ref = read_sha1_delta_ref(buf, type, &delta_size, recur_sha1, chain);
+		if (!delta_ref) {
+			fprintf(stderr, "failed to read delta %s\n", sha1_to_hex(buf));
+			free(buf);
+			return NULL;
+		}
+		newbuf = patch_delta(delta_ref, delta_size, buf+20, *size-20, &newsize);
+		if (!newbuf) {
+			fprintf(stderr, "patch_delta failed %s %lu\n", sha1_to_hex(buf), delta_size);
+		}
+		free(buf);
+		free(delta_ref);
+		*size = newsize;
+		return newbuf;
+
+	} else if (!strcmp(type, "packed")) {
+		if (!sha1) {
+			free(buf);
+			return NULL;
+		}
+		header_len = *size;
+		if (find_packed_header(sha1, buf, header_len, &offset)) {
+			free(buf);
+			return NULL;
+		}
+		offset += stream.total_in;
+		free(buf);
+		buf = unpack_sha1_file(sha1, map+offset, mapsize-offset, type, size, recur_sha1, chain);
+	}
 	return buf;
 }
 
@@ -223,21 +316,26 @@
 
 	map = map_sha1_file(sha1, &mapsize);
 	if (map) {
-		buf = unpack_sha1_file(map, mapsize, type, size);
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size, NULL, NULL);
+		munmap(map, mapsize);
+		return buf;
+	}
+	return NULL;
+}
+
+/*
+ * the same as read_sha1_file except chain is used to count the length
+ * of any delta chains hit while unpacking
+ */
+void * read_sha1_delta_ref(const unsigned char *sha1, char *type, unsigned long *size, const unsigned char *recur_sha1, int *chain)
+{
+	unsigned long mapsize;
+	void *map, *buf;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (map) {
+		buf = unpack_sha1_file(sha1, map, mapsize, type, size, recur_sha1, chain);
 		munmap(map, mapsize);
-		if (buf && !strcmp(type, "delta")) {
-			void *ref = NULL, *delta = buf;
-			unsigned long ref_size, delta_size = *size;
-			buf = NULL;
-			if (delta_size > 20)
-				ref = read_sha1_file(delta, type, &ref_size);
-			if (ref)
-				buf = patch_delta(ref, ref_size,
-						  delta+20, delta_size-20, 
-						  size);
-			free(delta);
-			free(ref);
-		}
 		return buf;
 	}
 	return NULL;
@@ -482,3 +580,322 @@
 		munmap(buf, size);
 	return ret;
 }
+
+static void *compress_buffer(void *buf, unsigned long buf_len, char *metadata, 
+                             int metadata_size, unsigned long *compsize)
+{
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+
+	/* Set it up */
+	memset(&stream, 0, sizeof(stream));
+	size = deflateBound(&stream, buf_len + metadata_size);
+	compressed = xmalloc(size);
+
+	/*
+	 * ASCII size + nul byte
+	 */	
+	stream.next_in = metadata;
+	stream.avail_in = metadata_size;
+	stream.next_out = compressed;
+	stream.avail_out = size;
+	deflateInit(&stream, Z_BEST_COMPRESSION);
+	while (deflate(&stream, 0) == Z_OK)
+		/* nothing */;
+
+	stream.next_in = buf;
+	stream.avail_in = buf_len;
+	/* Compress it */
+	while (deflate(&stream, Z_FINISH) == Z_OK)
+		/* nothing */;
+	deflateEnd(&stream);
+	size = stream.total_out;
+	*compsize = size;
+	return compressed;
+}
+
+/*
+ * generates a delta for buf against refsha1 and returns a compressed buffer
+ * with the results.  NULL is returned on error, or when the delta could
+ * not be done.  This might happen if the delta is larger then either the
+ * refsha1 or the buffer, or the delta chain is too long.
+ */
+void *delta_buffer(void *buf, unsigned long buf_len, char *metadata, 
+                   int metadata_size, unsigned long *compsize, 
+		   unsigned char *sha1, unsigned char *refsha1, int max_chain)
+{
+	char *compressed;
+	char *refbuffer = NULL;
+	char reftype[20];
+	unsigned long refsize = 0;
+	char *delta;
+	unsigned long delta_size;
+	char *lmetadata = xmalloc(220);
+	unsigned long lmetadata_size;
+	int chain_length = 0;
+
+	if (buf_len == 0)
+		return NULL;
+	refbuffer = read_sha1_delta_ref(refsha1, reftype, &refsize, sha1, &chain_length);
+
+	if (chain_length > max_chain) {
+		free(refbuffer);
+		return NULL;
+	}
+	/* note, we could just continue without the delta here */
+	if (!refbuffer) {
+		free(refbuffer);
+		return NULL;
+	}
+	delta = diff_delta(refbuffer, refsize, buf, buf_len, &delta_size);
+	free(refbuffer);
+	if (!delta)
+		return NULL;
+	if (delta_size > refsize || delta_size > buf_len) {
+		free(delta);
+		return NULL;
+	}
+	if (delta_size < 10) {
+		free(delta);
+		return NULL;
+	}
+	lmetadata_size = 1 + sprintf(lmetadata, "%s %lu","delta",delta_size+20);
+	memcpy(lmetadata + lmetadata_size, refsha1, 20);
+	lmetadata_size += 20;
+	compressed = compress_buffer(delta, delta_size, lmetadata, lmetadata_size, compsize);
+	free(lmetadata);
+	free(delta);
+	return compressed;
+}
+
+/*
+ * returns a newly malloc'd packed item with a compressed buffer for buf.  
+ * If refsha1 is non-null, attempts a delta against it.  The sha1 of buf 
+ * is returned via returnsha1.
+ */
+int pack_sha1_buffer(void *buf, unsigned long buf_len, char *type,
+		     unsigned char *returnsha1,
+		     unsigned char *refsha1,
+		     struct packed_item **packed_item, int max_depth)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char *compressed = NULL;
+	unsigned long size;
+	struct packed_item *item;
+	char *metadata = xmalloc(200);
+	int metadata_size;
+
+	*packed_item = NULL;
+
+	metadata_size = 1 + sprintf(metadata, "%s %lu", type, buf_len);
+
+	/* Sha1.. */
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, buf, buf_len);
+	SHA1_Final(sha1, &c);
+
+	if (returnsha1)
+		memcpy(returnsha1, sha1, 20);
+
+	if (refsha1)
+		compressed = delta_buffer(buf, buf_len, metadata, 
+		                          metadata_size, &size, sha1, 
+					  refsha1, max_depth);
+	if (!compressed)
+		compressed = compress_buffer(buf, buf_len, metadata, 
+		                             metadata_size, &size);
+	free(metadata);
+	if (!compressed)
+		return -1;
+
+	item = xmalloc(sizeof(struct packed_item));
+	memcpy(item->sha1, sha1, 20);
+	item->len = size;
+	item->next = NULL;
+	item->data = compressed;
+	*packed_item = item;
+	return 0;
+}
+
+static char *create_packed_header(struct packed_item *head, unsigned long *size)
+{
+	char *metadata = NULL;
+	int metadata_size = 0;
+	*size = 0;
+	int entry_size = 0;
+
+	while(head) {
+		char *p;
+		metadata = realloc(metadata, metadata_size + 220);
+		if (!metadata)
+			return NULL;
+		p = metadata+metadata_size;
+		memcpy(p, head->sha1, 20);
+		p += 20;
+		entry_size = 1 + sprintf(p, "%lu", head->len);
+		metadata_size += entry_size + 20;
+		head = head->next;
+	}
+	*size = metadata_size;
+	return metadata;
+}
+
+#define WRITE_BUFFER_SIZE 8192
+static char write_buffer[WRITE_BUFFER_SIZE];
+static unsigned long write_buffer_len;
+
+static int c_write(int fd, void *data, unsigned int len)
+{
+	while (len) {
+		unsigned int buffered = write_buffer_len;
+		unsigned int partial = WRITE_BUFFER_SIZE - buffered;
+		if (partial > len)
+			partial = len;
+		memcpy(write_buffer + buffered, data, partial);
+		buffered += partial;
+		if (buffered == WRITE_BUFFER_SIZE) {
+			if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
+				return -1;
+			buffered = 0;
+		}
+		write_buffer_len = buffered;
+		len -= partial;
+		data += partial;
+ 	}
+ 	return 0;
+}
+
+static int c_flush(int fd)
+{
+	if (write_buffer_len) {
+		int left = write_buffer_len;
+		if (write(fd, write_buffer, left) != left)
+			return -1;
+		write_buffer_len = 0;
+	}
+	return 0;
+}
+
+/*
+ * creates a new packed file for all the items in head.  hard links are
+ * made from the sha1 of all the items back to the packd file, and then
+ * the packed file is unlinked.
+ */
+int write_packed_list(struct packed_item *head)
+{
+	unsigned char sha1[20];
+	SHA_CTX c;
+	char filename[PATH_MAX];
+	char *metadata = xmalloc(200);
+	char *header;
+	int metadata_size;
+	int fd;
+	int ret = 0;
+	unsigned long header_len;
+	struct packed_item *item;
+	char *compressed;
+	z_stream stream;
+	unsigned long size;
+
+	header = create_packed_header(head, &header_len);
+	metadata_size = 1+sprintf(metadata, "packed %lu", header_len);
+	/* 
+	 * the header contains the sha1 of each item, so we only sha1 the
+	 * header
+	 */ 
+	SHA1_Init(&c);
+	SHA1_Update(&c, metadata, metadata_size);
+	SHA1_Update(&c, header, header_len);
+	SHA1_Final(sha1, &c);
+
+	if (access(sha1_file_name(sha1), F_OK) == 0)
+		goto out_nofile;
+
+	snprintf(filename, sizeof(filename), "%s/obj_XXXXXX", get_object_directory());
+	fd = mkstemp(filename);
+	if (fd < 0) {
+		ret = -errno;
+		goto out_nofile;
+	}
+
+       /* compress just the header info */
+        memset(&stream, 0, sizeof(stream));
+        deflateInit(&stream, Z_BEST_COMPRESSION);
+	size = deflateBound(&stream, header_len + metadata_size);
+        compressed = xmalloc(size);
+
+        stream.next_in = metadata;
+        stream.avail_in = metadata_size;
+        stream.next_out = compressed;
+        stream.avail_out = size;
+        while (deflate(&stream, 0) == Z_OK)
+                /* nothing */;
+        stream.next_in = header;
+        stream.avail_in = header_len;
+        while (deflate(&stream, Z_FINISH) == Z_OK)
+                /* nothing */;
+        deflateEnd(&stream);
+        size = stream.total_out;
+
+	c_write(fd, compressed, size);
+	free(compressed);
+
+	item = head;
+	while(item) {
+		if (c_write(fd, item->data, item->len)) {
+			ret = -EIO;
+			goto out;
+		}
+		item = item->next;
+	}
+	if (c_flush(fd)) {
+		ret = -EIO;
+		goto out;
+	}
+	item = head;
+	while(item) {
+		char *item_file;
+		char item_tmp[PATH_MAX];
+		struct packed_item *next = item->next;
+		int name_iter = 0;
+		item_file = sha1_file_name(item->sha1);
+		while(1) {
+			/* ugly stuff.  We want to atomically replace any old objects
+			 * with the same sha1, making sure they don't get deleted
+			 * if any step along the way fails
+			 */
+			snprintf(item_tmp, sizeof(item_tmp), "%s/obj_%d", get_object_directory(), name_iter);
+			if (link(filename, item_tmp)) {
+				if (errno != EEXIST) {
+					ret = -errno;
+					goto out;
+				}
+			} else {
+				/* link success */
+				if (rename(item_tmp, item_file)) {
+					ret = -errno;
+					goto out;
+				}
+				break;
+			}
+			if (name_iter++ > 1000) {
+				ret = -1;
+				goto out;
+			}
+		}
+		free(item->data);
+		free(item);
+		item = next;
+	}
+out:
+	unlink(filename);
+	fchmod(fd, 0444);
+	close(fd);
+out_nofile:
+	free(header);
+	free(metadata);
+	return ret;
+}

^ permalink raw reply	[relevance 11%]

* [PATCH] Kill a bunch of pointer sign warnings for gcc4
@ 2005-05-18 12:14 19% Brian Gerst
  0 siblings, 0 replies; 200+ results
From: Brian Gerst @ 2005-05-18 12:14 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 417 bytes --]

- Raw hashes should be unsigned char.
- String functions want signed char.
- Hash and compress functions want unsigned char.

Signed-off By: Brian Gerst <bgerst@didntduck.org>
----------------------------

PS.
tar-tree.c: In function ‘main’:
tar-tree.c:437: warning: pointer targets in passing argument 1 of 
‘write_header’ differ in signedness

The "0" looks bogus, since it should be a raw hash not a text string.


[-- Attachment #2: ptrsign.diff --]
[-- Type: text/x-patch, Size: 8063 bytes --]

Kill a bunch of pointer sign warnings for gcc4.

---
commit 9d6d4056081ea693b9d0b28a1507921328df0b26
tree 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3
parent 02481aec2a2cfce7bc47d0d10876be5507f0b7ba
author <bgerst@citadel.(none)> Wed, 18 May 2005 07:59:28 -0400
committer <bgerst@citadel.(none)> Wed, 18 May 2005 07:59:28 -0400

 cache.h      |    4 ++--
 diff-cache.c |    2 +-
 diff-files.c |    4 ++--
 http-pull.c  |    4 ++--
 ls-tree.c    |    2 +-
 read-cache.c |    2 +-
 rpush.c      |    2 +-
 sha1_file.c  |   18 +++++++++---------
 strbuf.h     |    2 +-
 tar-tree.c   |    6 +++---
 10 files changed, 23 insertions(+), 23 deletions(-)

Index: cache.h
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/cache.h  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/cache.h  (mode:100644)
@@ -143,7 +143,7 @@
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 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 long len, const char *type, unsigned char *return_sha1);
+extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
@@ -167,7 +167,7 @@
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 
 extern void *read_object_with_reference(const unsigned char *sha1,
-					const unsigned char *required_type,
+					const char *required_type,
 					unsigned long *size,
 					unsigned char *sha1_ret);
 
Index: diff-cache.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/diff-cache.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/diff-cache.c  (mode:100644)
@@ -63,7 +63,7 @@
 {
 	unsigned int mode, oldmode;
 	unsigned char *sha1;
-	unsigned char old_sha1_hex[60];
+	char old_sha1_hex[60];
 
 	if (get_stat_data(new, &sha1, &mode) < 0) {
 		if (report_missing)
Index: diff-files.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/diff-files.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/diff-files.c  (mode:100644)
@@ -48,7 +48,7 @@
 }
 
 static void show_modified(int oldmode, int mode,
-			  const char *old_sha1, const char *sha1,
+			  const unsigned char *old_sha1, const unsigned char *sha1,
 			  char *path)
 {
 	char old_sha1_hex[41];
@@ -64,7 +64,7 @@
 
 int main(int argc, char **argv)
 {
-	static const char null_sha1[20] = { 0, };
+	static const unsigned char null_sha1[20] = { 0, };
 	int entries = read_cache();
 	int i;
 
Index: http-pull.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/http-pull.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/http-pull.c  (mode:100644)
@@ -24,7 +24,7 @@
 
 static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, 
 			       void *data) {
-	char expn[4096];
+	unsigned char expn[4096];
 	size_t size = eltsize * nmemb;
 	int posn = 0;
 	do {
@@ -49,7 +49,7 @@
 {
 	char *hex = sha1_to_hex(sha1);
 	char *filename = sha1_file_name(sha1);
-	char real_sha1[20];
+	unsigned char real_sha1[20];
 	char *url;
 	char *posn;
 
Index: ls-tree.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/ls-tree.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/ls-tree.c  (mode:100644)
@@ -24,7 +24,7 @@
 }
 
 static void list_recursive(void *buffer,
-			   const unsigned char *type,
+			   const char *type,
 			   unsigned long size,
 			   struct path_prefix *prefix)
 {
Index: read-cache.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/read-cache.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/read-cache.c  (mode:100644)
@@ -344,7 +344,7 @@
 }
 
 #define WRITE_BUFFER_SIZE 8192
-static char write_buffer[WRITE_BUFFER_SIZE];
+static unsigned char write_buffer[WRITE_BUFFER_SIZE];
 static unsigned long write_buffer_len;
 
 static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
Index: rpush.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/rpush.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/rpush.c  (mode:100644)
@@ -6,7 +6,7 @@
 void service(int fd_in, int fd_out) {
 	ssize_t size;
 	int posn;
-	char sha1[20];
+	char unsigned sha1[20];
 	unsigned long objsize;
 	void *buf;
 	do {
Index: sha1_file.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/sha1_file.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/sha1_file.c  (mode:100644)
@@ -313,13 +313,13 @@
 	int ret, bytes;
 	z_stream stream;
 	char buffer[8192];
-	char *buf;
+	unsigned char *buf;
 
 	/* Get the data stream */
 	memset(&stream, 0, sizeof(stream));
 	stream.next_in = map;
 	stream.avail_in = mapsize;
-	stream.next_out = buffer;
+	stream.next_out = (unsigned char *)buffer;
 	stream.avail_out = sizeof(buffer);
 
 	inflateInit(&stream);
@@ -359,7 +359,7 @@
 }
 
 void *read_object_with_reference(const unsigned char *sha1,
-				 const unsigned char *required_type,
+				 const char *required_type,
 				 unsigned long *size,
 				 unsigned char *actual_sha1_return)
 {
@@ -403,20 +403,20 @@
 	}
 }
 
-int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
 	int size;
-	char *compressed;
+	unsigned char *compressed;
 	z_stream stream;
 	unsigned char sha1[20];
 	SHA_CTX c;
 	char *filename;
 	static char tmpfile[PATH_MAX];
-	char hdr[50];
+	unsigned char hdr[50];
 	int fd, hdrlen, ret;
 
 	/* Generate the header */
-	hdrlen = sprintf(hdr, "%s %lu", type, len)+1;
+	hdrlen = sprintf((char *)hdr, "%s %lu", type, len)+1;
 
 	/* Sha1.. */
 	SHA1_Init(&c);
@@ -516,8 +516,8 @@
 	int local;
 	z_stream stream;
 	unsigned char real_sha1[20];
-	char buf[4096];
-	char discard[4096];
+	unsigned char buf[4096];
+	unsigned char discard[4096];
 	int ret;
 	SHA_CTX c;
 
Index: strbuf.h
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/strbuf.h  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/strbuf.h  (mode:100644)
@@ -4,7 +4,7 @@
 	int alloc;
 	int len;
 	int eof;
-	unsigned char *buf;
+	char *buf;
 };
 
 extern void strbuf_init(struct strbuf *);
Index: tar-tree.c
===================================================================
--- 2b3e8f627f4b8338e1479f6011052d2f6c0e2468/tar-tree.c  (mode:100644)
+++ 6da6a42bd7b97ea6ebd79544f4fb16713ac74dc3/tar-tree.c  (mode:100644)
@@ -205,7 +205,7 @@
 	append_char(p, '\n');
 }
 
-static void write_header(const char *, char, const char *, struct path_prefix *,
+static void write_header(const unsigned char *, char, const char *, struct path_prefix *,
                          const char *, unsigned int, void *, unsigned long);
 
 /* stores a pax extended header directly in the block buffer */
@@ -238,7 +238,7 @@
 	free(buffer);
 }
 
-static void write_global_extended_header(const char *sha1)
+static void write_global_extended_header(const unsigned char *sha1)
 {
 	char *p;
 	unsigned int size;
@@ -253,7 +253,7 @@
 }
 
 /* stores a ustar header directly in the block buffer */
-static void write_header(const char *sha1, char typeflag, const char *basepath,
+static void write_header(const unsigned char *sha1, char typeflag, const char *basepath,
                          struct path_prefix *prefix, const char *path,
                          unsigned int mode, void *buffer, unsigned long size)
 {


^ permalink raw reply	[relevance 19%]

* [PATCH] Remove gitenv macro hack
@ 2005-05-19 22:01 19% Dan Weber
  0 siblings, 0 replies; 200+ results
From: Dan Weber @ 2005-05-19 22:01 UTC (permalink / raw)
  To: Git Mailing List


Removed hacky macro for gitenv.  Often produced warnings by the compiler 
for the use of ?: without anything after the ?

Signed-off-by: Dan Weber <dan@mirrorlynx.com>

---
commit 1b48b369a152a6315a9b4e6eebf50f56176cdd82
tree 53c238f3aa788df47325c456ab16b0eb25004074
parent 5cd4c7b7686d334e341b21d92449349feda3ef65
author Dan Weber <dan@mirrorlynx.com> Thu, 19 May 2005 17:57:44 -0400
committer Dan Weber <dan@mirrorlynx.com> Thu, 19 May 2005 17:57:44 -0400

  cache.h |    8 +++++++-
  1 files changed, 7 insertions(+), 1 deletion(-)

Index: cache.h
===================================================================
--- ca5fef50fb68a3afbb35e1a48ac622f7a964f021/cache.h  (mode:100644)
+++ 53c238f3aa788df47325c456ab16b0eb25004074/cache.h  (mode:100644)
@@ -37,7 +37,13 @@
   * We accept older names for now but warn.
   */
  extern char *gitenv_bc(const char *);
-#define gitenv(e) (getenv(e) ? : gitenv_bc(e))
+static inline char* gitenv(const char* name) {
+       char* result = getenv(name);
+       if (result)
+               return result;
+       else
+               return gitenv_bc(name);
+}

  /*
   * Basic data structures for the directory cache


^ permalink raw reply	[relevance 19%]

* [PATCH] Adding limits.h to cache.h in order to compile under Solaris
@ 2005-05-21  9:13 19% Thomas Glanzmann
  0 siblings, 0 replies; 200+ results
From: Thomas Glanzmann @ 2005-05-21  9:13 UTC (permalink / raw)
  To: GIT

diff-tree 1ede81fa79aa5bd656f2b2aae3541719d306698d (from 559967c6d4fa3bab269d4a22d2db23f70e0156b7)
Author: Thomas Glanzmann <sithglan@stud.uni-erlangen.de>
Date:   Sat May 21 10:50:22 2005 +0200
    
    Adding limits.h to cache.h in order to compile under Solaris

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -2,6 +2,7 @@
 #define CACHE_H
 
 #include <unistd.h>
+#include <limits.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <fcntl.h>

^ permalink raw reply	[relevance 19%]

* [PATCH] Handle deltified object correctly in git-*-pull family.
  @ 2005-06-02 16:46 13%   ` Junio C Hamano
    2005-06-02 16:49 14%   ` Junio C Hamano
  1 sibling, 1 reply; 200+ results
From: Junio C Hamano @ 2005-06-02 16:46 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

When a remote repository is deltified, we need to get the
objects that a deltified object we want to obtain is based upon.
The initial parts of each retrieved SHA1 file is inflated and
inspected to see if it is deltified, and its base object is
asked from the remote side when it is.  Since this partial
inflation and inspection has a small performance hit, it can
optionally be skipped by giving -d flag to git-*-pull commands.
This flag should be used only when the remote repository is
known to have no deltified objects.

Rsync transport does not have this problem since it fetches
everything the remote side has.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** Linus, this uses the new helper you wrote.  The interface is
*** much more pleasant to use.

 Documentation/git-http-pull.txt  |    6 +++++-
 Documentation/git-local-pull.txt |    6 +++++-
 Documentation/git-rpull.txt      |    6 +++++-
 cache.h                          |    3 +++
 pull.h                           |    3 +++
 http-pull.c                      |    4 +++-
 local-pull.c                     |    4 +++-
 pull.c                           |    6 ++++++
 rpull.c                          |    4 +++-
 sha1_file.c                      |   40 ++++++++++++++++++++++++++++++++++++++
 10 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
 
 SYNOPSIS
 --------
-'git-http-pull' [-c] [-t] [-a] [-v] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-v] [-d] commit-id url
 
 DESCRIPTION
 -----------
@@ -21,6 +21,10 @@ Downloads a remote GIT repository via HT
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-local-pull.txt b/Documentation/git-local-pull.txt
--- a/Documentation/git-local-pull.txt
+++ b/Documentation/git-local-pull.txt
@@ -9,7 +9,7 @@ git-local-pull - Duplicates another GIT 
 
 SYNOPSIS
 --------
-'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path
+'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path
 
 DESCRIPTION
 -----------
@@ -23,6 +23,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-rpull.txt b/Documentation/git-rpull.txt
--- a/Documentation/git-rpull.txt
+++ b/Documentation/git-rpull.txt
@@ -10,7 +10,7 @@ git-rpull - Pulls from a remote reposito
 
 SYNOPSIS
 --------
-'git-rpull' [-c] [-t] [-a] [-v] commit-id url
+'git-rpull' [-c] [-t] [-a] [-d] [-v] commit-id url
 
 DESCRIPTION
 -----------
@@ -25,6 +25,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -158,6 +158,9 @@ extern int write_sha1_file(void *buf, un
 
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
+extern int sha1_delta_base(const unsigned char *, unsigned char *);
+
+
 /* Read a tree into the cache */
 extern int read_tree(void *buffer, unsigned long size, int stage);
 
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -13,6 +13,9 @@ extern int get_history;
 /** Set to fetch the trees in the commit history. **/
 extern int get_all;
 
+/* Set to zero to skip the check for delta object base. */
+extern int get_delta;
+
 /* Set to be verbose */
 extern int get_verbosely;
 
diff --git a/http-pull.c b/http-pull.c
--- a/http-pull.c
+++ b/http-pull.c
@@ -103,6 +103,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-http-pull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-http-pull [-c] [-t] [-a] [-d] [-v] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -74,7 +74,7 @@ int fetch(unsigned char *sha1)
 }
 
 static const char *local_pull_usage = 
-"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path";
+"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
 
 /* 
  * By default we only use file copy.
@@ -92,6 +92,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		else if (argv[arg][1] == 'c')
 			get_history = 1;
+		else if (argv[arg][1] == 'd')
+			get_delta = 0;
 		else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
diff --git a/pull.c b/pull.c
--- a/pull.c
+++ b/pull.c
@@ -6,6 +6,7 @@
 
 int get_tree = 0;
 int get_history = 0;
+int get_delta = 1;
 int get_all = 0;
 int get_verbosely = 0;
 static unsigned char current_commit_sha1[20];
@@ -37,6 +38,11 @@ static int make_sure_we_have_it(const ch
 	status = fetch(sha1);
 	if (status && what)
 		report_missing(what, sha1);
+	if (get_delta) {
+		char delta_sha1[20];
+		if (sha1_delta_base(sha1, delta_sha1))
+			status = make_sure_we_have_it(what, delta_sha1);
+	}
 	return status;
 }
 
diff --git a/rpull.c b/rpull.c
--- a/rpull.c
+++ b/rpull.c
@@ -27,6 +27,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -37,7 +39,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-rpull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-rpull [-c] [-t] [-a] [-v] [-d] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -347,6 +347,46 @@ void * unpack_sha1_file(void *map, unsig
 	return buf;
 }
 
+int sha1_delta_base(const unsigned char *sha1, unsigned char *delta_sha1)
+{
+	unsigned long mapsize, size;
+	void *map;
+	char type[20];
+	char buffer[200];
+	z_stream stream;
+	int ret, bytes, status;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return 0;
+	ret = unpack_sha1_header(&stream, map, mapsize, buffer,
+				 sizeof(buffer));
+	status = 0;
+
+	if (ret < Z_OK ||
+	    sscanf(buffer, "%10s %lu", type, &size) != 2 ||
+	    strcmp(type, "delta"))
+		goto out;
+	bytes = strlen(buffer) + 1;
+	if (size - bytes < 20)
+		goto out;
+
+	memmove(buffer, buffer + bytes, stream.total_out - bytes);
+	bytes = stream.total_out - bytes;
+	if (bytes < 20 && ret == Z_OK) {
+		stream.next_out = buffer + bytes;
+		stream.avail_out = sizeof(buffer) - bytes;
+		while (inflate(&stream, Z_FINISH) == Z_OK)
+			; /* nothing */
+	}
+	status = 1;
+	memcpy(delta_sha1, buffer, 20);
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return status;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 13%]

* [PATCH] Find size of SHA1 object without inflating everything.
    2005-06-02 16:46 13%   ` [PATCH] Handle deltified object correctly in git-*-pull family Junio C Hamano
@ 2005-06-02 16:49 14%   ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-02 16:49 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This adds sha1_file_size() helper function and uses it in the
rename/copy similarity estimator.  The helper function handles
deltified object as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** Linus, this also uses the new helper you wrote.

 cache.h     |    2 +-
 diff.c      |   11 +++++---
 sha1_file.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -159,7 +159,7 @@ extern int write_sha1_file(void *buf, un
 extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
 extern int sha1_delta_base(const unsigned char *, unsigned char *);
-
+extern int sha1_file_size(const unsigned char *, unsigned long *);
 
 /* Read a tree into the cache */
 extern int read_tree(void *buffer, unsigned long size, int stage);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -333,7 +333,6 @@ int diff_populate_filespec(struct diff_f
 		close(fd);
 	}
 	else {
-		/* We cannot do size only for SHA1 blobs */
 		char type[20];
 		struct sha1_size_cache *e;
 
@@ -343,11 +342,13 @@ int diff_populate_filespec(struct diff_f
 				s->size = e->size;
 				return 0;
 			}
+			if (!sha1_file_size(s->sha1, &s->size))
+				locate_size_cache(s->sha1, s->size);
+		}
+		else {
+			s->data = read_sha1_file(s->sha1, type, &s->size);
+			s->should_free = 1;
 		}
-		s->data = read_sha1_file(s->sha1, type, &s->size);
-		s->should_free = 1;
-		if (s->data && size_only)
-			locate_size_cache(s->sha1, s->size);
 	}
 	return 0;
 }
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -387,6 +387,84 @@ int sha1_delta_base(const unsigned char 
 	return status;
 }
 
+int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
+{
+	unsigned long mapsize, size;
+	void *map;
+	char type[20];
+	char buffer[200];
+	z_stream stream;
+	int ret, bytes, status;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return 0;
+	ret = unpack_sha1_header(&stream, map, mapsize, buffer,
+				 sizeof(buffer));
+	status = -1;
+
+	if (ret < Z_OK || sscanf(buffer, "%10s %lu", type, &size) != 2)
+		goto out;
+	if (strcmp(type, "delta")) {
+		*sizep = size;
+		status = 0;
+		goto out;
+	}
+
+	/* We are dealing with delta object.  Inflated, the first 20
+	 * bytes hold the base object SHA1, and delta data follows
+	 * immediately after it.
+	 */
+	bytes = strlen(buffer) + 1;
+	if (size < bytes + 6 + 20)
+		goto out; /* the smallest delta size is 6 bytes */
+
+	memmove(buffer, buffer + bytes, stream.total_out - bytes);
+	bytes = stream.total_out - bytes;
+	if (bytes < sizeof(buffer) && ret == Z_OK) {
+		stream.next_out = buffer + bytes;
+		stream.avail_out = sizeof(buffer) - bytes;
+		while (inflate(&stream, Z_FINISH) == Z_OK)
+			; /* nothing */
+	}
+
+	/* We have read initial part of the delta, which starts at
+	 * buffer+20.  Borrow code from patch-delta to read the
+	 * result size.
+	 */
+	{
+		const unsigned char *data = buffer + 20;
+		unsigned char cmd;
+		int i;
+
+		/* Skip over the source size; we are not interested in
+		 * it and we cannot verify it because we do not want
+		 * to read the base object.
+		 */
+		cmd = *data++;
+		while (cmd) {
+			if (cmd & 1)
+				data++;
+			cmd >>= 1;
+		}
+		/* Read the result size */
+		size = i = 0;
+		cmd = *data++;
+		while (cmd) {
+			if (cmd & 1)
+				size |= *data++ << i;
+			i += 8;
+			cmd >>= 1;
+		}
+		*sizep = size;
+	}
+	status = 0;
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return status;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 14%]

* [PATCH] Handle deltified object correctly in git-*-pull family.
  @ 2005-06-02 18:55 12%       ` Junio C Hamano
    2005-06-02 18:57 14%       ` [PATCH] " Junio C Hamano
  1 sibling, 1 reply; 200+ results
From: Junio C Hamano @ 2005-06-02 18:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

When a remote repository is deltified, we need to get the
objects that a deltified object we want to obtain is based upon.
The initial parts of each retrieved SHA1 file is inflated and
inspected to see if it is deltified, and its base object is
asked from the remote side when it is.  Since this partial
inflation and inspection has a small performance hit, it can
optionally be skipped by giving -d flag to git-*-pull commands.
This flag should be used only when the remote repository is
known to have no deltified objects.

Rsync transport does not have this problem since it fetches
everything the remote side has.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** Now uses parse_sha1_header() and unpack_sha1_rest().  I
*** decided not to make it the callers responsibility to check
*** what we have already got and fixed unpack_sha1_rest() to
*** avoid copying more than size bytes.

 Documentation/git-http-pull.txt  |    6 ++++-
 Documentation/git-local-pull.txt |    6 ++++-
 Documentation/git-rpull.txt      |    6 ++++-
 cache.h                          |    1 +
 pull.h                           |    3 +++
 http-pull.c                      |    4 +++-
 local-pull.c                     |    4 +++-
 pull.c                           |    7 ++++++
 rpull.c                          |    4 +++-
 sha1_file.c                      |   43 +++++++++++++++++++++++++++++++++++++-
 10 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
 
 SYNOPSIS
 --------
-'git-http-pull' [-c] [-t] [-a] [-v] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-v] [-d] commit-id url
 
 DESCRIPTION
 -----------
@@ -21,6 +21,10 @@ Downloads a remote GIT repository via HT
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-local-pull.txt b/Documentation/git-local-pull.txt
--- a/Documentation/git-local-pull.txt
+++ b/Documentation/git-local-pull.txt
@@ -9,7 +9,7 @@ git-local-pull - Duplicates another GIT 
 
 SYNOPSIS
 --------
-'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path
+'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path
 
 DESCRIPTION
 -----------
@@ -23,6 +23,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-rpull.txt b/Documentation/git-rpull.txt
--- a/Documentation/git-rpull.txt
+++ b/Documentation/git-rpull.txt
@@ -10,7 +10,7 @@ git-rpull - Pulls from a remote reposito
 
 SYNOPSIS
 --------
-'git-rpull' [-c] [-t] [-a] [-v] commit-id url
+'git-rpull' [-c] [-t] [-a] [-d] [-v] commit-id url
 
 DESCRIPTION
 -----------
@@ -25,6 +25,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern int sha1_delta_base(const unsigned char *, unsigned char *);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -13,6 +13,9 @@ extern int get_history;
 /** Set to fetch the trees in the commit history. **/
 extern int get_all;
 
+/* Set to zero to skip the check for delta object base. */
+extern int get_delta;
+
 /* Set to be verbose */
 extern int get_verbosely;
 
diff --git a/http-pull.c b/http-pull.c
--- a/http-pull.c
+++ b/http-pull.c
@@ -103,6 +103,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-http-pull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-http-pull [-c] [-t] [-a] [-d] [-v] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -74,7 +74,7 @@ int fetch(unsigned char *sha1)
 }
 
 static const char *local_pull_usage = 
-"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path";
+"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
 
 /* 
  * By default we only use file copy.
@@ -92,6 +92,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		else if (argv[arg][1] == 'c')
 			get_history = 1;
+		else if (argv[arg][1] == 'd')
+			get_delta = 0;
 		else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
diff --git a/pull.c b/pull.c
--- a/pull.c
+++ b/pull.c
@@ -6,6 +6,7 @@
 
 int get_tree = 0;
 int get_history = 0;
+int get_delta = 1;
 int get_all = 0;
 int get_verbosely = 0;
 static unsigned char current_commit_sha1[20];
@@ -37,6 +38,12 @@ static int make_sure_we_have_it(const ch
 	status = fetch(sha1);
 	if (status && what)
 		report_missing(what, sha1);
+	if (get_delta) {
+		char delta_sha1[20];
+		status = sha1_delta_base(sha1, delta_sha1);
+		if (0 < status)
+			status = make_sure_we_have_it(what, delta_sha1);
+	}
 	return status;
 }
 
diff --git a/rpull.c b/rpull.c
--- a/rpull.c
+++ b/rpull.c
@@ -27,6 +27,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -37,7 +39,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-rpull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-rpull [-c] [-t] [-a] [-v] [-d] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -325,7 +325,13 @@ void *unpack_sha1_rest(z_stream *stream,
 	int bytes = strlen(buffer) + 1;
 	char *buf = xmalloc(1+size);
 
-	memcpy(buf, buffer + bytes, stream->total_out - bytes);
+	/* (stream->total_out - bytes) is what we already have.  The
+	 * caller could be asking for something smaller than that.
+	 */
+	if (size < stream->total_out - bytes)
+		memcpy(buf, buffer + bytes, size);
+	else
+		memcpy(buf, buffer + bytes, stream->total_out - bytes);
 	bytes = stream->total_out - bytes;
 	if (bytes < size) {
 		stream->next_out = buf + bytes;
@@ -401,6 +407,41 @@ void * unpack_sha1_file(void *map, unsig
 	return unpack_sha1_rest(&stream, hdr, *size);
 }
 
+int sha1_delta_base(const unsigned char *sha1, unsigned char *base_sha1)
+{
+	int ret;
+	unsigned long mapsize, size;
+	void *map;
+	z_stream stream;
+	char hdr[1024], type[20];
+	void *delta_data_head;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return -1;
+	ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+	if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
+		ret = -1;
+		goto out;
+	}
+	if (strcmp(type, "delta")) {
+		ret = 0;
+		goto out;
+	}
+	delta_data_head = unpack_sha1_rest(&stream, hdr, 20);
+	if (!delta_data_head) {
+		ret = -1;
+		goto out;
+	}
+	ret = 1;
+	memcpy(base_sha1, delta_data_head, 20);
+	free(delta_data_head);
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return ret;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 12%]

* [PATCH] Find size of SHA1 object without inflating everything.
    2005-06-02 18:55 12%       ` Junio C Hamano
@ 2005-06-02 18:57 14%       ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-02 18:57 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This adds sha1_file_size() helper function and uses it in the
rename/copy similarity estimator.  The helper function handles
deltified object as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** The U*MAX fix patch from previous round still applies, so I am
*** resending it to you.  This probably would depend on it, so
*** please apply U*MAX fix patch before this one.

 cache.h     |    1 +
 diff.c      |   11 ++++++----
 sha1_file.c |   64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -154,6 +154,7 @@ extern void * map_sha1_file(const unsign
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
 extern int sha1_delta_base(const unsigned char *, unsigned char *);
+extern int sha1_file_size(const unsigned char *, unsigned long *);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -333,7 +333,6 @@ int diff_populate_filespec(struct diff_f
 		close(fd);
 	}
 	else {
-		/* We cannot do size only for SHA1 blobs */
 		char type[20];
 		struct sha1_size_cache *e;
 
@@ -343,11 +342,13 @@ int diff_populate_filespec(struct diff_f
 				s->size = e->size;
 				return 0;
 			}
+			if (!sha1_file_size(s->sha1, &s->size))
+				locate_size_cache(s->sha1, s->size);
+		}
+		else {
+			s->data = read_sha1_file(s->sha1, type, &s->size);
+			s->should_free = 1;
 		}
-		s->data = read_sha1_file(s->sha1, type, &s->size);
-		s->should_free = 1;
-		if (s->data && size_only)
-			locate_size_cache(s->sha1, s->size);
 	}
 	return 0;
 }
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -442,6 +442,70 @@ int sha1_delta_base(const unsigned char 
 	return ret;
 }
 
+int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
+{
+	int ret, status;
+	unsigned long mapsize, size;
+	void *map;
+	z_stream stream;
+	char hdr[1024], type[20];
+	void *delta_data_head;
+	const unsigned char *data;
+	unsigned char cmd;
+	int i;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return -1;
+	ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+	status = -1;
+	if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0)
+		goto out;
+	if (strcmp(type, "delta")) {
+		*sizep = size;
+		status = 0;
+		goto out;
+	}
+
+	/* We are dealing with delta object.  Inflated, the first 20
+	 * bytes hold the base object SHA1, and delta data follows
+	 * immediately after it.
+	 */
+	delta_data_head = unpack_sha1_rest(&stream, hdr, 200);
+
+	/* The initial part of the delta starts at delta_data_head +
+	 * 20.  Borrow code from patch-delta to read the result size.
+	 */
+
+	data = delta_data_head + 20;
+
+	/* Skip over the source size; we are not interested in
+	 * it and we cannot verify it because we do not want
+	 * to read the base object.
+	 */
+	cmd = *data++;
+	while (cmd) {
+		if (cmd & 1)
+			data++;
+		cmd >>= 1;
+	}
+	/* Read the result size */
+	size = i = 0;
+	cmd = *data++;
+	while (cmd) {
+		if (cmd & 1)
+			size |= *data++ << i;
+		i += 8;
+		cmd >>= 1;
+	}
+	*sizep = size;
+	status = 0;
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return status;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 14%]

* [PATCH 1/2] Handle deltified object correctly in git-*-pull family.
  @ 2005-06-02 22:19 13%             ` Junio C Hamano
  2005-06-02 22:20 14%             ` [PATCH 2/2] Find size of SHA1 object without inflating everything Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-02 22:19 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Nicolas Pitre, git

>>>>> "NP" == Nicolas Pitre <nico@cam.org> writes:

>> Here you don't need to call unpack_sha1_rest() at all which would call 
>> xmalloc and another memcpy needlessly.  Instead,...

Like this...

------------
When a remote repository is deltified, we need to get the
objects that a deltified object we want to obtain is based upon.
The initial parts of each retrieved SHA1 file is inflated and
inspected to see if it is deltified, and its base object is
asked from the remote side when it is.  Since this partial
inflation and inspection has a small performance hit, it can
optionally be skipped by giving -d flag to git-*-pull commands.
This flag should be used only when the remote repository is
known to have no deltified objects.

Rsync transport does not have this problem since it fetches
everything the remote side has.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** Thanks and credits goes to Nico for suggesting not to
*** use unpack_sha1_rest().

 Documentation/git-http-pull.txt  |    6 +++++-
 Documentation/git-local-pull.txt |    6 +++++-
 Documentation/git-rpull.txt      |    6 +++++-
 cache.h                          |    1 +
 pull.h                           |    3 +++
 http-pull.c                      |    4 +++-
 local-pull.c                     |    4 +++-
 pull.c                           |    7 +++++++
 rpull.c                          |    4 +++-
 sha1_file.c                      |   31 +++++++++++++++++++++++++++++++
 10 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
 
 SYNOPSIS
 --------
-'git-http-pull' [-c] [-t] [-a] [-v] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-v] [-d] commit-id url
 
 DESCRIPTION
 -----------
@@ -21,6 +21,10 @@ Downloads a remote GIT repository via HT
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-local-pull.txt b/Documentation/git-local-pull.txt
--- a/Documentation/git-local-pull.txt
+++ b/Documentation/git-local-pull.txt
@@ -9,7 +9,7 @@ git-local-pull - Duplicates another GIT 
 
 SYNOPSIS
 --------
-'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path
+'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path
 
 DESCRIPTION
 -----------
@@ -23,6 +23,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/Documentation/git-rpull.txt b/Documentation/git-rpull.txt
--- a/Documentation/git-rpull.txt
+++ b/Documentation/git-rpull.txt
@@ -10,7 +10,7 @@ git-rpull - Pulls from a remote reposito
 
 SYNOPSIS
 --------
-'git-rpull' [-c] [-t] [-a] [-v] commit-id url
+'git-rpull' [-c] [-t] [-a] [-d] [-v] commit-id url
 
 DESCRIPTION
 -----------
@@ -25,6 +25,10 @@ OPTIONS
 	Get trees associated with the commit objects.
 -a::
 	Get all the objects.
+-d::
+	Do not check for delta base objects (use this option
+	only when you know the remote repository is not
+	deltified).
 -v::
 	Report what is downloaded.
 
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern int sha1_delta_base(const unsigned char *, unsigned char *);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -13,6 +13,9 @@ extern int get_history;
 /** Set to fetch the trees in the commit history. **/
 extern int get_all;
 
+/* Set to zero to skip the check for delta object base. */
+extern int get_delta;
+
 /* Set to be verbose */
 extern int get_verbosely;
 
diff --git a/http-pull.c b/http-pull.c
--- a/http-pull.c
+++ b/http-pull.c
@@ -103,6 +103,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-http-pull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-http-pull [-c] [-t] [-a] [-d] [-v] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -74,7 +74,7 @@ int fetch(unsigned char *sha1)
 }
 
 static const char *local_pull_usage = 
-"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path";
+"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
 
 /* 
  * By default we only use file copy.
@@ -92,6 +92,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		else if (argv[arg][1] == 'c')
 			get_history = 1;
+		else if (argv[arg][1] == 'd')
+			get_delta = 0;
 		else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
diff --git a/pull.c b/pull.c
--- a/pull.c
+++ b/pull.c
@@ -6,6 +6,7 @@
 
 int get_tree = 0;
 int get_history = 0;
+int get_delta = 1;
 int get_all = 0;
 int get_verbosely = 0;
 static unsigned char current_commit_sha1[20];
@@ -37,6 +38,12 @@ static int make_sure_we_have_it(const ch
 	status = fetch(sha1);
 	if (status && what)
 		report_missing(what, sha1);
+	if (get_delta) {
+		char delta_sha1[20];
+		status = sha1_delta_base(sha1, delta_sha1);
+		if (0 < status)
+			status = make_sure_we_have_it(what, delta_sha1);
+	}
 	return status;
 }
 
diff --git a/rpull.c b/rpull.c
--- a/rpull.c
+++ b/rpull.c
@@ -27,6 +27,8 @@ int main(int argc, char **argv)
 			get_tree = 1;
 		} else if (argv[arg][1] == 'c') {
 			get_history = 1;
+		} else if (argv[arg][1] == 'd') {
+			get_delta = 0;
 		} else if (argv[arg][1] == 'a') {
 			get_all = 1;
 			get_tree = 1;
@@ -37,7 +39,7 @@ int main(int argc, char **argv)
 		arg++;
 	}
 	if (argc < arg + 2) {
-		usage("git-rpull [-c] [-t] [-a] [-v] commit-id url");
+		usage("git-rpull [-c] [-t] [-a] [-v] [-d] commit-id url");
 		return 1;
 	}
 	commit_id = argv[arg];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -401,6 +401,37 @@ void * unpack_sha1_file(void *map, unsig
 	return unpack_sha1_rest(&stream, hdr, *size);
 }
 
+int sha1_delta_base(const unsigned char *sha1, unsigned char *base_sha1)
+{
+	int ret;
+	unsigned long mapsize, size;
+	void *map;
+	z_stream stream;
+	char hdr[64], type[20];
+	void *delta_data_head;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return -1;
+	ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+	if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
+		ret = -1;
+		goto out;
+	}
+	if (strcmp(type, "delta")) {
+		ret = 0;
+		goto out;
+	}
+
+	delta_data_head = hdr + strlen(hdr) + 1;
+	ret = 1;
+	memcpy(base_sha1, delta_data_head, 20);
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return ret;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 13%]

* [PATCH 2/2] Find size of SHA1 object without inflating everything.
    2005-06-02 22:19 13%             ` [PATCH 1/2] " Junio C Hamano
@ 2005-06-02 22:20 14%             ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-02 22:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Nicolas Pitre, git

This adds sha1_file_size() helper function and uses it in the
rename/copy similarity estimator.  The helper function handles
deltified object as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** Thanks and credits goes to Nico for suggesting not to
*** use unpack_sha1_rest().

 cache.h     |    1 +
 diff.c      |   11 ++++++-----
 sha1_file.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -154,6 +154,7 @@ extern void * map_sha1_file(const unsign
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
 extern int sha1_delta_base(const unsigned char *, unsigned char *);
+extern int sha1_file_size(const unsigned char *, unsigned long *);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -333,7 +333,6 @@ int diff_populate_filespec(struct diff_f
 		close(fd);
 	}
 	else {
-		/* We cannot do size only for SHA1 blobs */
 		char type[20];
 		struct sha1_size_cache *e;
 
@@ -343,11 +342,13 @@ int diff_populate_filespec(struct diff_f
 				s->size = e->size;
 				return 0;
 			}
+			if (!sha1_file_size(s->sha1, &s->size))
+				locate_size_cache(s->sha1, s->size);
+		}
+		else {
+			s->data = read_sha1_file(s->sha1, type, &s->size);
+			s->should_free = 1;
 		}
-		s->data = read_sha1_file(s->sha1, type, &s->size);
-		s->should_free = 1;
-		if (s->data && size_only)
-			locate_size_cache(s->sha1, s->size);
 	}
 	return 0;
 }
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -432,6 +432,66 @@ int sha1_delta_base(const unsigned char 
 	return ret;
 }
 
+int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
+{
+	int ret, status;
+	unsigned long mapsize, size;
+	void *map;
+	z_stream stream;
+	char hdr[64], type[20];
+	const unsigned char *data;
+	unsigned char cmd;
+	int i;
+
+	map = map_sha1_file(sha1, &mapsize);
+	if (!map)
+		return -1;
+	ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+	status = -1;
+	if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0)
+		goto out;
+	if (strcmp(type, "delta")) {
+		*sizep = size;
+		status = 0;
+		goto out;
+	}
+
+	/* We are dealing with a delta object.  Inflated, the first
+	 * 20 bytes hold the base object SHA1, and delta data follows
+	 * immediately after it.
+	 *
+	 * The initial part of the delta starts at delta_data_head +
+	 * 20.  Borrow code from patch-delta to read the result size.
+	 */
+	data = hdr + strlen(hdr) + 1 + 20;
+
+	/* Skip over the source size; we are not interested in
+	 * it and we cannot verify it because we do not want
+	 * to read the base object.
+	 */
+	cmd = *data++;
+	while (cmd) {
+		if (cmd & 1)
+			data++;
+		cmd >>= 1;
+	}
+	/* Read the result size */
+	size = i = 0;
+	cmd = *data++;
+	while (cmd) {
+		if (cmd & 1)
+			size |= *data++ << i;
+		i += 8;
+		cmd >>= 1;
+	}
+	*sizep = size;
+	status = 0;
+ out:
+	inflateEnd(&stream);
+	munmap(map, mapsize);
+	return status;
+}
+
 void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 {
 	unsigned long mapsize;
------------


^ permalink raw reply	[relevance 14%]

* [PATCH] Anal retentive 'const unsigned char *sha1'
@ 2005-06-03 15:05 17% Jason McMullan
  0 siblings, 0 replies; 200+ results
From: Jason McMullan @ 2005-06-03 15:05 UTC (permalink / raw)
  To: git

Anal Retentive: make 'sha1' parameters const where possible

Signed-off-by: Jason McMullan <jason.mcmullan@timesys.com>

diff --git a/blob.c b/blob.c
--- a/blob.c
+++ b/blob.c
@@ -4,7 +4,7 @@
 
 const char *blob_type = "blob";
 
-struct blob *lookup_blob(unsigned char *sha1)
+struct blob *lookup_blob(const unsigned char *sha1)
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
diff --git a/blob.h b/blob.h
--- a/blob.h
+++ b/blob.h
@@ -9,7 +9,7 @@ struct blob {
 	struct object object;
 };
 
-struct blob *lookup_blob(unsigned char *sha1);
+struct blob *lookup_blob(const unsigned char *sha1);
 
 int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
 
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -157,7 +157,7 @@ extern void * unpack_sha1_file(void *map
 extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
 extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 
-extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
+extern int check_sha1_signature(const 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);
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -4,7 +4,7 @@
 
 const char *commit_type = "commit";
 
-static struct commit *check_commit(struct object *obj, unsigned char *sha1)
+static struct commit *check_commit(struct object *obj, const unsigned char *sha1)
 {
 	if (obj->type != commit_type) {
 		error("Object %s is a %s, not a commit", 
@@ -14,7 +14,7 @@ static struct commit *check_commit(struc
 	return (struct commit *) obj;
 }
 
-struct commit *lookup_commit_reference(unsigned char *sha1)
+struct commit *lookup_commit_reference(const unsigned char *sha1)
 {
 	struct object *obj = parse_object(sha1);
 
@@ -25,7 +25,7 @@ struct commit *lookup_commit_reference(u
 	return check_commit(obj, sha1);
 }
 
-struct commit *lookup_commit(unsigned char *sha1)
+struct commit *lookup_commit(const unsigned char *sha1)
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -19,8 +19,8 @@ struct commit {
 
 extern const char *commit_type;
 
-struct commit *lookup_commit(unsigned char *sha1);
-struct commit *lookup_commit_reference(unsigned char *sha1);
+struct commit *lookup_commit(const unsigned char *sha1);
+struct commit *lookup_commit_reference(const unsigned char *sha1);
 
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
 
diff --git a/delta.c b/delta.c
--- a/delta.c
+++ b/delta.c
@@ -17,7 +17,7 @@ struct delta {
 	} u;
 };
 
-struct delta *lookup_delta(unsigned char *sha1)
+struct delta *lookup_delta(const unsigned char *sha1)
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
diff --git a/delta.h b/delta.h
--- a/delta.h
+++ b/delta.h
@@ -12,7 +12,7 @@ extern void *patch_delta(void *src_buf, 
 /* handling of delta objects */
 struct delta;
 struct object_list;
-extern struct delta *lookup_delta(unsigned char *sha1);
+extern struct delta *lookup_delta(const unsigned char *sha1);
 extern int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size);
 extern int parse_delta(struct delta *item, unsigned char sha1);
 extern int process_deltas(void *src, unsigned long src_size,
diff --git a/object.c b/object.c
--- a/object.c
+++ b/object.c
@@ -10,7 +10,7 @@ struct object **objs;
 int nr_objs;
 static int obj_allocs;
 
-static int find_object(unsigned char *sha1)
+static int find_object(const unsigned char *sha1)
 {
 	int first = 0, last = nr_objs;
 
@@ -31,7 +31,7 @@ static int find_object(unsigned char *sh
         return -first-1;
 }
 
-struct object *lookup_object(unsigned char *sha1)
+struct object *lookup_object(const unsigned char *sha1)
 {
 	int pos = find_object(sha1);
 	if (pos >= 0)
@@ -39,7 +39,7 @@ struct object *lookup_object(unsigned ch
 	return NULL;
 }
 
-void created_object(unsigned char *sha1, struct object *obj)
+void created_object(const unsigned char *sha1, struct object *obj)
 {
 	int pos = find_object(sha1);
 
@@ -98,7 +98,7 @@ void mark_reachable(struct object *obj, 
 	}
 }
 
-struct object *parse_object(unsigned char *sha1)
+struct object *parse_object(const unsigned char *sha1)
 {
 	unsigned long mapsize;
 	void *map = map_sha1_file(sha1, &mapsize);
diff --git a/object.h b/object.h
--- a/object.h
+++ b/object.h
@@ -20,12 +20,12 @@ struct object {
 extern int nr_objs;
 extern struct object **objs;
 
-struct object *lookup_object(unsigned char *sha1);
+struct object *lookup_object(const unsigned char *sha1);
 
-void created_object(unsigned char *sha1, struct object *obj);
+void created_object(const unsigned char *sha1, struct object *obj);
 
 /** Returns the object, having parsed it to find out what it is. **/
-struct object *parse_object(unsigned char *sha1);
+struct object *parse_object(const unsigned char *sha1);
 
 void add_ref(struct object *refer, struct object *target);
 
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -257,7 +257,7 @@ static char *find_sha1_file(const unsign
 	return NULL;
 }
 
-int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
+int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
 {
 	char header[100];
 	unsigned char real_sha1[20];
diff --git a/tag.c b/tag.c
--- a/tag.c
+++ b/tag.c
@@ -3,7 +3,7 @@
 
 const char *tag_type = "tag";
 
-struct tag *lookup_tag(unsigned char *sha1)
+struct tag *lookup_tag(const unsigned char *sha1)
 {
         struct object *obj = lookup_object(sha1);
         if (!obj) {
diff --git a/tag.h b/tag.h
--- a/tag.h
+++ b/tag.h
@@ -12,7 +12,7 @@ struct tag {
 	char *signature; /* not actually implemented */
 };
 
-extern struct tag *lookup_tag(unsigned char *sha1);
+extern struct tag *lookup_tag(const unsigned char *sha1);
 extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);
 extern int parse_tag(struct tag *item);
 
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -73,7 +73,7 @@ int read_tree(void *buffer, unsigned lon
 	return read_tree_recursive(buffer, size, "", 0, stage);
 }
 
-struct tree *lookup_tree(unsigned char *sha1)
+struct tree *lookup_tree(const unsigned char *sha1)
 {
 	struct object *obj = lookup_object(sha1);
 	if (!obj) {
diff --git a/tree.h b/tree.h
--- a/tree.h
+++ b/tree.h
@@ -24,7 +24,7 @@ struct tree {
 	struct tree_entry_list *entries;
 };
 
-struct tree *lookup_tree(unsigned char *sha1);
+struct tree *lookup_tree(const unsigned char *sha1);
 
 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
 
======== end ========

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation

^ permalink raw reply	[relevance 17%]

* [PATCH] Expose more sha1_file.c interfaces
@ 2005-06-03 15:08 15% Jason McMullan
  0 siblings, 0 replies; 200+ results
From: Jason McMullan @ 2005-06-03 15:08 UTC (permalink / raw)
  To: git

Expose more SHA1 file interfaces:

/* Unpack the rest of a SHA1 file, after using unpack_sha1_header()
 */
void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size);

/* Copy SHA1 object file between FDs, and verify that the SHA1 is as
 * expected. Useful for pulling from a socket into a temporary file
 * before you run object reference dependency checks. (Hint Hint people
 * maintaining pull.c!)
 */
int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int fd_local);

Signed-off-by: Jason McMullan <jason.mcmullan@timesys.com>

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
@@ -162,6 +163,7 @@ extern int check_sha1_signature(const un
 /* Read a tree into the cache */
 extern int read_tree(void *buffer, unsigned long size, int stage);
 
+extern int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int fd_local);
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
 
 extern int has_sha1_file(const unsigned char *sha1);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -579,23 +579,15 @@ int write_sha1_file(void *buf, unsigned 
 	return 0;
 }
 
-int write_sha1_from_fd(const unsigned char *sha1, int fd)
+int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int local)
 {
-	char *filename = sha1_file_name(sha1);
-
-	int local;
 	z_stream stream;
 	unsigned char real_sha1[20];
 	unsigned char buf[4096];
 	unsigned char discard[4096];
-	int ret;
+	int ret, compressed_size=0;
 	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);
@@ -606,13 +598,12 @@ int write_sha1_from_fd(const unsigned ch
 		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;
 		}
+		compressed_size += size;
 		write(local, buf, size);
 		stream.avail_in = size;
 		stream.next_in = buf;
@@ -627,18 +618,35 @@ int write_sha1_from_fd(const unsigned ch
 	} 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;
+	return compressed_size;
+}
+
+int write_sha1_from_fd(const unsigned char *sha1, int fd)
+{
+	char *filename = sha1_file_name(sha1);
+
+	int local;
+	int ret;
+
+	local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+
+	if (local < 0)
+		return error("Couldn't open %s\n", filename);
+
+	ret = write_sha1_from_fd_to_fd(sha1, fd, local);
+	close(local);
+	if (ret < 0)
+		unlink(filename);
+
+	return ret;
 }
 
 int has_sha1_file(const unsigned char *sha1)
======== end ========

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation

^ permalink raw reply	[relevance 15%]

* [PATCH 1/4] Operations on refs
  @ 2005-06-06 20:31 18% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-06-06 20:31 UTC (permalink / raw)
  To: Linus Torvalds, Petr Baudis, Junio C Hamano; +Cc: git

This patch adds code to read a hash out of a specified file under
{GIT_DIR}/refs/, and to write such files atomically and optionally with an
compare and lock.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

Index: Makefile
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/Makefile  (mode:100644 sha1:a5e7552e10bf50888814d43b1ba1a7276d130ca6)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/Makefile  (mode:100644 sha1:c6e2eae2e68a47cdb88d2b1b7fec2c4cc230d506)
@@ -40,7 +40,7 @@
 	$(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 delta.o date.o index.o diff-delta.o patch-delta.o
+	 tag.o delta.o date.o index.o diff-delta.o patch-delta.o refs.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h
 
Index: cache.h
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/cache.h  (mode:100644 sha1:481f7c787040aadbbea877adbb3b9a4fd5f9b9d0)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/cache.h  (mode:100644 sha1:d2dbb0088b2a540972cd3c896d76b6c8dc1844ab)
@@ -110,6 +110,7 @@
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 
 extern char *get_object_directory(void);
+extern char *get_refs_directory(void);
 extern char *get_index_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
Index: refs.c
===================================================================
--- /dev/null  (tree:2dde8ae2d3300fb95e35facac622b9b54990624e)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/refs.c  (mode:100644 sha1:9973d1fc21e9d14f4cf1d30cb59f55cdfd7fc1e7)
@@ -0,0 +1,173 @@
+#include "refs.h"
+#include "cache.h"
+
+#include <errno.h>
+
+static char *ref_file_name(const char *ref)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int reflen = strlen(ref);
+	char *ret = xmalloc(baselen + 2 + reflen);
+	sprintf(ret, "%s/%s", base, ref);
+	return ret;
+}
+
+static char *ref_lock_file_name(const char *ref)
+{
+	char *base = get_refs_directory();
+	int baselen = strlen(base);
+	int reflen = strlen(ref);
+	char *ret = xmalloc(baselen + 7 + reflen);
+	sprintf(ret, "%s/%s.lock", base, ref);
+	return ret;
+}
+
+static int read_ref_file(const 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_ref_sha1(const char *ref, unsigned char *sha1)
+{
+	char *filename;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	retval = read_ref_file(filename, sha1);
+	free(filename);
+	return retval;
+}
+
+static int lock_ref_file(const char *filename, const char *lock_filename,
+			 const unsigned char *old_sha1)
+{
+	int fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	unsigned char current_sha1[20];
+	int retval;
+	if (fd < 0) {
+		return error("Couldn't open lock file for %s: %s",
+			     filename, strerror(errno));
+	}
+	retval = read_ref_file(filename, current_sha1);
+	if (old_sha1) {
+		if (retval) {
+			close(fd);
+			unlink(lock_filename);
+			return error("Could not read the current value of %s",
+				     filename);
+		}
+		if (memcmp(current_sha1, old_sha1, 20)) {
+			close(fd);
+			unlink(lock_filename);
+			error("The current value of %s is %s",
+			      filename, sha1_to_hex(current_sha1));
+			return error("Expected %s",
+				     sha1_to_hex(old_sha1));
+		}
+	} else {
+		if (!retval) {
+			close(fd);
+			unlink(lock_filename);
+			return error("Unexpectedly found a value of %s for %s",
+				     sha1_to_hex(current_sha1), filename);
+		}
+	}
+	return fd;
+}
+
+int lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	retval = lock_ref_file(filename, lock_filename, old_sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
+
+static int write_ref_file(const char *filename,
+			  const char *lock_filename, int fd,
+			  const unsigned char *sha1)
+{
+	char *hex = sha1_to_hex(sha1);
+	char term = '\n';
+	if (write(fd, hex, 40) < 40 ||
+	    write(fd, &term, 1) < 1) {
+		error("Couldn't write %s\n", filename);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	rename(lock_filename, filename);
+	return 0;
+}
+
+int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int retval;
+	if (fd < 0)
+		return -1;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	retval = write_ref_file(filename, lock_filename, fd, sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
+
+int check_ref_format(const char *ref)
+{
+	char *middle;
+	if (ref[0] == '.' || ref[0] == '/')
+		return -1;
+	middle = strchr(ref, '/');
+	if (!middle || !middle[1])
+		return -1;
+	if (strchr(middle + 1, '/'))
+		return -1;
+	return 0;
+}
+
+int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
+{
+	char *filename;
+	char *lock_filename;
+	int fd;
+	int retval;
+	if (check_ref_format(ref))
+		return -1;
+	filename = ref_file_name(ref);
+	lock_filename = ref_lock_file_name(ref);
+	fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		error("Writing %s", lock_filename);
+		perror("Open");
+	}
+	retval = write_ref_file(filename, lock_filename, fd, sha1);
+	free(filename);
+	free(lock_filename);
+	return retval;
+}
Index: refs.h
===================================================================
--- /dev/null  (tree:2dde8ae2d3300fb95e35facac622b9b54990624e)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/refs.h  (mode:100644 sha1:60cf48086f61c9206a343425ba9fdae3dce62937)
@@ -0,0 +1,21 @@
+#ifndef REFS_H
+#define REFS_H
+
+/** Reads the refs file specified into sha1 **/
+extern int get_ref_sha1(const char *ref, unsigned char *sha1);
+
+/** Locks ref and returns the fd to give to write_ref_sha1() if the ref
+ * has the given value currently; otherwise, returns -1.
+ **/
+extern int lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
+
+/** Writes sha1 into the refs file specified, locked with the given fd. **/
+extern int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1);
+
+/** Writes sha1 into the refs file specified. **/
+extern int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1);
+
+/** Returns 0 if target has the right format for a ref. **/
+extern int check_ref_format(const char *target);
+
+#endif /* REFS_H */
Index: sha1_file.c
===================================================================
--- 2dde8ae2d3300fb95e35facac622b9b54990624e/sha1_file.c  (mode:100644 sha1:a2ba4c81dba1b55b119d9ec3c42a7e4ce4ca1df5)
+++ 9138b84eb683fc23a285445f7d7fc5a836ba01cb/sha1_file.c  (mode:100644 sha1:7cfd43c51ba20ee85fe6056c67bbc88cc90dad81)
@@ -58,7 +58,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);
@@ -69,6 +69,8 @@
 		git_object_dir = xmalloc(strlen(git_dir) + 9);
 		sprintf(git_object_dir, "%s/objects", git_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);
@@ -83,6 +85,13 @@
 	return git_object_dir;
 }
 
+char *get_refs_directory(void)
+{
+	if (!git_refs_dir)
+		setup_git_env();
+	return git_refs_dir;
+}
+
 char *get_index_file(void)
 {
 	if (!git_index_file)


^ permalink raw reply	[relevance 18%]

* [PATCH 2/2] Fix oversimplified optimization for add_cache_entry().
  @ 2005-06-24 23:40 13% ` Junio C Hamano
    0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2005-06-24 23:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

An earlier change to optimize directory-file conflict check
broke what "read-tree --emu23" expects.  Introduce an explicit
flag to tell add_cache_entry() not to check for conflicts and
use it when reading an existing tree into an empty stage ---
by definition this case can never introduce such conflicts.

Resurrect the unoptimized directory-file conflict check code for
now as well.  The new one did not handle higher stages properly.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h                           |    1 
 read-cache.c                      |  177 +++++++++++++++++++------------------
 t/t1005-read-tree-m-2way-emu23.sh |    6 +
 tree.c                            |    2 
 4 files changed, 95 insertions(+), 91 deletions(-)

cb13405368b0132ec3b3edcda22d32d89e9c1f85
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,7 @@ extern int write_cache(int newfd, struct
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DF_CHECK 4	/* Ok to skip directory/file conflict checks */
 extern int add_cache_entry(struct cache_entry *ce, int option);
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(char *path);
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -171,83 +171,6 @@ int ce_same_name(struct cache_entry *a, 
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
-/*
- * Do we have another file that has the beginning components being a
- * proper superset of the name we're trying to add?
- */
-static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replace)
-{
-	int retval = 0;
-	int len = ce_namelen(ce);
-	const char *name = ce->name;
-
-	while (pos < active_nr) {
-		struct cache_entry *p = active_cache[pos++];
-
-		if (len >= ce_namelen(p))
-			break;
-		if (memcmp(name, p->name, len))
-			break;
-		if (p->name[len] != '/')
-			continue;
-		retval = -1;
-		if (!ok_to_replace)
-			break;
-		remove_cache_entry_at(--pos);
-	}
-	return retval;
-}
-
-/*
- * Do we have another file with a pathname that is a proper
- * subset of the name we're trying to add?
- */
-static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
-{
-	int retval = 0;
-	const char *name = ce->name;
-	const char *slash = name + ce_namelen(ce);
-
-	for (;;) {
-		int len;
-
-		for (;;) {
-			if (*--slash == '/')
-				break;
-			if (slash <= ce->name)
-				return retval;
-		}
-		len = slash - name;
-
-		pos = cache_name_pos(name, len);
-		if (pos >= 0) {
-			retval = -1;
-			if (ok_to_replace)
-				break;
-			remove_cache_entry_at(pos);
-			continue;
-		}
-
-		/*
-		 * Trivial optimization: if we find an entry that
-		 * already matches the sub-directory, then we know
-		 * we're ok, and we can exit
-		 */
-		pos = -pos-1;
-		if (pos < active_nr) {
-			struct cache_entry *p = active_cache[pos];
-			if (ce_namelen(p) <= len)
-				continue;
-			if (p->name[len] != '/')
-				continue;
-			if (memcmp(p->name, name, len))
-				continue;
-			break;
-		}
-	}
-	return retval;
-}
-
 /* We may be in a situation where we already have path/file and path
  * is being added, or we already have path and path/file is being
  * added.  Either one would result in a nonsense tree that has path
@@ -257,19 +180,98 @@ static int has_dir_name(const struct cac
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
  */
-static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
+static int check_file_directory_conflict(const struct cache_entry *ce,
+					 int ok_to_replace)
 {
+	int pos, replaced = 0;
+	const char *path = ce->name;
+	int namelen = strlen(path);
+	int stage = ce_stage(ce);
+	char *pathbuf = xmalloc(namelen + 1);
+	char *cp;
+
+	memcpy(pathbuf, path, namelen + 1);
+
 	/*
-	 * We check if the path is a sub-path of a subsequent pathname
-	 * first, since removing those will not change the position
-	 * in the array
+	 * We are inserting path/file.  Do they have path registered at
+	 * the same stage?  We need to do this for all the levels of our
+	 * subpath.
 	 */
-	int retval = has_file_name(ce, pos, ok_to_replace);
-	/*
-	 * Then check if the path might have a clashing sub-directory
-	 * before it.
+	cp = pathbuf;
+	while (1) {
+		char *ep = strchr(cp, '/');
+		int len;
+		if (!ep)
+			break;
+		*ep = 0;    /* first cut it at slash */
+		len = ep - pathbuf;
+		pos = cache_name_pos(pathbuf,
+				     ntohs(create_ce_flags(len, stage)));
+		if (0 <= pos) {
+			/* Our leading path component is registered as a file,
+			 * and we are trying to make it a directory.  This is
+			 * bad.
+			 */
+			if (!ok_to_replace) {
+				free(pathbuf);
+				return -1;
+			}
+			fprintf(stderr, "removing file '%s' to replace it with a directory to create '%s'.\n", pathbuf, path);
+			remove_cache_entry_at(pos);
+			replaced = 1;
+		}
+		*ep = '/';  /* then restore it and go downwards */
+		cp = ep + 1;
+	}
+	free(pathbuf);
+
+	/* Do we have an entry in the cache that makes our path a prefix
+	 * of it?  That is, are we creating a file where they already expect
+	 * a directory there?
+	 */
+	pos = cache_name_pos(path,
+			     ntohs(create_ce_flags(namelen, stage)));
+
+	/* (0 <= pos) cannot happen because add_cache_entry()
+	 * should have taken care of that case.
+	 */
+	pos = -pos-1;
+
+	/* pos would point at an existing entry that would come immediately
+	 * after our path.  It could be the same as our path in higher stage,
+	 * or different path but in a lower stage.
+	 *
+	 * E.g. when we are inserting path at stage 2,
+	 *
+	 *        1 path
+	 * pos->  3 path
+	 *        2 path/file1
+	 *        3 path/file1
+	 *        2 path/file2
+	 *        2 patho
+	 *
+	 * We need to examine pos, ignore it because it is at different
+	 * stage, examine next to find the path/file at stage 2, and
+	 * complain.  We need to do this until we are not the leading
+	 * path of an existing entry anymore.
 	 */
-	return retval + has_dir_name(ce, pos, ok_to_replace);
+
+	while (pos < active_nr) {
+		struct cache_entry *other = active_cache[pos];
+		if (strncmp(other->name, path, namelen))
+			break; /* it is not our "subdirectory" anymore */
+		if ((ce_stage(other) == stage) &&
+		    other->name[namelen] == '/') {
+			if (!ok_to_replace)
+				return -1;
+			fprintf(stderr, "removing file '%s' under '%s' to be replaced with a file\n", other->name, path);
+			remove_cache_entry_at(pos);
+			replaced = 1;
+			continue; /* cycle without updating pos */
+		}
+		pos++;
+	}
+	return replaced;
 }
 
 int add_cache_entry(struct cache_entry *ce, int option)
@@ -277,6 +279,7 @@ int add_cache_entry(struct cache_entry *
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
+	int skip_df_check = option & ADD_CACHE_SKIP_DF_CHECK;
 	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it */
@@ -302,7 +305,7 @@ int add_cache_entry(struct cache_entry *
 	if (!ok_to_add)
 		return -1;
 
-	if (!ce_stage(ce) && check_file_directory_conflict(ce, pos, ok_to_replace)) {
+	if (!skip_df_check && check_file_directory_conflict(ce, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
 		pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -389,7 +389,7 @@ test_expect_success \
      :'
 
 # Emu23 can grok I having more than H.  Make sure we did not
-# botch the conflict tests (Linus code botches this test).
+# botch the conflict tests (fixed).
 test_expect_success \
     'DF vs DF/DF case test (#2).' \
     'rm -f .git/index &&
@@ -400,8 +400,8 @@ test_expect_success \
      # This should fail because I and H have a conflict
      # at DF.
      if git-read-tree --emu23 $treeDF $treeDFDF
-     then true  ;# should be false
-     else false ;# should be true
+     then false
+     else true
      fi'
 
 test_done
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -18,7 +18,7 @@ static int read_one_entry(unsigned char 
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DF_CHECK);
 }
 
 static int read_tree_recursive(void *buffer, unsigned long size,
------------


^ permalink raw reply	[relevance 13%]

* [PATCH 7/9] Fix oversimplified optimization for add_cache_entry().
  @ 2005-06-25  9:25 15%         ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-25  9:25 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

An earlier change to optimize directory-file conflict check
broke what "read-tree --emu23" expects.  This is fixed by this
commit.

(1) Introduces an explicit flag to tell add_cache_entry() not to
    check for conflicts and use it when reading an existing tree
    into an empty stage --- by definition this case can never
    introduce such conflicts.

(2) Makes read-cache.c:has_file_name() and read-cache.c:has_dir_name()
    aware of the cache stages, and flag conflict only with paths
    in the same stage.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h                           |    1 +
 read-cache.c                      |   32 +++++++++++++++++++++-----------
 t/t1005-read-tree-m-2way-emu23.sh |   25 ++++++++++++++++++++-----
 tree.c                            |    2 +-
 4 files changed, 43 insertions(+), 17 deletions(-)

904dbb145f2f42227ea5b94752146ef8d4c2b153
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,7 @@ extern int write_cache(int newfd, struct
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
+#define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
 extern int add_cache_entry(struct cache_entry *ce, int option);
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(char *path);
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -179,6 +179,7 @@ static int has_file_name(const struct ca
 {
 	int retval = 0;
 	int len = ce_namelen(ce);
+	int stage = ce_stage(ce);
 	const char *name = ce->name;
 
 	while (pos < active_nr) {
@@ -188,6 +189,8 @@ static int has_file_name(const struct ca
 			break;
 		if (memcmp(name, p->name, len))
 			break;
+		if (ce_stage(p) != stage)
+			continue;
 		if (p->name[len] != '/')
 			continue;
 		retval = -1;
@@ -205,6 +208,7 @@ static int has_file_name(const struct ca
 static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
 {
 	int retval = 0;
+	int stage = ce_stage(ce);
 	const char *name = ce->name;
 	const char *slash = name + ce_namelen(ce);
 
@@ -219,7 +223,7 @@ static int has_dir_name(const struct cac
 		}
 		len = slash - name;
 
-		pos = cache_name_pos(name, len);
+		pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
 		if (pos >= 0) {
 			retval = -1;
 			if (ok_to_replace)
@@ -231,18 +235,23 @@ static int has_dir_name(const struct cac
 		/*
 		 * Trivial optimization: if we find an entry that
 		 * already matches the sub-directory, then we know
-		 * we're ok, and we can exit
+		 * we're ok, and we can exit.
 		 */
 		pos = -pos-1;
-		if (pos < active_nr) {
+		while (pos < active_nr) {
 			struct cache_entry *p = active_cache[pos];
-			if (ce_namelen(p) <= len)
-				continue;
-			if (p->name[len] != '/')
-				continue;
-			if (memcmp(p->name, name, len))
-				continue;
-			break;
+			if ((ce_namelen(p) <= len) ||
+			    (p->name[len] != '/') ||
+			    memcmp(p->name, name, len))
+				break; /* not our subdirectory */
+			if (ce_stage(p) == stage)
+				/* p is at the same stage as our entry, and
+				 * is a subdirectory of what we are looking
+				 * at, so we cannot have conflicts at our
+				 * level or anything shorter.
+				 */
+				return retval;
+			pos++;
 		}
 	}
 	return retval;
@@ -277,6 +286,7 @@ int add_cache_entry(struct cache_entry *
 	int pos;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
+	int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
 	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it */
@@ -302,7 +312,7 @@ int add_cache_entry(struct cache_entry *
 	if (!ok_to_add)
 		return -1;
 
-	if (!ce_stage(ce) && check_file_directory_conflict(ce, pos, ok_to_replace)) {
+	if (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
 		pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -366,6 +366,7 @@ test_expect_success \
      treeDF=`git-write-tree` &&
      echo treeDF $treeDF &&
      git-ls-tree $treeDF &&
+     git-ls-files --stage >DF.out
 
      rm -f DF &&
      mkdir DF &&
@@ -377,7 +378,7 @@ test_expect_success \
      git-ls-files --stage >DFDF.out'
 
 test_expect_success \
-    'DF vs DF/DF case test.' \
+    'DF vs DF/DF case test (#1)' \
     'rm -f .git/index &&
      rm -fr DF &&
      echo DF >DF &&
@@ -388,10 +389,24 @@ test_expect_success \
      check_cache_at DF/DF clean && # different from pure 2-way
      :'
 
+# The other way around
+test_expect_success \
+    'DF vs DF/DF case test (#2)' \
+    'rm -f .git/index &&
+     rm -fr DF &&
+     mkdir DF &&
+     echo DF/DF >DF/DF &&
+     git-update-cache --add DF/DF &&
+     read_tree_twoway $treeDFDF $treeDF &&
+     git-ls-files --stage >DFDFcheck.out &&
+     diff -u DF.out DFDFcheck.out &&
+     check_cache_at DF clean && # different from pure 2-way
+     :'
+
 # Emu23 can grok I having more than H.  Make sure we did not
-# botch the conflict tests (Linus code botches this test).
+# botch the conflict tests (fixed).
 test_expect_success \
-    'DF vs DF/DF case test (#2).' \
+    'DF vs DF/DF case test (#3).' \
     'rm -f .git/index &&
      rm -fr DF &&
      mkdir DF &&
@@ -400,8 +415,8 @@ test_expect_success \
      # This should fail because I and H have a conflict
      # at DF.
      if git-read-tree --emu23 $treeDF $treeDFDF
-     then true  ;# should be false
-     else false ;# should be true
+     then false
+     else true
      fi'
 
 test_done
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -18,7 +18,7 @@ static int read_one_entry(unsigned char 
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	memcpy(ce->sha1, sha1, 20);
-	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+	return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
 static int read_tree_recursive(void *buffer, unsigned long size,
------------


^ permalink raw reply	[relevance 15%]

* [PATCH] Skip writing out sha1 files for objects in packed git.
  @ 2005-06-28  2:03 17%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-28  2:03 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Now, there's still a misfeature there, which is that when you
create a new object, it doesn't check whether that object
already exists in the pack-file, so you'll end up with a few
recent objects that you really don't need (notably tree
objects), and this patch fixes it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 apply.c          |    2 +-
 cache.h          |    2 +-
 commit-tree.c    |    2 +-
 convert-cache.c  |    6 +++---
 mktag.c          |    2 +-
 sha1_file.c      |   44 ++++++++++++++++++++++++++++++--------------
 unpack-objects.c |    4 ++--
 update-cache.c   |    2 +-
 write-tree.c     |    2 +-
 9 files changed, 41 insertions(+), 25 deletions(-)

f4f76b275cdabc038bcb4f3c7ca0d443638df88d
diff --git a/apply.c b/apply.c
--- a/apply.c
+++ b/apply.c
@@ -1221,7 +1221,7 @@ static void add_index_file(const char *p
 	if (lstat(path, &st) < 0)
 		die("unable to stat newly created file %s", path);
 	fill_stat_cache_info(ce, &st);
-	if (write_sha1_file(buf, size, "blob", ce->sha1) < 0)
+	if (write_sha1_file(buf, size, "blob", ce->sha1, 0) < 0)
 		die("unable to create backing store for newly created file %s", path);
 	if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
 		die("unable to add cache entry for %s", path);
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -165,7 +165,7 @@ extern int parse_sha1_header(char *hdr, 
 extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
 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(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1, int do_expand);
 
 extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -191,7 +191,7 @@ int main(int argc, char **argv)
 	while (fgets(comment, sizeof(comment), stdin) != NULL)
 		add_buffer(&buffer, &size, "%s", comment);
 
-	write_sha1_file(buffer, size, "commit", commit_sha1);
+	write_sha1_file(buffer, size, "commit", commit_sha1, 0);
 	printf("%s\n", sha1_to_hex(commit_sha1));
 	return 0;
 }
diff --git a/convert-cache.c b/convert-cache.c
--- a/convert-cache.c
+++ b/convert-cache.c
@@ -111,7 +111,7 @@ static int write_subdirectory(void *buff
 		buffer += len;
 	}
 
-	write_sha1_file(new, newlen, "tree", result_sha1);
+	write_sha1_file(new, newlen, "tree", result_sha1, 0);
 	free(new);
 	return used;
 }
@@ -251,7 +251,7 @@ static void convert_date(void *buffer, u
 	memcpy(new + newlen, buffer, size);
 	newlen += size;
 
-	write_sha1_file(new, newlen, "commit", result_sha1);
+	write_sha1_file(new, newlen, "commit", result_sha1, 0);
 	free(new);	
 }
 
@@ -286,7 +286,7 @@ static struct entry * convert_entry(unsi
 	memcpy(buffer, data, size);
 	
 	if (!strcmp(type, "blob")) {
-		write_sha1_file(buffer, size, "blob", entry->new_sha1);
+		write_sha1_file(buffer, size, "blob", entry->new_sha1, 0);
 	} else if (!strcmp(type, "tree"))
 		convert_tree(buffer, size, entry->new_sha1);
 	else if (!strcmp(type, "commit"))
diff --git a/mktag.c b/mktag.c
--- a/mktag.c
+++ b/mktag.c
@@ -123,7 +123,7 @@ int main(int argc, char **argv)
 	if (verify_tag(buffer, size) < 0)
 		die("invalid tag signature file");
 
-	if (write_sha1_file(buffer, size, "tag", result_sha1) < 0)
+	if (write_sha1_file(buffer, size, "tag", result_sha1, 0) < 0)
 		die("unable to write tag file");
 	printf("%s\n", sha1_to_hex(result_sha1));
 	return 0;
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -891,31 +891,47 @@ void *read_object_with_reference(const u
 	}
 }
 
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+static char *write_sha1_file_prepare(void *buf,
+				     unsigned long len,
+				     const char *type,
+				     unsigned char *sha1,
+				     unsigned char *hdr,
+				     int *hdrlen)
 {
-	int size;
-	unsigned char *compressed;
-	z_stream stream;
-	unsigned char sha1[20];
 	SHA_CTX c;
-	char *filename;
-	static char tmpfile[PATH_MAX];
-	unsigned char hdr[50];
-	int fd, hdrlen, ret;
 
 	/* Generate the header */
-	hdrlen = sprintf((char *)hdr, "%s %lu", type, len)+1;
+	*hdrlen = sprintf((char *)hdr, "%s %lu", type, len)+1;
 
 	/* Sha1.. */
 	SHA1_Init(&c);
-	SHA1_Update(&c, hdr, hdrlen);
+	SHA1_Update(&c, hdr, *hdrlen);
 	SHA1_Update(&c, buf, len);
 	SHA1_Final(sha1, &c);
 
+	return sha1_file_name(sha1);
+}
+
+int write_sha1_file(void *buf, unsigned long len, const char *type,
+		    unsigned char *returnsha1, int do_expand)
+{
+	int size;
+	unsigned char *compressed;
+	z_stream stream;
+	unsigned char sha1[20];
+	char *filename;
+	static char tmpfile[PATH_MAX];
+	unsigned char hdr[50];
+	int fd, hdrlen, ret;
+
+	/* Normally if we have it in the pack then we do not bother writing
+	 * it out into .git/objects/??/?{38} file.
+	 */
+	filename = write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
 	if (returnsha1)
 		memcpy(returnsha1, sha1, 20);
-
-	filename = sha1_file_name(sha1);
+	if (!do_expand && has_sha1_file(sha1))
+		return 0;
 	fd = open(filename, O_RDONLY);
 	if (fd >= 0) {
 		/*
@@ -1082,7 +1098,7 @@ int index_fd(unsigned char *sha1, int fd
 	if ((int)(long)buf == -1)
 		return -1;
 
-	ret = write_sha1_file(buf, size, "blob", sha1);
+	ret = write_sha1_file(buf, size, "blob", sha1, 0);
 	if (size)
 		munmap(buf, size);
 	return ret;
diff --git a/unpack-objects.c b/unpack-objects.c
--- a/unpack-objects.c
+++ b/unpack-objects.c
@@ -126,7 +126,7 @@ static int unpack_non_delta_entry(struct
 	case 'B': type_s = "blob"; break;
 	default: goto err_finish;
 	}
-	if (write_sha1_file(buffer, size, type_s, sha1) < 0)
+	if (write_sha1_file(buffer, size, type_s, sha1, 1) < 0)
 		die("failed to write %s (%s)",
 		    sha1_to_hex(entry->sha1), type_s);
 	printf("%s %s\n", sha1_to_hex(sha1), type_s);
@@ -223,7 +223,7 @@ static int unpack_delta_entry(struct pac
 		die("failed to apply delta");
 	free(delta_data);
 
-	if (write_sha1_file(result, result_size, type, sha1) < 0)
+	if (write_sha1_file(result, result_size, type, sha1, 1) < 0)
 		die("failed to write %s (%s)",
 		    sha1_to_hex(entry->sha1), type);
 	free(result);
diff --git a/update-cache.c b/update-cache.c
--- a/update-cache.c
+++ b/update-cache.c
@@ -77,7 +77,7 @@ static int add_file_to_cache(char *path)
 			free(target);
 			return -1;
 		}
-		if (write_sha1_file(target, st.st_size, "blob", ce->sha1))
+		if (write_sha1_file(target, st.st_size, "blob", ce->sha1, 0))
 			return -1;
 		free(target);
 		break;
diff --git a/write-tree.c b/write-tree.c
--- a/write-tree.c
+++ b/write-tree.c
@@ -76,7 +76,7 @@ static int write_tree(struct cache_entry
 		nr++;
 	}
 
-	write_sha1_file(buffer, offset, "tree", returnsha1);
+	write_sha1_file(buffer, offset, "tree", returnsha1, 0);
 	free(buffer);
 	return nr;
 }
------------

^ permalink raw reply	[relevance 17%]

* [PATCH] Expose packed_git and alt_odb.
  @ 2005-06-28 21:56 14%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-28 21:56 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

The commands git-fsck-cache and probably git-*-pull needs to
have a way to enumerate objects contained in packed GIT archives
and alternate object pools.  This commit exposes the data
structure used to keep track of them from sha1_file.c, and adds
a couple of accessor interface functions for use by the enhanced
git-fsck-cache command.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h     |   19 +++++++++++++++++++
 sha1_file.c |   43 ++++++++++++++++++++++++-------------------
 2 files changed, 43 insertions(+), 19 deletions(-)

da37711700d11f8c7f44fcb6819c724978c840b7
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -233,4 +233,23 @@ struct checkout {
 
 extern int checkout_entry(struct cache_entry *ce, struct checkout *state);
 
+extern struct alternate_object_database {
+	char *base;
+	char *name;
+} *alt_odb;
+extern void prepare_alt_odb(void);
+
+extern struct packed_git {
+	struct packed_git *next;
+	unsigned long index_size;
+	unsigned long pack_size;
+	unsigned int *index_base;
+	void *pack_base;
+	unsigned int pack_last_used;
+	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
+} *packed_git;
+extern void prepare_packed_git(void);
+extern int num_packed_objects(const struct packed_git *p);
+extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
+
 #endif /* CACHE_H */
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -184,10 +184,7 @@ char *sha1_file_name(const unsigned char
 	return base;
 }
 
-static struct alternate_object_database {
-	char *base;
-	char *name;
-} *alt_odb;
+struct alternate_object_database *alt_odb;
 
 /*
  * Prepare alternate object database registry.
@@ -205,13 +202,15 @@ static struct alternate_object_database 
  * pointed by base fields of the array elements with one xmalloc();
  * the string pool immediately follows the array.
  */
-static void prepare_alt_odb(void)
+void prepare_alt_odb(void)
 {
 	int pass, totlen, i;
 	const char *cp, *last;
 	char *op = NULL;
 	const char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
 
+	if (alt_odb)
+		return;
 	/* The first pass counts how large an area to allocate to
 	 * hold the entire alt_odb structure, including array of
 	 * structs and path buffers for them.  The second pass fills
@@ -258,8 +257,7 @@ static char *find_sha1_file(const unsign
 
 	if (!stat(name, st))
 		return name;
-	if (!alt_odb)
-		prepare_alt_odb();
+	prepare_alt_odb();
 	for (i = 0; (name = alt_odb[i].name) != NULL; i++) {
 		fill_sha1_path(name, sha1);
 		if (!stat(alt_odb[i].base, st))
@@ -271,15 +269,7 @@ static char *find_sha1_file(const unsign
 #define PACK_MAX_SZ (1<<26)
 static int pack_used_ctr;
 static unsigned long pack_mapped;
-static struct packed_git {
-	struct packed_git *next;
-	unsigned long index_size;
-	unsigned long pack_size;
-	unsigned int *index_base;
-	void *pack_base;
-	unsigned int pack_last_used;
-	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
-} *packed_git;
+struct packed_git *packed_git;
 
 struct pack_entry {
 	unsigned int offset;
@@ -430,7 +420,7 @@ static void prepare_packed_git_one(char 
 	}
 }
 
-static void prepare_packed_git(void)
+void prepare_packed_git(void)
 {
 	int i;
 	static int run_once = 0;
@@ -439,8 +429,7 @@ static void prepare_packed_git(void)
 		return;
 
 	prepare_packed_git_one(get_object_directory());
-	if (!alt_odb)
-		prepare_alt_odb();
+	prepare_alt_odb();
 	for (i = 0; alt_odb[i].base != NULL; i++) {
 		alt_odb[i].name[0] = 0;
 		prepare_packed_git_one(alt_odb[i].base);
@@ -750,6 +739,22 @@ static void *unpack_entry(struct pack_en
 	return unpack_non_delta_entry(pack+5, size, left);
 }
 
+int num_packed_objects(const struct packed_git *p)
+{
+	/* See check_packed_git_idx and pack-objects.c */
+	return (p->index_size - 20 - 20 - 4*256) / 24;
+}
+
+int nth_packed_object_sha1(const struct packed_git *p, int n,
+			   unsigned char* sha1)
+{
+	void *index = p->index_base + 256;
+	if (n < 0 || num_packed_objects(p) <= n)
+		return -1;
+	memcpy(sha1, (index + 24 * n + 4), 20);
+	return 0;
+}
+
 static int find_pack_entry_1(const unsigned char *sha1,
 			     struct pack_entry *e, struct packed_git *p)
 {
------------

^ permalink raw reply	[relevance 14%]

* [PATCH] Add git-verify-pack command.
  @ 2005-06-29  9:51 12%                             ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-06-29  9:51 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Given a list of <pack>.idx files, this command validates the
index file and the corresponding .pack file for consistency.

This patch also uses the same validation mechanism in fsck-cache
when the --full flag is used.

During normal operation, sha1_file.c verifies that a given .idx
file matches the .pack file by comparing the SHA1 checksum
stored in .idx file and .pack file as a minimum sanity check.
We may further want to check the pack signature and version when
we map the pack, but that would be a separate patch.

Earlier, errors to map a pack file was not flagged fatal but led
to a random fatal error later.  This version explicitly die()s
when such an error is detected.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** This actually covers two of the items I listed in the "Last
*** mile again" message.  I ended up doing the LRU myself.

*** Linus, what would be the practical/recommended/sane limit
*** for mmap regions we would want to use?  Currently I start
*** throwing away mapped packs when the total size of mapped
*** packs exceeds 64MB.

*** Currently, pack-objects/unpack-objects pair is not
*** documented.  Any takers?

*** Oh, again, Linus, what is your preferred way to get a
*** cover-letter material (like this) for a single patch?  I
*** always do a separate cover letter for multi-patch series
*** with [PATCH 0/N], but do you prefer to get [PATCH 0/1] and
*** [PATCH 1/1] for a single patch, or do you prefer to see
*** commentaries after the three-dash line like this message
*** does?

 Documentation/git-verify-pack.txt |   38 +++++++++++++++++++++
 Documentation/git.txt             |    3 ++
 Makefile                          |    5 ++-
 cache.h                           |    4 ++
 fsck-cache.c                      |    5 +++
 pack.h                            |    2 +
 sha1_file.c                       |   66 ++++++++++++++++++++++++++++---------
 t/t5300-pack-object.sh            |   38 +++++++++++++++++++++
 verify-pack.c                     |   26 +++++++++++++++
 verify_pack.c                     |   62 +++++++++++++++++++++++++++++++++++
 10 files changed, 231 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/git-verify-pack.txt
 create mode 100644 verify-pack.c
 create mode 100644 verify_pack.c

8ac4f374a587c58b3d2ecc44220b6b866f769350
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/git-verify-pack.txt
@@ -0,0 +1,38 @@
+git-verify-pack(1)
+==================
+v0.1, June 2005
+
+NAME
+----
+git-verify-pack - Validate packed GIT archive files.
+
+
+SYNOPSIS
+--------
+'git-verify-pack' <pack>.idx ...
+
+
+DESCRIPTION
+-----------
+Reads given idx file for packed GIT archive created with
+git-pack-objects command and verifies idx file and the
+corresponding pack file.
+
+OPTIONS
+-------
+<pack>.idx ...::
+	The idx files to verify.
+
+
+Author
+------
+Written by Junio C Hamano <junkio@cox.net>
+
+Documentation
+--------------
+Documentation by Junio C Hamano
+
+GIT
+---
+Part of the link:git.html[git] suite
+
diff --git a/Documentation/git.txt b/Documentation/git.txt
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -110,6 +110,9 @@ link:git-tar-tree.html[git-tar-tree]::
 link:git-unpack-file.html[git-unpack-file]::
 	Creates a temporary file with a blob's contents
 
+link:git-verify-pack.html[git-verify-pack]::
+	Validates packed GIT archive files
+
 The interrogate commands may create files - and you can force them to
 touch the working file set - but in general they don't
 
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-helper git-tar-tree git-local-pull git-write-blob \
 	git-get-tar-commit-id git-apply git-stripspace \
 	git-cvs2git git-diff-stages git-rev-parse git-patch-id \
-	git-pack-objects git-unpack-objects
+	git-pack-objects git-unpack-objects git-verify-pack
 
 all: $(PROG)
 
@@ -45,7 +45,7 @@ install: $(PROG) $(SCRIPTS)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o date.o index.o diff-delta.o patch-delta.o entry.o \
-	 epoch.o refs.o csum-file.o
+	 epoch.o refs.o csum-file.o verify_pack.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h pack.h
 
@@ -124,6 +124,7 @@ git-rev-parse: rev-parse.c
 git-patch-id: patch-id.c
 git-pack-objects: pack-objects.c
 git-unpack-objects: unpack-objects.c
+git-verify-pack: verify-pack.c
 
 git-http-pull: LIBS += -lcurl
 git-rev-list: LIBS += -lssl
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -246,9 +246,13 @@ extern struct packed_git {
 	unsigned int *index_base;
 	void *pack_base;
 	unsigned int pack_last_used;
+	unsigned int pack_use_cnt;
 	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
 } *packed_git;
 extern void prepare_packed_git(void);
+extern int use_packed_git(struct packed_git *);
+extern void unuse_packed_git(struct packed_git *);
+extern struct packed_git *add_packed_git(char *, int);
 extern int num_packed_objects(const struct packed_git *p);
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
 
diff --git a/fsck-cache.c b/fsck-cache.c
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -6,6 +6,7 @@
 #include "tree.h"
 #include "blob.h"
 #include "tag.h"
+#include "pack.h"
 
 #define REACHABLE 0x0001
 
@@ -437,6 +438,10 @@ int main(int argc, char **argv)
 			alt_odb[j].name[-1] = '/';
 		}
 		prepare_packed_git();
+		for (p = packed_git; p; p = p->next)
+			/* verify gives error messages itself */
+			verify_pack(p); 
+
 		for (p = packed_git; p; p = p->next) {
 			int num = num_packed_objects(p);
 			for (i = 0; i < num; i++) {
diff --git a/pack.h b/pack.h
--- a/pack.h
+++ b/pack.h
@@ -27,4 +27,6 @@ struct pack_header {
 	unsigned int hdr_entries;
 };
 
+extern int verify_pack(struct packed_git *);
+
 #endif
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -302,7 +302,7 @@ static int check_packed_git_idx(const ch
 	index = idx_map;
 
 	/* check index map */
-	if (idx_size < 4*256 + 20)
+	if (idx_size < 4*256 + 20 + 20)
 		return error("index file too small");
 	nr = 0;
 	for (i = 0; i < 256; i++) {
@@ -327,12 +327,29 @@ static int check_packed_git_idx(const ch
 	return 0;
 }
 
-static void unuse_one_packed_git(void)
+static int unuse_one_packed_git(void)
 {
-	/* NOTYET */
+	struct packed_git *p, *lru = NULL;
+
+	for (p = packed_git; p; p = p->next) {
+		if (p->pack_use_cnt || !p->pack_base)
+			continue;
+		if (!lru || p->pack_last_used < lru->pack_last_used)
+			lru = p;
+	}
+	if (!lru)
+		return 0;
+	munmap(lru->pack_base, lru->pack_size);
+	lru->pack_base = NULL;
+	return 1;
+}
+
+void unuse_packed_git(struct packed_git *p)
+{
+	p->pack_use_cnt--;
 }
 
-static int use_packed_git(struct packed_git *p)
+int use_packed_git(struct packed_git *p)
 {
 	if (!p->pack_base) {
 		int fd;
@@ -340,28 +357,36 @@ static int use_packed_git(struct packed_
 		void *map;
 
 		pack_mapped += p->pack_size;
-		while (PACK_MAX_SZ < pack_mapped)
-			unuse_one_packed_git();
+		while (PACK_MAX_SZ < pack_mapped && unuse_one_packed_git())
+			; /* nothing */
 		fd = open(p->pack_name, O_RDONLY);
 		if (fd < 0)
-			return -1;
+			die("packfile %s cannot be opened", p->pack_name);
 		if (fstat(fd, &st)) {
 			close(fd);
-			return -1;
+			die("packfile %s cannot be opened", p->pack_name);
 		}
 		if (st.st_size != p->pack_size)
-			return -1;
+			die("packfile %s size mismatch.", p->pack_name);
 		map = mmap(NULL, p->pack_size, PROT_READ, MAP_PRIVATE, fd, 0);
 		close(fd);
 		if (map == MAP_FAILED)
-			return -1;
+			die("packfile %s cannot be mapped.", p->pack_name);
 		p->pack_base = map;
+
+		/* Check if the pack file matches with the index file.
+		 * this is cheap.
+		 */
+		if (memcmp((char*)(p->index_base) + p->index_size - 40,
+			   p->pack_base + p->pack_size - 20, 20))
+			die("packfile %s does not match index.", p->pack_name);
 	}
 	p->pack_last_used = pack_used_ctr++;
+	p->pack_use_cnt++;
 	return 0;
 }
 
-static struct packed_git *add_packed_git(char *path, int path_len)
+struct packed_git *add_packed_git(char *path, int path_len)
 {
 	struct stat st;
 	struct packed_git *p;
@@ -388,6 +413,7 @@ static struct packed_git *add_packed_git
 	p->next = NULL;
 	p->pack_base = NULL;
 	p->pack_last_used = 0;
+	p->pack_use_cnt = 0;
 	return p;
 }
 
@@ -671,6 +697,7 @@ static int packed_object_info(struct pac
 	unsigned long offset, size, left;
 	unsigned char *pack;
 	enum object_type kind;
+	int retval;
 
 	if (use_packed_git(p))
 		die("cannot map packed file");
@@ -681,8 +708,9 @@ static int packed_object_info(struct pac
 
 	switch (kind) {
 	case OBJ_DELTA:
-		return packed_delta_info(pack, size, left, type, sizep);
-		break;
+		retval = packed_delta_info(pack, size, left, type, sizep);
+		unuse_packed_git(p);
+		return retval;
 	case OBJ_COMMIT:
 		strcpy(type, "commit");
 		break;
@@ -699,6 +727,7 @@ static int packed_object_info(struct pac
 		die("corrupted pack file");
 	}
 	*sizep = size;
+	unuse_packed_git(p);
 	return 0;
 }
 
@@ -785,6 +814,7 @@ static void *unpack_entry(struct pack_en
 	unsigned long offset, size, left;
 	unsigned char *pack;
 	enum object_type kind;
+	void *retval;
 
 	if (use_packed_git(p))
 		die("cannot map packed file");
@@ -794,7 +824,9 @@ static void *unpack_entry(struct pack_en
 	left = p->pack_size - offset;
 	switch (kind) {
 	case OBJ_DELTA:
-		return unpack_delta_entry(pack, size, left, type, sizep);
+		retval = unpack_delta_entry(pack, size, left, type, sizep);
+		unuse_packed_git(p);
+		return retval;
 	case OBJ_COMMIT:
 		strcpy(type, "commit");
 		break;
@@ -811,12 +843,14 @@ static void *unpack_entry(struct pack_en
 		die("corrupted pack file");
 	}
 	*sizep = size;
-	return unpack_non_delta_entry(pack, size, left);
+	retval = unpack_non_delta_entry(pack, size, left);
+	unuse_packed_git(p);
+	return retval;
 }
 
 int num_packed_objects(const struct packed_git *p)
 {
-	/* See check_packed_git_idx and pack-objects.c */
+	/* See check_packed_git_idx() */
 	return (p->index_size - 20 - 20 - 4*256) / 24;
 }
 
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -127,4 +127,42 @@ test_expect_success \
     } >current &&
     diff expect current'
 
+unset GIT_OBJECT_DIRECTORY
+
+test_expect_success \
+    'verify pack' \
+    'git-verify-pack test-1.idx test-2.idx'
+
+test_expect_success \
+    'corrupt a pack and see if verify catches' \
+    'cp test-1.idx test-3.idx &&
+     cp test-2.pack test-3.pack &&
+     if git-verify-pack test-3.idx
+     then false
+     else :;
+     fi &&
+
+     cp test-1.pack test-3.pack &&
+     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
+     if git-verify-pack test-3.idx
+     then false
+     else :;
+     fi &&
+
+     cp test-1.pack test-3.pack &&
+     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
+     if git-verify-pack test-3.idx
+     then false
+     else :;
+     fi &&
+
+     cp test-1.pack test-3.pack &&
+     dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
+     if git-verify-pack test-3.idx
+     then false
+     else :;
+     fi &&
+
+     :'
+
 test_done
diff --git a/verify-pack.c b/verify-pack.c
new file mode 100644
--- /dev/null
+++ b/verify-pack.c
@@ -0,0 +1,26 @@
+#include "cache.h"
+#include "pack.h"
+
+static int verify_one_pack(char *arg)
+{
+	struct packed_git *g = add_packed_git(arg, strlen(arg));
+	if (!g)
+		return -1;
+	return verify_pack(g);
+}
+
+int main(int ac, char **av)
+{
+	int errs = 0;
+
+	while (1 < ac) {
+		char path[PATH_MAX];
+		strcpy(path, av[1]);
+		if (verify_one_pack(path))
+			errs++;
+		else
+			printf("%s: OK\n", av[1]);
+		ac--; av++;
+	}
+	return !!errs;
+}
diff --git a/verify_pack.c b/verify_pack.c
new file mode 100644
--- /dev/null
+++ b/verify_pack.c
@@ -0,0 +1,62 @@
+#include "cache.h"
+#include "pack.h"
+
+static int verify_packfile(struct packed_git *p)
+{
+	unsigned long index_size = p->index_size;
+	void *index_base = p->index_base;
+	SHA_CTX ctx;
+	unsigned char sha1[20];
+	unsigned long pack_size = p->pack_size;
+	void *pack_base;
+	struct pack_header *hdr;
+	int nr_objects;
+
+	hdr = p->pack_base;
+	if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
+		return error("Packfile signature mismatch", p->pack_name);
+	if (hdr->hdr_version != htonl(PACK_VERSION))
+		return error("Packfile version %d different from ours %d",
+			     ntohl(hdr->hdr_version), PACK_VERSION);
+	nr_objects = ntohl(hdr->hdr_entries);
+	if (num_packed_objects(p) != nr_objects)
+		return error("Packfile claims to have %d objects, "
+			     "while idx size expects %d", nr_objects,
+			     num_packed_objects(p));
+
+	SHA1_Init(&ctx);
+	pack_base = p->pack_base;
+	SHA1_Update(&ctx, pack_base, pack_size - 20);
+	SHA1_Final(sha1, &ctx);
+	if (memcmp(sha1, index_base + index_size - 40, 20))
+		return error("Packfile %s SHA1 mismatch with idx",
+			     p->pack_name);
+	if (memcmp(sha1, pack_base + pack_size - 20, 20))
+		return error("Packfile %s SHA1 mismatch with itself",
+			     p->pack_name);
+	return 0;
+}
+
+
+int verify_pack(struct packed_git *p)
+{
+	unsigned long index_size = p->index_size;
+	void *index_base = p->index_base;
+	SHA_CTX ctx;
+	unsigned char sha1[20];
+	int ret;
+
+	/* Verify SHA1 sum of the index file */
+	SHA1_Init(&ctx);
+	SHA1_Update(&ctx, index_base, index_size - 20);
+	SHA1_Final(sha1, &ctx);
+	if (memcmp(sha1, index_base + index_size - 20, 20))
+		return error("Packfile index for %s SHA1 mismatch",
+			     p->pack_name);
+
+	/* Verify pack file */
+	use_packed_git(p);
+	ret = verify_packfile(p);
+	unuse_packed_git(p);
+	return ret;
+}
------------

^ permalink raw reply	[relevance 12%]

* [PATCH 1/2] verify-pack updates.
@ 2005-07-01  0:15 13% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-01  0:15 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Nico pointed out that having verify_pack.c and verify-pack.c was
confusing.  Rename verify_pack.c to pack-check.c as suggested,
and enhances the verification done quite a bit.

 - Built-in sha1_file unpacking knows that a base object of a
   deltified object _must_ be in the same pack, and takes
   advantage of that fact.

 - Earlier verify-pack command only checked the SHA1 sum for the
   entire pack file and did not look into its contents.  It now
   checks everything idx file claims to have unpacks correctly.

 - It now has a hook to give more detailed information for
   objects contained in the pack under -v flag.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** I used "git format-patch -M20" to generate diff to show this
*** commit as a rename/copy patch.  Let's see if git-apply can
*** still grok it ;-).

 Makefile      |    2 +-
 cache.h       |    9 ++++++++
 fsck-cache.c  |    2 +-
 pack-check.c  |   68 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 pack.h        |    2 +-
 sha1_file.c   |   66 +++++++++++++++++++++++++++++++++++++------------------
 verify-pack.c |   51 ++++++++++++++++++++++++++++++++++---------
 7 files changed, 156 insertions(+), 44 deletions(-)
 rename verify_pack.c => pack-check.c (25%)

cf43fb6e9fec205d4786a284e1656b3612c28a77
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ install: $(PROG) $(SCRIPTS)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o date.o index.o diff-delta.o patch-delta.o entry.o \
-	 epoch.o refs.o csum-file.o verify_pack.o pkt-line.o
+	 epoch.o refs.o csum-file.o pack-check.o pkt-line.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h \
 	pack.h pkt-line.h
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -251,11 +251,20 @@ extern struct packed_git {
 	unsigned int pack_use_cnt;
 	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
 } *packed_git;
+
+struct pack_entry {
+	unsigned int offset;
+	unsigned char sha1[20];
+	struct packed_git *p;
+};
+
 extern void prepare_packed_git(void);
 extern int use_packed_git(struct packed_git *);
 extern void unuse_packed_git(struct packed_git *);
 extern struct packed_git *add_packed_git(char *, int);
 extern int num_packed_objects(const struct packed_git *p);
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
+extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
+extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
 
 #endif /* CACHE_H */
diff --git a/fsck-cache.c b/fsck-cache.c
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -440,7 +440,7 @@ int main(int argc, char **argv)
 		prepare_packed_git();
 		for (p = packed_git; p; p = p->next)
 			/* verify gives error messages itself */
-			verify_pack(p); 
+			verify_pack(p, 0);
 
 		for (p = packed_git; p; p = p->next) {
 			int num = num_packed_objects(p);
diff --git a/verify_pack.c b/pack-check.c
similarity index 25%
rename from verify_pack.c
rename to pack-check.c
--- a/verify_pack.c
+++ b/pack-check.c
@@ -10,8 +10,9 @@ static int verify_packfile(struct packed
 	unsigned long pack_size = p->pack_size;
 	void *pack_base;
 	struct pack_header *hdr;
-	int nr_objects;
+	int nr_objects, err, i;
 
+	/* Header consistency check */
 	hdr = p->pack_base;
 	if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
 		return error("Packfile signature mismatch", p->pack_name);
@@ -34,11 +35,47 @@ static int verify_packfile(struct packed
 	if (memcmp(sha1, pack_base + pack_size - 20, 20))
 		return error("Packfile %s SHA1 mismatch with itself",
 			     p->pack_name);
-	return 0;
+
+	/* Make sure everything reachable from idx is valid.  Since we
+	 * have verified that nr_objects matches between idx and pack,
+	 * we do not do scan-streaming check on the pack file.
+	 */
+	for (i = err = 0; i < nr_objects; i++) {
+		unsigned char sha1[20];
+		struct pack_entry e;
+		void *data;
+		char type[20];
+		unsigned long size;
+
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("internal error pack-check nth-packed-object");
+		if (!find_pack_entry_one(sha1, &e, p))
+			die("internal error pack-check find-pack-entry-one");
+		data = unpack_entry_gently(&e, type, &size);
+		if (!data) {
+			err = error("cannot unpack %s from %s",
+				    sha1_to_hex(sha1), p->pack_name);
+			continue;
+		}
+		if (check_sha1_signature(sha1, data, size, type)) {
+			err = error("cannot packed %s from %s corrupt",
+				    sha1_to_hex(sha1), p->pack_name);
+			free(data);
+			continue;
+		}
+		free(data);
+	}
+
+	return err;
 }
 
 
-int verify_pack(struct packed_git *p)
+static void show_pack_info(struct packed_git *p)
+{
+	/* Next round */
+}
+
+int verify_pack(struct packed_git *p, int verbose)
 {
 	unsigned long index_size = p->index_size;
 	void *index_base = p->index_base;
@@ -46,17 +83,30 @@ int verify_pack(struct packed_git *p)
 	unsigned char sha1[20];
 	int ret;
 
+	ret = 0;
 	/* Verify SHA1 sum of the index file */
 	SHA1_Init(&ctx);
 	SHA1_Update(&ctx, index_base, index_size - 20);
 	SHA1_Final(sha1, &ctx);
 	if (memcmp(sha1, index_base + index_size - 20, 20))
-		return error("Packfile index for %s SHA1 mismatch",
-			     p->pack_name);
+		ret = error("Packfile index for %s SHA1 mismatch",
+			    p->pack_name);
+
+	if (!ret) {
+		/* Verify pack file */
+		use_packed_git(p);
+		ret = verify_packfile(p);
+		unuse_packed_git(p);
+	}
+
+	if (verbose) {
+		if (ret)
+			printf("%s: bad\n", p->pack_name);
+		else {
+			show_pack_info(p);
+			printf("%s: ok\n", p->pack_name);
+		}
+	}
 
-	/* Verify pack file */
-	use_packed_git(p);
-	ret = verify_packfile(p);
-	unuse_packed_git(p);
 	return ret;
 }
diff --git a/pack.h b/pack.h
--- a/pack.h
+++ b/pack.h
@@ -27,6 +27,6 @@ struct pack_header {
 	unsigned int hdr_entries;
 };
 
-extern int verify_pack(struct packed_git *);
+extern int verify_pack(struct packed_git *, int);
 
 #endif
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -272,12 +272,6 @@ static int pack_used_ctr;
 static unsigned long pack_mapped;
 struct packed_git *packed_git;
 
-struct pack_entry {
-	unsigned int offset;
-	unsigned char sha1[20];
-	struct packed_git *p;
-};
-
 static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
 				void **idx_map_)
 {
@@ -618,22 +612,34 @@ void * unpack_sha1_file(void *map, unsig
 	return unpack_sha1_rest(&stream, hdr, *size);
 }
 
+/* forward declaration for a mutually recursive function */
+static int packed_object_info(struct pack_entry *entry,
+			      char *type, unsigned long *sizep);
+
 static int packed_delta_info(unsigned char *base_sha1,
 			     unsigned long delta_size,
 			     unsigned long left,
 			     char *type,
-			     unsigned long *sizep)
+			     unsigned long *sizep,
+			     struct packed_git *p)
 {
+	struct pack_entry base_ent;
+
 	if (left < 20)
 		die("truncated pack file");
 
+	/* The base entry _must_ be in the same pack */
+	if (!find_pack_entry_one(base_sha1, &base_ent, p))
+		die("failed to find delta-pack base object %s",
+		    sha1_to_hex(base_sha1));
+
 	/* We choose to only get the type of the base object and
 	 * ignore potentially corrupt pack file that expects the delta
 	 * based on a base with a wrong size.  This saves tons of
 	 * inflate() calls.
 	 */
 
-	if (sha1_object_info(base_sha1, type, NULL))
+	if (packed_object_info(&base_ent, type, NULL))
 		die("cannot get info for delta-pack base");
 
 	if (sizep) {
@@ -716,7 +722,7 @@ static int packed_object_info(struct pac
 
 	switch (kind) {
 	case OBJ_DELTA:
-		retval = packed_delta_info(pack, size, left, type, sizep);
+		retval = packed_delta_info(pack, size, left, type, sizep, p);
 		unuse_packed_git(p);
 		return retval;
 	case OBJ_COMMIT:
@@ -747,8 +753,10 @@ static void *unpack_delta_entry(unsigned
 				unsigned long delta_size,
 				unsigned long left,
 				char *type,
-				unsigned long *sizep)
+				unsigned long *sizep,
+				struct packed_git *p)
 {
+	struct pack_entry base_ent;
 	void *data, *delta_data, *result, *base;
 	unsigned long data_size, result_size, base_size;
 	z_stream stream;
@@ -773,8 +781,11 @@ static void *unpack_delta_entry(unsigned
 	if ((st != Z_STREAM_END) || stream.total_out != delta_size)
 		die("delta data unpack failed");
 
-	/* This may recursively unpack the base, which is what we want */
-	base = read_sha1_file(base_sha1, type, &base_size);
+	/* The base entry _must_ be in the same pack */
+	if (!find_pack_entry_one(base_sha1, &base_ent, p))
+		die("failed to find delta-pack base object %s",
+		    sha1_to_hex(base_sha1));
+	base = unpack_entry_gently(&base_ent, type, &base_size);
 	if (!base)
 		die("failed to read delta-pack base object %s",
 		    sha1_to_hex(base_sha1));
@@ -820,21 +831,33 @@ static void *unpack_entry(struct pack_en
 			  char *type, unsigned long *sizep)
 {
 	struct packed_git *p = entry->p;
-	unsigned long offset, size, left;
-	unsigned char *pack;
-	enum object_type kind;
 	void *retval;
 
 	if (use_packed_git(p))
 		die("cannot map packed file");
+	retval = unpack_entry_gently(entry, type, sizep);
+	unuse_packed_git(p);
+	if (!retval)
+		die("corrupted pack file");
+	return retval;
+}
+
+/* The caller is responsible for use_packed_git()/unuse_packed_git() pair */
+void *unpack_entry_gently(struct pack_entry *entry,
+			  char *type, unsigned long *sizep)
+{
+	struct packed_git *p = entry->p;
+	unsigned long offset, size, left;
+	unsigned char *pack;
+	enum object_type kind;
+	void *retval;
 
 	offset = unpack_object_header(p, entry->offset, &kind, &size);
 	pack = p->pack_base + offset;
 	left = p->pack_size - offset;
 	switch (kind) {
 	case OBJ_DELTA:
-		retval = unpack_delta_entry(pack, size, left, type, sizep);
-		unuse_packed_git(p);
+		retval = unpack_delta_entry(pack, size, left, type, sizep, p);
 		return retval;
 	case OBJ_COMMIT:
 		strcpy(type, "commit");
@@ -849,11 +872,10 @@ static void *unpack_entry(struct pack_en
 		strcpy(type, "tag");
 		break;
 	default:
-		die("corrupted pack file");
+		return NULL;
 	}
 	*sizep = size;
 	retval = unpack_non_delta_entry(pack, size, left);
-	unuse_packed_git(p);
 	return retval;
 }
 
@@ -873,8 +895,8 @@ int nth_packed_object_sha1(const struct 
 	return 0;
 }
 
-static int find_pack_entry_1(const unsigned char *sha1,
-			     struct pack_entry *e, struct packed_git *p)
+int find_pack_entry_one(const unsigned char *sha1,
+			struct pack_entry *e, struct packed_git *p)
 {
 	int *level1_ofs = p->index_base;
 	int hi = ntohl(level1_ofs[*sha1]);
@@ -904,7 +926,7 @@ static int find_pack_entry(const unsigne
 	prepare_packed_git();
 
 	for (p = packed_git; p; p = p->next) {
-		if (find_pack_entry_1(sha1, e, p))
+		if (find_pack_entry_one(sha1, e, p))
 			return 1;
 	}
 	return 0;
diff --git a/verify-pack.c b/verify-pack.c
--- a/verify-pack.c
+++ b/verify-pack.c
@@ -1,25 +1,56 @@
 #include "cache.h"
 #include "pack.h"
 
-static int verify_one_pack(char *arg)
+static int verify_one_pack(char *arg, int verbose)
 {
-	struct packed_git *g = add_packed_git(arg, strlen(arg));
-	if (!g)
-		return -1;
-	return verify_pack(g);
+	int len = strlen(arg);
+	struct packed_git *g;
+	
+	while (1) {
+		/* Should name foo.idx, but foo.pack may be named;
+		 * convert it to foo.idx
+		 */
+		if (!strcmp(arg + len - 5, ".pack")) {
+			strcpy(arg + len - 5, ".idx");
+			len--;
+		}
+		/* Should name foo.idx now */
+		if ((g = add_packed_git(arg, len)))
+			break;
+		/* No?  did you name just foo? */
+		strcpy(arg + len, ".idx");
+		len += 4;
+		if ((g = add_packed_git(arg, len)))
+			break;
+		return error("packfile %s not found.", arg);
+	}
+	return verify_pack(g, verbose);
 }
 
+static const char *verify_pack_usage = "git-verify-pack [-v] <pack>...";
+
 int main(int ac, char **av)
 {
 	int errs = 0;
+	int verbose = 0;
+	int no_more_options = 0;
 
 	while (1 < ac) {
 		char path[PATH_MAX];
-		strcpy(path, av[1]);
-		if (verify_one_pack(path))
-			errs++;
-		else
-			printf("%s: OK\n", av[1]);
+
+		if (!no_more_options && av[1][0] == '-') {
+			if (!strcmp("-v", av[1]))
+				verbose = 1;
+			else if (!strcmp("--", av[1]))
+				no_more_options = 1;
+			else
+				usage(verify_pack_usage);
+		}
+		else {
+			strcpy(path, av[1]);
+			if (verify_one_pack(path, verbose))
+				errs++;
+		}
 		ac--; av++;
 	}
 	return !!errs;
------------

^ permalink raw reply	[relevance 13%]

* [PATCH 2/2] Show more details of packfile with verify-pack -v.
@ 2005-07-01  0:17 14% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-01  0:17 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This implements show_pack_info() function used in verify-pack
command when -v flag is used to obtain something like
unpack-objects used to give when it was first written.

It shows the following for each non-deltified object found in
the pack:

    SHA1 type size offset

For deltified objects, it shows this instead:

    SHA1 type size offset depth base_sha1

In order to get the output in the order that appear in the pack
file for debugging purposes, you can do this:

 $ git-verify-pack -v packfile | sort -n -k 4,4

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h      |    1 +
 pack-check.c |   33 ++++++++++++++++++++++++++++++++-
 sha1_file.c  |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 1 deletions(-)

c45c7e2f7d1718a156cef21630940e6be0e75d18
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -266,5 +266,6 @@ extern int num_packed_objects(const stru
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
 extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
 extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
+extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, int *, unsigned char *);
 
 #endif /* CACHE_H */
diff --git a/pack-check.c b/pack-check.c
--- a/pack-check.c
+++ b/pack-check.c
@@ -72,7 +72,36 @@ static int verify_packfile(struct packed
 
 static void show_pack_info(struct packed_git *p)
 {
-	/* Next round */
+	struct pack_header *hdr;
+	int nr_objects, i;
+
+	hdr = p->pack_base;
+	nr_objects = ntohl(hdr->hdr_entries);
+
+	for (i = 0; i < nr_objects; i++) {
+		unsigned char sha1[20], base_sha1[20];
+		struct pack_entry e;
+		char type[20];
+		unsigned long size;
+		unsigned long store_size;
+		int delta_chain_length;
+
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("internal error pack-check nth-packed-object");
+		if (!find_pack_entry_one(sha1, &e, p))
+			die("internal error pack-check find-pack-entry-one");
+
+		packed_object_info_detail(&e, type, &size, &store_size,
+					  &delta_chain_length,
+					  base_sha1);
+		printf("%s ", sha1_to_hex(sha1));
+		if (!delta_chain_length)
+			printf("%-6s %lu %u\n", type, size, e.offset);
+		else
+			printf("%-6s %lu %u %d %s\n", type, size, e.offset,
+			       delta_chain_length, sha1_to_hex(base_sha1));
+	}
+
 }
 
 int verify_pack(struct packed_git *p, int verbose)
@@ -103,7 +132,9 @@ int verify_pack(struct packed_git *p, in
 		if (ret)
 			printf("%s: bad\n", p->pack_name);
 		else {
+			use_packed_git(p);
 			show_pack_info(p);
+			unuse_packed_git(p);
 			printf("%s: ok\n", p->pack_name);
 		}
 	}
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -704,6 +704,57 @@ static unsigned long unpack_object_heade
 	return offset;
 }
 
+void packed_object_info_detail(struct pack_entry *e,
+			       char *type,
+			       unsigned long *size,
+			       unsigned long *store_size,
+			       int *delta_chain_length,
+			       unsigned char *base_sha1)
+{
+	struct packed_git *p = e->p;
+	unsigned long offset, left;
+	unsigned char *pack;
+	enum object_type kind;
+
+	offset = unpack_object_header(p, e->offset, &kind, size);
+	pack = p->pack_base + offset;
+	left = p->pack_size - offset;
+	if (kind != OBJ_DELTA)
+		*delta_chain_length = 0;
+	else {
+		int chain_length = 0;
+		memcpy(base_sha1, pack, 20);
+		do {
+			struct pack_entry base_ent;
+			unsigned long junk;
+
+			find_pack_entry_one(pack, &base_ent, p);
+			offset = unpack_object_header(p, base_ent.offset,
+						      &kind, &junk);
+			pack = p->pack_base + offset;
+			chain_length++;
+		} while (kind == OBJ_DELTA);
+		*delta_chain_length = chain_length;
+	}
+	switch (kind) {
+	case OBJ_COMMIT:
+		strcpy(type, "commit");
+		break;
+	case OBJ_TREE:
+		strcpy(type, "tree");
+		break;
+	case OBJ_BLOB:
+		strcpy(type, "blob");
+		break;
+	case OBJ_TAG:
+		strcpy(type, "tag");
+		break;
+	default:
+		die("corrupted pack file");
+	}
+	*store_size = 0; /* notyet */
+}
+
 static int packed_object_info(struct pack_entry *entry,
 			      char *type, unsigned long *sizep)
 {
------------

^ permalink raw reply	[relevance 14%]

* [PATCH] clone-pack.c:write_one_ref() - Create leading directories.
  @ 2005-07-06  8:11 17% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-06  8:11 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

The function write_one_ref() is passed the list of refs received
from the other end, which was obtained by directory traversal
under $GIT_DIR/refs; this can contain paths other than what
git-init-db prepares and would fail to clone when there is
such.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h      |    2 ++
 clone-pack.c |    5 ++++-
 sha1_file.c  |   19 +++++++++++++++++++
 3 files changed, 25 insertions(+), 1 deletions(-)

dfad9e5e585c1c9e1eaf599878f040f7ae519b18
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -161,6 +161,8 @@ extern void rollback_index_file(struct c
 extern char *git_path(const char *fmt, ...);
 extern char *sha1_file_name(const unsigned char *sha1);
 
+int safe_create_leading_directories(char *path);
+
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
diff --git a/clone-pack.c b/clone-pack.c
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -68,9 +68,12 @@ static int is_master(struct ref *ref)
 static void write_one_ref(struct ref *ref)
 {
 	char *path = git_path(ref->name);
-	int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	int fd;
 	char *hex;
 
+	if (safe_create_leading_directories(path))
+		die("unable to create leading directory for %s", ref->name);
+	fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
 	if (fd < 0)
 		die("unable to create ref %s", ref->name);
 	hex = sha1_to_hex(ref->sha1);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -130,6 +130,25 @@ char *git_path(const char *fmt, ...)
 	return ret;
 }
 
+int safe_create_leading_directories(char *path)
+{
+	char *pos = path;
+
+	while (pos) {
+		pos = strchr(pos, '/');
+		if (!pos)
+			break;
+		*pos = 0;
+		if (mkdir(path, 0777) < 0)
+			if (errno != EEXIST) {
+				*pos = '/';
+				return -1;
+			}
+		*pos++ = '/';
+	}
+	return 0;
+}
+
 int get_sha1(const char *str, unsigned char *sha1)
 {
 	static const char *prefix[] = {

^ permalink raw reply	[relevance 17%]

* [PATCH] Pull efficiently from a dumb git store.
  @ 2005-07-07 23:16  9%             ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-07 23:16 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, git

The git-update-dumb-server-script command statically prepares
additional information to describe what the server side has, so
that a smart client can pull things efficiently even via a
transport such as static-file-only HTTP.

The files prepared by the command is $GIT_DIR/info/server, which
is a tar archive that contains the following files:

    rev-cache   -- commit ancestry chain, append only to help
	           rsync mirroring.
    inventory   -- list of refs and their SHA1.
    pack        -- list of available prepackaged packs.
    server.sha1 -- sha1sum output for the above three files (optional).

A smart client git-dumb-pull-script works in the following way:

 - First it slurps these files, and then .idx files that
   corresponds to the packs described in "pack".

 - Then it finds the commits that it wants from the server by
   looking at "inventory" to find various heads, and "rev-cache" to
   find commits that is missing from the client, and "pack" to
   figure out downloading which packs is the most efficient way to
   fill what is missing from its repository.  This is done with
   the help of the git-dumb-pull-resolve command.

 - Then it slurps the pack files.

 - The git-http-pull / git-local-pull command walks the commit
   chain in an old-fashioned way and downloads unpacked objects
   to fill the rest.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 Makefile                      |   10 +
 dumb-pull-resolve.c           |  239 +++++++++++++++++++++++++++++++++
 git-dumb-pull-script          |  129 ++++++++++++++++++
 git-update-dumb-server-script |   47 ++++++
 rev-cache.c                   |  300 +++++++++++++++++++++++++++++++++++++++++
 rev-cache.h                   |   31 ++++
 show-rev-cache.c              |   18 ++
 update-dumb-server.c          |  153 +++++++++++++++++++++
 8 files changed, 925 insertions(+), 2 deletions(-)
 create mode 100644 dumb-pull-resolve.c
 create mode 100755 git-dumb-pull-script
 create mode 100755 git-update-dumb-server-script
 create mode 100644 rev-cache.c
 create mode 100644 rev-cache.h
 create mode 100644 show-rev-cache.c
 create mode 100644 update-dumb-server.c

a880bc7300f070aca3a255828b48390cb9793245
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,8 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-fetch-script git-status-script git-commit-script \
 	git-log-script git-shortlog git-cvsimport-script git-diff-script \
 	git-reset-script git-add-script git-checkout-script git-clone-script \
-	gitk git-cherry git-rebase-script git-relink-script git-repack-script
+	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
+	git-dumb-pull-script git-update-dumb-server-script
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
@@ -44,7 +45,8 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-stages git-rev-parse git-patch-id git-pack-objects \
 	git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
 	git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
-	git-show-index
+	git-show-index git-update-dumb-server git-show-rev-cache \
+	git-dumb-pull-resolve
 
 all: $(PROG)
 
@@ -58,6 +60,9 @@ LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h \
 	pack.h pkt-line.h refs.h
 
+LIB_H += rev-cache.h
+LIB_OBJS += rev-cache.o
+
 LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
 
@@ -153,6 +158,7 @@ object.o: $(LIB_H)
 read-cache.o: $(LIB_H)
 sha1_file.o: $(LIB_H)
 usage.o: $(LIB_H)
+rev-cache.o: $(LIB_H)
 strbuf.o: $(LIB_H)
 gitenv.o: $(LIB_H)
 entry.o: $(LIB_H)
diff --git a/dumb-pull-resolve.c b/dumb-pull-resolve.c
new file mode 100644
--- /dev/null
+++ b/dumb-pull-resolve.c
@@ -0,0 +1,239 @@
+#include "cache.h"
+#include "rev-cache.h"
+
+static const char *dumb_pull_resolve_usage =
+"git-dumb_pull_resolve <tmpdir> (<remote> <local>)...";
+
+static struct inventory {
+	struct inventory *next;
+	unsigned char sha1[20];
+	char name[1]; /* more; 1 is for terminating NUL */
+} *inventory;
+
+static struct inventory *find_inventory(const char *name)
+{
+	struct inventory *e = inventory;
+	while (e && strcmp(e->name, name))
+		e = e->next;
+	return e;
+}
+
+static void read_inventory(const char *path)
+{
+	FILE *fp;
+	char buf[1024];
+
+	fp = fopen(path, "r");
+	if (!fp)
+		die("cannot open %s", path);
+	while (fgets(buf, sizeof(buf), fp)) {
+		struct inventory *e; 
+		int len = strlen(buf);
+		if (buf[len-1] != '\n')
+			die("malformed inventory file");
+		buf[--len] = 0;
+		e = xmalloc(sizeof(*e) + len - 41);
+		strcpy(e->name, buf + 41);
+		get_sha1_hex(buf, e->sha1);
+		e->next = inventory;
+		inventory = e;
+	}
+	fclose(fp);
+}
+
+#define MAX_PACKS 0
+static struct pack {
+	struct pack *next;
+	unsigned int *map;
+	unsigned long pack_size;
+	unsigned long index_size;
+	unsigned char ix;
+	unsigned long fill;
+	char name[1]; /* more; 1 is for terminating NUL */
+} *pack;
+
+static void map_pack_idx(const char *path, const char *tmpdir)
+{
+	FILE *fp;
+	char buf[1024];
+	int num_pack = 0;
+
+	fp = fopen(path, "r");
+	if (!fp)
+		die("cannot open %s", path);
+	while (fgets(buf, sizeof(buf), fp)) {
+		struct pack *e;
+		int len;
+		int fd;
+		struct stat st;
+		char path[PATH_MAX];
+		char *cp;
+
+		cp = strchr(buf, ' ');
+		if (!cp || !*++cp)
+			die("malformed pack file");
+
+		len = strlen(cp);
+		if (cp[len-1] != '\n')
+			die("malformed pack file");
+		cp[--len] = 0;
+		
+		if (MAX_PACKS && MAX_PACKS < num_pack) {
+			error("cannot handle too many packs.  ignoring %s",
+			      cp);
+			continue;
+		}
+
+		e = xmalloc(sizeof(*e) + len);
+		strcpy(e->name, cp);
+		e->pack_size = strtoul(buf, NULL, 10);
+
+		sprintf(path, "%s/%s", tmpdir, cp);
+		len = strlen(path);
+		strcpy(path + len - 5, ".idx");
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			goto ignore_entry;
+		if (fstat(fd, &st)) {
+			close(fd);
+			goto ignore_entry;
+		}
+		e->index_size = st.st_size;
+		e->map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+		close(fd);
+		if (e->map == MAP_FAILED)
+			die("cannot map %s", path);
+		e->next = pack;
+		e->ix = num_pack++;
+		pack = e;
+		continue;
+	ignore_entry:
+		free(e);
+	}
+	fclose(fp);
+}
+
+static int find_in_pack_idx(const unsigned char *sha1, struct pack *e)
+{
+	unsigned int *level1_ofs = e->map;
+	int hi = ntohl(level1_ofs[*sha1]);
+	int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+	void *index = e->map + 256;
+
+	do {
+		int mi = (lo + hi) / 2;
+		int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
+		if (!cmp)
+			return 1;
+		if (0 < cmp)
+			hi = mi;
+		else
+			lo = mi+1;
+	} while (lo < hi);
+	return 0;
+}
+
+static void mark_needed(const unsigned char *sha1)
+{
+	struct rev_cache *rc;
+	struct rev_list_elem *rle;
+	int pos;
+
+	if (has_sha1_file(sha1))
+		return;
+	pos = find_rev_cache(sha1);
+	if (pos < 0)
+		die("rev-cache does not match inventory");
+	rc = rev_cache[pos];
+	rc->work = 1;
+	for (rle = rc->parents; rle; rle= rle->next)
+		mark_needed(rle->ri->sha1);
+}
+
+static struct rev_cache *needed;
+static unsigned long num_needed;
+
+static void link_needed(void)
+{
+	/* Link needed ones for quick traversal */
+	int i;
+	num_needed = 0;
+	for (i = 0; i < nr_revs; i++) {
+		struct rev_cache *rc = rev_cache[i];
+		if (rc->work) {
+			rc->work_ptr = needed;
+			needed = rc;
+			num_needed++;
+		}
+	}
+}
+
+/* Currently this part is stupid, FIXME */
+static void find_optimum_packs(void)
+{
+	struct rev_cache *rc;
+	struct pack *e;
+	unsigned long hits, total;
+
+	hits = total = 0;
+	for (rc = needed; rc; rc = rc->work_ptr)
+		rc->work = 0;
+
+	for (e = pack; e; e = e->next) {
+		e->fill = 0;
+		for (rc = needed; rc; rc = rc->work_ptr)
+			if (!rc->work && find_in_pack_idx(rc->sha1, e)) {
+				rc->work = 1<<(e->ix);
+				e->fill++;
+				hits++;
+			}
+		if (e->fill) {
+			fprintf(stderr, "use %s to fill %lu\n",
+				e->name, e->fill);
+			total += e->pack_size;
+		}
+	}
+
+	fprintf(stderr, "# needed %lu, hits %lu, total %lu\n",
+		num_needed, hits, total);
+	for (e = pack; e; e = e->next)
+		if (e->fill)
+			printf("%s\n", e->name);
+}
+
+int main(int ac, char **av)
+{
+	int i;
+	char path[PATH_MAX];
+	const char *tmpdir;
+
+	if (ac < 4 || ac % 2)
+		usage(dumb_pull_resolve_usage);
+
+	tmpdir = av[1];
+	ac--; av++;
+
+	sprintf(path, "%s/inventory", tmpdir);
+	read_inventory(path);
+
+	sprintf(path, "%s/rev-cache", tmpdir);
+	read_rev_cache(path, NULL, 0);
+
+	for (i = 1; i < ac; i += 2) {
+		/* av[i] is a remote branch name */
+		struct inventory *e = find_inventory(av[i]);
+		if (!e) {
+			error("cannot find branch %s", av[i]);
+			continue;
+		}
+		mark_needed(e->sha1);
+	}
+
+	link_needed();
+
+	sprintf(path, "%s/pack", tmpdir);
+	map_pack_idx(path, tmpdir);
+
+	find_optimum_packs();
+	return 0;
+}
diff --git a/git-dumb-pull-script b/git-dumb-pull-script
new file mode 100755
--- /dev/null
+++ b/git-dumb-pull-script
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="${GIT_DIR}/objects"}
+
+usage () {
+	echo >&2 "* git dumb-pull <url> ( <remote-name> <local-name> ) ..."
+	exit 1
+}
+
+error () {
+	echo >&2 "* git-dumb-pull: $*"
+	exit 1
+}
+
+download_one() {
+	# $1 - URL
+	# $2 - Local target
+	case "$1" in
+	file://* )
+		path=/$(expr "$1" : 'file:/*\(.*\)')
+		cp "$path" "$2" || rm -f "$2"
+		;;
+	http://* | https://* )
+		wget -O "$2" "$1" || rm -f "$2"
+		;;
+	esac
+}
+
+case "$#" in
+0)
+	usage;;
+esac
+url="$1"; shift
+
+case "$url" in
+http://* | https://*)
+	use_url="$url"
+	cmd='git-http-pull -a -v'
+	;;
+file://*)
+	use_url=/$(expr "$url" : 'file:/*\(.*\)')
+	cmd='git-local-pull -a -l -v'
+	;;
+*)
+	error "Unknown url scheme $url"
+	;;
+esac
+
+# The rest of arguments are remote and local names
+case $#,$(expr "$#" % 2) in
+0,* | 1,* | *,1)
+	error "Need one or more branch name pairs." ;;
+esac
+
+tmp=.git-dumb-pull-$$
+mkdir "$tmp" || error "cannot create temporary directory"
+trap "rm -fr $tmp" 0 1 2 3 15
+
+# Failing to download is not fatal.  It just means the server is
+# dumber than we thought ;-)
+if download_one "$url/info/server" $tmp/server
+then
+	infofiles='inventory pack rev-cache'
+	(
+	  cd $tmp &&
+	  tar xvf server $infofiles || exit 1
+	  if tar xf server server.sha1
+	  then
+		sha1sum -c server.sha1 || {
+		    # did we fail because we did not have sha1sum command?
+		    case "$?" in
+		    127)
+		        : ;; # the command did not exist.
+		    *)
+		        false ;;
+		    esac
+		}
+	  else
+	  	echo >&2 "* warning: server file lacks sha1 checksum"
+	  fi &&
+	  rm -f server.sha1
+	) || exit
+fi
+
+if test -f $tmp/pack
+then
+	while read pack_size pack
+	do
+		case "$pack" in
+		*/*)
+			echo >&2 "* malformed pack $pack"
+			continue
+			;;
+		esac
+
+		idx=$(expr "$pack" : '\(.*\)\.pack$').idx
+		# It is possible, even likely, that we already have that
+		# index file and associated pack file.
+		if test -f "${GIT_OBJECT_DIRECTORY}/pack/$pack" &&
+		   test -f "${GIT_OBJECT_DIRECTORY}/pack/$idx"
+		then
+			continue
+		fi
+		download_one "$url/objects/pack/$idx" "$tmp/$idx"
+	done <$tmp/pack
+
+	git-dumb-pull-resolve $tmp "$@" |
+	while read pack
+	do
+		echo >&2 "* $pack"
+		download_one "$url/objects/pack/$pack" "$tmp/$pack"
+		if test -f "$tmp/$pack" && git-verify-pack "$tmp/$pack"
+		then
+			idx=$(expr "$pack" : '\(.*\)\.pack$').idx
+			mv "$tmp/$pack" "$tmp/$idx" \
+				"${GIT_OBJECT_DIRECTORY}/pack/"
+		fi
+	done
+fi
+
+while case "$#" in 0) break ;; esac
+do
+	remote="$1" local="$2"
+	$cmd -w "$local" "$remote" "$use_url"
+
+	shift
+	shift
+done
diff --git a/git-update-dumb-server-script b/git-update-dumb-server-script
new file mode 100755
--- /dev/null
+++ b/git-update-dumb-server-script
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright (c) 2005, Junio C Hamano
+#
+
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+export GIT_DIR GIT_OBJECT_DIRECTORY
+
+infofiles='inventory pack rev-cache'
+
+usage () {
+	echo >&2 "* git update-dumb-server"
+	exit 1
+}
+
+# Allow 10MB plain SHA1 files to be accumulated before we repack.
+max_plain_size=10240
+
+plain_size=$(
+{
+	du -sk "$GIT_OBJECT_DIRECTORY/" "$GIT_OBJECT_DIRECTORY/pack/" |
+	sed -e 's/^[ 	]*\([0-9][0-9]*\)[ 	].*/\1/'
+	echo ' - p'
+} | dc) &&
+
+if test $max_plain_size -lt $plain_size >/dev/null
+then
+	git-repack-script && git-prune-packed
+fi &&
+
+git-update-dumb-server &&
+
+files=$infofiles
+cd "$GIT_DIR/info" &&
+if sha1sum $infofiles >server.sha1
+then
+	files="$files server.sha1"
+else
+	rm -f server.sha1
+	echo >&2 "* warning: creating server file without sha1sum"
+fi &&
+tar cf server $files &&
+
+# We leave rev-cache there for later runs.
+rm -f server.sha1 inventory pack
+
diff --git a/rev-cache.c b/rev-cache.c
new file mode 100644
--- /dev/null
+++ b/rev-cache.c
@@ -0,0 +1,300 @@
+#include "refs.h"
+#include "cache.h"
+#include "rev-cache.h"
+
+struct rev_cache **rev_cache;
+int nr_revs, alloc_revs;
+
+struct rev_list_elem *rle_free;
+
+#define BATCH_SIZE 512
+
+int find_rev_cache(const unsigned char *sha1)
+{
+	int lo = 0, hi = nr_revs;
+	while (lo < hi) {
+		int mi = (lo + hi) / 2;
+		struct rev_cache *ri = rev_cache[mi];
+		int cmp = memcmp(sha1, ri->sha1, 20);
+		if (!cmp)
+			return mi;
+		if (cmp < 0)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo - 1;
+}
+
+static struct rev_list_elem *alloc_list_elem(void)
+{
+	struct rev_list_elem *rle;
+	if (!rle_free) {
+		int i;
+
+		rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
+		for (i = 0; i < BATCH_SIZE - 1; i++) {
+			rle[i].ri = NULL;
+			rle[i].next = &rle[i + 1];
+		}
+		rle[BATCH_SIZE - 1].ri = NULL; 
+		rle[BATCH_SIZE - 1].next = NULL; 
+		rle_free = rle;
+	}
+	rle = rle_free;
+	rle_free = rle->next;
+	return rle;
+}
+
+static struct rev_cache *create_rev_cache(const unsigned char *sha1)
+{
+	struct rev_cache *ri;
+	int pos = find_rev_cache(sha1);
+
+	if (0 <= pos)
+		return rev_cache[pos];
+	pos = -pos - 1;
+	if (alloc_revs <= ++nr_revs) {
+		alloc_revs = alloc_nr(alloc_revs);
+		rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
+	}
+	if (pos < nr_revs)
+		memmove(rev_cache + pos + 1, rev_cache + pos,
+			(nr_revs - pos - 1) * sizeof(ri));
+	ri = xcalloc(1, sizeof(*ri));
+	memcpy(ri->sha1, sha1, 20);
+	rev_cache[pos] = ri;
+	return ri;
+}
+
+static unsigned char last_sha1[20];
+
+static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
+{
+	unsigned char flag;
+	struct rev_list_elem *rle;
+
+	if (ri->written)
+		return;
+
+	if (ri->parsed) {
+
+		/* We use last_sha1 compression only for the first parent;
+		 * otherwise the resulting rev-cache would lose the parent
+		 * order information.
+		 */
+		if (ri->parents &&
+		    !memcmp(ri->parents->ri->sha1, last_sha1, 20))
+			flag = (ri->num_parents - 1) | 0x80;
+		else
+			flag = ri->num_parents;
+
+		fwrite(ri->sha1, 20, 1, rev_cache_file);
+		fwrite(&flag, 1, 1, rev_cache_file);
+		for (rle = ri->parents; rle; rle = rle->next) {
+			if (flag & 0x80 && rle == ri->parents)
+				continue;
+			fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
+		}
+		memcpy(last_sha1, ri->sha1, 20);
+		ri->written = 1;
+	}
+	/* recursively write children depth first */
+	for (rle = ri->children; rle; rle = rle->next)
+		write_one_rev_cache(rev_cache_file, rle->ri);
+}
+
+void write_rev_cache(const char *path)
+{
+	/* write the following commit ancestry information in
+	 * $GIT_DIR/info/rev-cache.
+	 *
+	 * The format is:
+	 * 20-byte SHA1 (commit ID)
+	 * 1-byte flag:
+	 * - bit 0-6 records "number of parent commit SHA1s to
+	 *   follow" (i.e. up to 127 children can be listed).
+	 * - when the bit 7 is on, then "the entry immediately
+	 *   before this entry is one of the parents of this
+         *   commit".
+	 * N x 20-byte SHA1 (parent commit IDs)
+	 */
+	FILE *rev_cache_file;
+	int i;
+	struct rev_cache *ri;
+
+	rev_cache_file = fopen(path, "a");
+	if (!rev_cache_file)
+		die("cannot append to rev cache file.");
+
+	memset(last_sha1, 0, 20);
+
+	/* Go through available rev_cache structures, starting from
+	 * parentless ones first, so that we would get most out of
+	 * last_sha1 optimization by the depth first behaviour of
+	 * write_one_rev_cache().
+	 */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		if (ri->num_parents)
+			continue;
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+	/* Then the rest */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+
+	fclose(rev_cache_file);
+}
+
+static void add_parent(struct rev_cache *child,
+		       const unsigned char *parent_sha1)
+{
+	struct rev_cache *parent = create_rev_cache(parent_sha1);
+	struct rev_list_elem *e = alloc_list_elem();
+
+	/* Keep the parent list ordered in the same way the commit
+	 * object records them.
+	 */
+	e->ri = parent;
+	e->next = NULL;
+	if (!child->parents_tail)
+		child->parents = e;
+	else
+		child->parents_tail->next = e;
+	child->parents_tail = e;
+	child->num_parents++;
+	
+	/* There is no inherent order of the children so we just
+	 * LIFO them together.
+	 */
+	e = alloc_list_elem();
+	e->next = parent->children;
+	parent->children = e;
+	e->ri = child;
+	parent->num_children++;
+}
+
+int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
+{
+	unsigned char *map;
+	int fd;
+	struct stat st;
+	unsigned long ofs, len;
+	struct rev_cache *ri = NULL;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return 0;
+	if (fstat(fd, &st)) {
+		close(fd);
+		return -1;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	memset(last_sha1, 0, 20);
+	ofs = 0;
+	len = st.st_size;
+	while (ofs < len) {
+		unsigned char sha1[20];
+		int flag, cnt, i;
+		if (len < ofs + 21)
+			die("rev-cache too short"); 
+		memcpy(sha1, map + ofs, 20);
+		flag = map[ofs + 20];
+		ofs += 21;
+		cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
+		if (len < ofs + (flag & 0x7f) * 20)
+			die("rev-cache too short to have %d more parents",
+			    (flag & 0x7f));
+		if (dumpfile)
+			fprintf(dumpfile, "%s", sha1_to_hex(sha1));
+		if (!dry_run) {
+			ri = create_rev_cache(sha1);
+			ri->written = 1;
+			ri->parsed = 1;
+			if (!ri)
+				die("cannot create rev-cache for %s",
+				    sha1_to_hex(sha1));
+		}
+		i = 0;
+		if (flag & 0x80) {
+			if (!dry_run)
+				add_parent(ri, last_sha1);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			i++;
+		}
+		while (i++ < cnt) {
+			if (!dry_run)
+				add_parent(ri, map + ofs);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			ofs += 20;
+		}
+		if (dumpfile)
+			fprintf(dumpfile, "\n");
+		memcpy(last_sha1, sha1, 20);
+	}
+	if (ofs != len)
+		die("rev-cache truncated?");
+	munmap(map, len);
+	return 0;
+}
+
+int record_rev_cache(const unsigned char *sha1)
+{
+	unsigned char parent[20];
+	char type[20];
+	unsigned long size, ofs;
+	unsigned int cnt, i;
+	void *buf;
+	struct rev_cache *ri;
+
+	buf = read_sha1_file(sha1, type, &size);
+	if (!buf)
+		return 1; /* unavailable */
+	if (strcmp(type, "commit")) {
+		/* could be a tag or tree */
+		free(buf);
+		return 1;
+	}
+	ri = create_rev_cache(sha1);
+	if (ri->parsed)
+		return 0;
+
+	cnt = 0;
+	ofs = 46; /* "tree " + hex-sha1 + "\n" */
+	while (!memcmp(buf + ofs, "parent ", 7) &&
+	       !get_sha1_hex(buf + ofs + 7, parent)) {
+		ofs += 48;
+		cnt++;
+	}
+	if (cnt * 48 + 46 != ofs) {
+		free(buf);
+		return error("internal error in record_rev_cache");
+	}
+
+	ri = create_rev_cache(sha1);
+	ri->parsed = 1;
+
+	for (i = 0; i < cnt; i++) {
+		unsigned char parent_sha1[20];
+		
+		ofs = 46 + i * 48 + 7;
+		get_sha1_hex(buf + ofs, parent_sha1);
+		add_parent(ri, parent_sha1);
+		record_rev_cache(parent_sha1);
+	}
+	free(buf);
+	return 0;
+}
diff --git a/rev-cache.h b/rev-cache.h
new file mode 100644
--- /dev/null
+++ b/rev-cache.h
@@ -0,0 +1,31 @@
+#ifndef REV_CACHE_H
+#define REV_CACHE_H
+
+#define REV_CACHE_PATH "info/rev-cache"
+
+extern struct rev_cache {
+	struct rev_cache *head_list;
+	struct rev_list_elem *children;
+	struct rev_list_elem *parents;
+	struct rev_list_elem *parents_tail;
+	unsigned short num_parents;
+	unsigned short num_children;
+	unsigned int written : 1;
+	unsigned int parsed : 1;
+	unsigned int work : 30;
+	void *work_ptr;
+	unsigned char sha1[20];
+} **rev_cache;
+extern int nr_revs, alloc_revs;
+
+struct rev_list_elem {
+	struct rev_list_elem *next;
+	struct rev_cache *ri;
+};
+
+extern int find_rev_cache(const unsigned char *);
+extern int read_rev_cache(const char *, FILE *, int);
+extern int record_rev_cache(const unsigned char *);
+extern void write_rev_cache(const char *);
+
+#endif
diff --git a/show-rev-cache.c b/show-rev-cache.c
new file mode 100644
--- /dev/null
+++ b/show-rev-cache.c
@@ -0,0 +1,18 @@
+#include "cache.h"
+#include "rev-cache.h"
+
+static char *dump_rev_cache_usage =
+"git-dump-rev-cache <rev-cache-file>";
+
+int main(int ac, char **av)
+{
+	while (1 < ac && av[0][1] == '-') {
+		/* do flags here */
+		break;
+		ac--; av++;
+	}
+	if (ac != 2)
+		usage(dump_rev_cache_usage);
+
+	return read_rev_cache(av[1], stdout, 1);
+}
diff --git a/update-dumb-server.c b/update-dumb-server.c
new file mode 100644
--- /dev/null
+++ b/update-dumb-server.c
@@ -0,0 +1,153 @@
+#include "refs.h"
+#include "cache.h"
+#include "rev-cache.h"
+
+static FILE *inventory_file;
+static int verbose = 0;
+
+static int do_refs(const char *path, const unsigned char *sha1)
+{
+	/* path is like .git/refs/heads/master */
+	int pfxlen = 10; /* strlen(".git/refs/") */
+	fprintf(inventory_file, "%s %s\n", sha1_to_hex(sha1), path + pfxlen);
+	if (verbose)
+		fprintf(stderr, "inventory %s %s\n",
+			sha1_to_hex(sha1), path + pfxlen);
+	record_rev_cache(sha1);
+	return 0;
+}
+
+static int inventory(void)
+{
+	/* write names of $GIT_DIR/refs/?*?/?* files in
+	 * $GIT_DIR/info/inventory, and find the ancestry
+	 * information.
+	 */
+	char path[PATH_MAX];
+
+	strcpy(path, git_path("info/inventory"));
+	safe_create_leading_directories(path);
+	inventory_file = fopen(path, "w");
+	if (!inventory_file)
+		die("cannot create inventory file.");
+	for_each_ref(do_refs);
+	fclose(inventory_file);
+	return 0;
+}
+
+static int compare_pack_size(const void *a_, const void *b_)
+{
+	struct packed_git *const*a = a_;
+	struct packed_git *const*b = b_;
+	if ((*a)->pack_size < (*b)->pack_size)
+		return 1;
+	else if ((*a)->pack_size == (*b)->pack_size)
+		return 0;
+	return -1;
+}
+
+static int write_packs(void)
+{
+	/* write names of pack files under $GIT_OBJECT_DIRECTORY/pack
+	 * into $GIT_DIR/info/packs.
+	 */
+	struct packed_git *p;
+	char path[PATH_MAX];
+	FILE *packs_file;
+	int pfxlen = strlen(".git/objects/pack/");
+	struct packed_git **list;
+	int cnt, i;
+
+	for (cnt = 0, p = packed_git; p; p = p->next)
+		cnt++;
+	list = xmalloc(sizeof(*list) * cnt);
+	for (i = 0, p = packed_git; p; p = p->next)
+		list[i++] = p;
+	qsort(list, cnt, sizeof(*list), compare_pack_size);
+
+	strcpy(path, git_path("info/pack"));
+	safe_create_leading_directories(path);
+	packs_file = fopen(path, "w");
+	if (!packs_file)
+		return -1;
+	for (i = 0; i < cnt; i++) {
+		p = list[i];
+		fprintf(packs_file, "%lu %s\n",
+			p->pack_size, p->pack_name + pfxlen);
+		if (verbose)
+			fprintf(stderr, "pack %lu %s\n",
+				p->pack_size,
+				p->pack_name + pfxlen);
+	}
+	free(list);
+	fclose(packs_file);
+	return 0;
+}
+
+static int inventory_packs(void)
+{
+	struct packed_git *p;
+
+	for (p = packed_git; p; p = p->next) {
+		int nth, lim;
+		lim = num_packed_objects(p);
+		for (nth = 0; nth < lim; nth++) {
+			unsigned char sha1[20];
+			char type[20];
+			if (nth_packed_object_sha1(p, nth, sha1)) {
+				error("cannot read %dth object from pack %s",
+				      nth, p->pack_name);
+				continue;
+			}
+			if (sha1_object_info(sha1, type, NULL)) {
+				error("cannot find type of %s", sha1_to_hex(sha1));
+				continue;
+			}
+			if (strcmp(type, "commit"))
+				continue;
+			record_rev_cache(sha1);
+		}
+	}
+	return 0;
+}
+
+static const char *update_dumb_server_usage =
+"git-update-dumb-server [-v] [-a]";
+
+int main(int ac, char **av)
+{
+	char path[PATH_MAX];
+	int all_commits = 0;
+
+	while (1 < ac && av[1][0] == '-') {
+		if (!strcmp(av[1], "-v"))
+			verbose = 1;
+		else if (!strcmp(av[1], "-a"))
+			all_commits = 1;
+		else
+			usage(update_dumb_server_usage);
+		ac--; av++;
+	}
+
+	/* read existing rev-cache if any */
+	strcpy(path, git_path(REV_CACHE_PATH));
+	read_rev_cache(path, verbose ? stderr : NULL, 0);
+
+	/* read refs directory and find commit ancentry information */
+	inventory();
+
+	/* 
+	 * prepare info/pack file.
+	 * Note that we do prepare_packed_git() in case we ran in
+	 * an headless repository.
+	 */
+	prepare_packed_git();
+	write_packs();
+
+	if (all_commits)
+		inventory_packs();
+
+	/* update the rev-cache database by appending newly found one to it */
+	write_rev_cache(path);
+	return 0;
+}
------------

^ permalink raw reply	[relevance 9%]

* [PATCH] 2/7 Prepare for the next two patches
@ 2005-07-08 10:54 18% Bryan Larsen
  0 siblings, 0 replies; 200+ results
From: Bryan Larsen @ 2005-07-08 10:54 UTC (permalink / raw)
  To: git



Prepare for the next two patches.  This patch makes the first half of
write_sha1_file() and index_fd() externally visible.  The first half of
these two functions is basically just an SHA1 calculation, so there is
probably a better way to do this.  However, doing things this way makes
this patch and the subsequent patches minimally intrusive.

Signed-off-by: Bryan Larsen <bryan.larsen@gmail.com>
---

  cache.h        |    3 ++-
  sha1_file.c    |   13 +++++++++----
  update-cache.c |    2 +-
  write-blob.c   |    2 +-
  4 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -139,7 +139,7 @@ extern int remove_cache_entry_at(int pos
  extern int remove_file_from_cache(char *path);
  extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
  extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int 
info_only);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);

  struct cache_file {
@@ -169,6 +169,7 @@ extern int sha1_object_info(const unsign
  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(void *buf, unsigned long len, const char 
*type, unsigned char *return_sha1);
+extern char *write_sha1_file_prepare(void *buf, unsigned long len, 
const char *type, unsigned char *sha1, unsigned char *hdr, int *hdrlen);

  extern int check_sha1_signature(const unsigned char *sha1, void *buf, 
unsigned long size, const char *type);

diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1084,7 +1084,7 @@ void *read_object_with_reference(const u
  	}
  }

-static char *write_sha1_file_prepare(void *buf,
+char *write_sha1_file_prepare(void *buf,
  				     unsigned long len,
  				     const char *type,
  				     unsigned char *sha1,
@@ -1283,12 +1283,14 @@ int has_sha1_file(const unsigned char *s
  	return find_pack_entry(sha1, &e);
  }

-int index_fd(unsigned char *sha1, int fd, struct stat *st)
+int index_fd(unsigned char *sha1, int fd, struct stat *st, int info_only)
  {
  	unsigned long size = st->st_size;
  	void *buf;
  	int ret;
-
+	unsigned char hdr[50];
+	int hdrlen;
+	
  	buf = "";
  	if (size)
  		buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -1296,7 +1298,10 @@ int index_fd(unsigned char *sha1, int fd
  	if ((int)(long)buf == -1)
  		return -1;

-	ret = write_sha1_file(buf, size, "blob", sha1);
+	if (info_only) {
+		(void) write_sha1_file_prepare(buf, size, "blob", sha1, hdr, &hdrlen);
+		ret = 0;
+	} else ret = write_sha1_file(buf, size, "blob", sha1);
  	if (size)
  		munmap(buf, size);
  	return ret;
diff --git a/update-cache.c b/update-cache.c
--- a/update-cache.c
+++ b/update-cache.c
@@ -68,7 +68,7 @@ static int add_file_to_cache(char *path)
  		fd = open(path, O_RDONLY);
  		if (fd < 0)
  			return -1;
-		if (index_fd(ce->sha1, fd, &st) < 0)
+		if (index_fd(ce->sha1, fd, &st, 0) < 0)
  			return -1;
  		break;
  	case S_IFLNK:
diff --git a/write-blob.c b/write-blob.c
--- a/write-blob.c
+++ b/write-blob.c
@@ -17,7 +17,7 @@ int main(int argc, char **argv)
  		fd = open(path, O_RDONLY);
  		if (fd < 0 ||
  		    fstat(fd, &st) < 0 ||
-		    index_fd(sha1, fd, &st) < 0)
+		    index_fd(sha1, fd, &st, 0) < 0)
  			die("Unable to add blob %s to database", path);
  		printf("%s\n", sha1_to_hex(sha1));
  	}


\f

^ permalink raw reply	[relevance 18%]

* Re: patches to support working without the object database
  @ 2005-07-08 18:36 14% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-08 18:36 UTC (permalink / raw)
  To: Bryan Larsen; +Cc: git

>>>>> "BL" == Bryan Larsen <bryan.larsen@gmail.com> writes:

BL> Sometimes you may wish to keep an audit trail of what changed, where,
BL> and by whom.  You do not need to know the exact details of the change,
BL> and the files are so large that keeping an extra copy of the data in
BL> the object database cache is prohibitively expensive.

I am basically OK with this patch series, except I have one
minor problem about interface detail, and more seriously, that
the patch is whitespace mangled and would not apply.  E.g.

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -139,7 +139,7 @@ extern int remove_cache_entry_at(int pos
  extern int remove_file_from_cache(char *path);
  extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
  extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int 
info_only);

Notice the "info_only" folded, and other unchanged lines
indented by two spaces instead of one?

Please retry.  I especially like what [PATCH 4/7] does and do
not want to see this patch go to dustbin due to technicalities.

Also please make sure that core GIT part patch applies against
Linus tip (especially [PATCH 2/7]) as well. I think it does, but
please double check.

I would also suggest adding the same --info-only logic to
write-blob (perhaps give it a short and sweet name like "-n"),
in order to get the hash information out of it without actually
registering the blob.

This would make things more useful in general.  One immediate
benefit of it is that we would have a standalone checksum
program we can reuse, by just saying "write-blob -n".  Once you
have it, you _could_ even drop --info-only from git-update-cache
and use normal --cacheinfo instead.

While you are at it, you might also want to add an option to
write-blob to specify the type of the object you are hashing, so
that would make [*1*]:

    git-write-blob [-n] [-t <type>] <file>...

One way to do this would be to add "const char *type" argument
to index_fd(), which is usually "blob" in the traditional use.
Then, the change to index_fd() would become:

-	ret = write_sha1_file(buf, size, "blob", sha1);
+	if (info_only) {
+		(void) write_sha1_file_prepare(buf, size, type, sha1, hdr, &hdrlen);
+		ret = 0;
+	} else ret = write_sha1_file(buf, size, type, sha1);

But first let's get the whitespace mangling fixed up ;-).

[Footnote]

*1* I considered this instead:

    git-write-blob [-n | -t <type>] <file>...

which means that if you specify type then -n is implied.  But
making -t independent would let you have inverse of
git-cat-file; a silly example:

    $ git-cat-file -t $FOO
    tree
    $ git-cat-file tree $FOO >tmp1
    $ FOO1=$(git-write-blob -t tree tmp1)

If we go this route, we may also want to rename it to
write-object, but I would want to have it as a separate patch
after this series settles down.

^ permalink raw reply	[relevance 14%]

* [PATCH 1/2] Management of packs not yet installed
  @ 2005-07-10 19:55 19% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-07-10 19:55 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Petr Baudis

Support for parsing index files without pack files, installing pack
files while running, and checking what pack files are available.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

---
commit b686d7a0377c24e05dbed0dafe909dda6c3dfb48
tree ce285b1a0adb4f8d415f72668a77bc1f1f92e1e1
parent 167a4a3308f4a1606e268c2204c98d6999046ae0
author Daniel Barkalow <barkalow@iabervon.org> 1121024924 -0400
committer Daniel Barkalow <barkalow@silva-tulga.(none)> 1121024924 -0400

Index: cache.h
===================================================================
--- dbae854c7c91182c8a124d0b85d802945d1c6223/cache.h  (mode:100644 sha1:84d43d366c6145a30865aa65d92ada88ab95bb9f)
+++ ce285b1a0adb4f8d415f72668a77bc1f1f92e1e1/cache.h  (mode:100644 sha1:719a77dfabb24e58abd21b7f3a4b846a114e000a)
@@ -161,6 +161,8 @@
 extern char *mkpath(const char *fmt, ...);
 extern char *git_path(const char *fmt, ...);
 extern char *sha1_file_name(const unsigned char *sha1);
+extern char *sha1_pack_name(const unsigned char *sha1);
+extern char *sha1_pack_index_name(const unsigned char *sha1);
 
 int safe_create_leading_directories(char *path);
 
@@ -189,6 +191,9 @@
 extern int has_sha1_pack(const unsigned char *sha1);
 extern int has_sha1_file(const unsigned char *sha1);
 
+extern int has_pack_file(const unsigned char *sha1);
+extern int has_pack_index(const unsigned char *sha1);
+
 /* Convert to/from hex/sha1 representation */
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
@@ -260,6 +265,7 @@
 	void *pack_base;
 	unsigned int pack_last_used;
 	unsigned int pack_use_cnt;
+	unsigned char sha1[20];
 	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
 } *packed_git;
 
@@ -274,7 +280,14 @@
 extern int path_match(const char *path, int nr, char **match);
 extern int get_ack(int fd, unsigned char *result_sha1);
 
+extern struct packed_git *parse_pack_index(unsigned char *sha1);
+
 extern void prepare_packed_git(void);
+extern void install_packed_git(struct packed_git *pack);
+
+struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+				  struct packed_git *packs);
+
 extern int use_packed_git(struct packed_git *);
 extern void unuse_packed_git(struct packed_git *);
 extern struct packed_git *add_packed_git(char *, int);
Index: sha1_file.c
===================================================================
--- dbae854c7c91182c8a124d0b85d802945d1c6223/sha1_file.c  (mode:100644 sha1:b2914dd2ea629ae974fd4b4c272e77cb04e5c0e0)
+++ ce285b1a0adb4f8d415f72668a77bc1f1f92e1e1/sha1_file.c  (mode:100644 sha1:27136fdba0fbf2dd943f2634cb49660cdbf95ec4)
@@ -200,6 +200,56 @@
 	return base;
 }
 
+char *sha1_pack_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.pack", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	
+	return base;
+}
+
+char *sha1_pack_index_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.idx", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	
+	return base;
+}
+
 struct alternate_object_database *alt_odb;
 
 /*
@@ -360,6 +410,14 @@
 
 int use_packed_git(struct packed_git *p)
 {
+	if (!p->pack_size) {
+		struct stat st;
+		// We created the struct before we had the pack
+		stat(p->pack_name, &st);
+		if (!S_ISREG(st.st_mode))
+			die("packfile %s not a regular file", p->pack_name);
+		p->pack_size = st.st_size;
+	}
 	if (!p->pack_base) {
 		int fd;
 		struct stat st;
@@ -387,8 +445,10 @@
 		 * this is cheap.
 		 */
 		if (memcmp((char*)(p->index_base) + p->index_size - 40,
-			   p->pack_base + p->pack_size - 20, 20))
+			   p->pack_base + p->pack_size - 20, 20)) {
+			      
 			die("packfile %s does not match index.", p->pack_name);
+		}
 	}
 	p->pack_last_used = pack_used_ctr++;
 	p->pack_use_cnt++;
@@ -426,6 +486,37 @@
 	return p;
 }
 
+struct packed_git *parse_pack_index(unsigned char *sha1)
+{
+	struct packed_git *p;
+	unsigned long idx_size;
+	void *idx_map;
+	char *path = sha1_pack_index_name(sha1);
+
+	if (check_packed_git_idx(path, &idx_size, &idx_map))
+		return NULL;
+
+	path = sha1_pack_name(sha1);
+
+	p = xmalloc(sizeof(*p) + strlen(path) + 2);
+	strcpy(p->pack_name, path);
+	p->index_size = idx_size;
+	p->pack_size = 0;
+	p->index_base = idx_map;
+	p->next = NULL;
+	p->pack_base = NULL;
+	p->pack_last_used = 0;
+	p->pack_use_cnt = 0;
+	memcpy(p->sha1, sha1, 20);
+	return p;
+}
+
+void install_packed_git(struct packed_git *pack)
+{
+	pack->next = packed_git;
+	packed_git = pack;
+}
+
 static void prepare_packed_git_one(char *objdir)
 {
 	char path[PATH_MAX];
@@ -999,6 +1090,20 @@
 	return 0;
 }
 
+struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+				  struct packed_git *packs)
+{
+	struct packed_git *p;
+	struct pack_entry e;
+
+	for (p = packs; p; p = p->next) {
+		if (find_pack_entry_one(sha1, &e, p))
+			return p;
+	}
+	return NULL;
+	
+}
+
 int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
 {
 	int status;
@@ -1283,6 +1388,22 @@
 	return 0;
 }
 
+int has_pack_index(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_index_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
+int has_pack_file(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
 int has_sha1_pack(const unsigned char *sha1)
 {
 	struct pack_entry e;

^ permalink raw reply	[relevance 19%]

* [PATCH 2/2] Remove map_sha1_file
    2005-07-10 22:25 20% ` [PATCH 1/2] write_sha1_to_fd() Daniel Barkalow
@ 2005-07-10 22:27 22% ` Daniel Barkalow
  1 sibling, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-07-10 22:27 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

Remove map_sha1_file(), now unused.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
commit c21a02262f770a25b005378e06354e582aa1bfd8
tree 7ac9fabe666f00f37572e7b349fdb859bf8a6491
parent 264ff9f3dcde5553728b34fa08e04643b2b55946
author Daniel Barkalow <barkalow@iabervon.org> 1121033599 -0400
committer Daniel Barkalow <barkalow@silva-tulga.(none)> 1121033599 -0400

Index: cache.h
===================================================================
--- 353fe33ae9c7265d7b685bca864d657e3efe2849/cache.h  (mode:100644 sha1:38dac6d6a413f1c788e5331ef4741fc15d72d9bd)
+++ 7ac9fabe666f00f37572e7b349fdb859bf8a6491/cache.h  (mode:100644 sha1:11ba95c8aa9202fa3b1a3cbc07bc976641cd1908)
@@ -167,7 +167,6 @@
 int safe_create_leading_directories(char *path);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
-extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
 extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
Index: sha1_file.c
===================================================================
--- 353fe33ae9c7265d7b685bca864d657e3efe2849/sha1_file.c  (mode:100644 sha1:08560b2c7a6dff400a46160501c247081f9bb4c7)
+++ 7ac9fabe666f00f37572e7b349fdb859bf8a6491/sha1_file.c  (mode:100644 sha1:e082f2e6cb985caca11979311c291aa51d6c37fd)
@@ -578,8 +578,7 @@
 }
 
 static void *map_sha1_file_internal(const unsigned char *sha1,
-				    unsigned long *size,
-				    int say_error)
+				    unsigned long *size)
 {
 	struct stat st;
 	void *map;
@@ -587,8 +586,6 @@
 	char *filename = find_sha1_file(sha1, &st);
 
 	if (!filename) {
-		if (say_error)
-			error("cannot map sha1 file %s", sha1_to_hex(sha1));
 		return NULL;
 	}
 
@@ -602,8 +599,6 @@
 				break;
 		/* Fallthrough */
 		case 0:
-			if (say_error)
-				perror(filename);
 			return NULL;
 		}
 
@@ -620,11 +615,6 @@
 	return map;
 }
 
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
-{
-	return map_sha1_file_internal(sha1, size, 1);
-}
-
 int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size)
 {
 	/* Get the data stream */
@@ -1112,7 +1102,7 @@
 	z_stream stream;
 	char hdr[128];
 
-	map = map_sha1_file_internal(sha1, &mapsize, 0);
+	map = map_sha1_file_internal(sha1, &mapsize);
 	if (!map) {
 		struct pack_entry e;
 
@@ -1151,7 +1141,7 @@
 	unsigned long mapsize;
 	void *map, *buf;
 
-	map = map_sha1_file_internal(sha1, &mapsize, 0);
+	map = map_sha1_file_internal(sha1, &mapsize);
 	if (map) {
 		buf = unpack_sha1_file(map, mapsize, type, size);
 		munmap(map, mapsize);
@@ -1331,7 +1321,7 @@
 	ssize_t size;
 	unsigned long objsize;
 	int posn = 0;
-	char *buf = map_sha1_file_internal(sha1, &objsize, 0);
+	char *buf = map_sha1_file_internal(sha1, &objsize);
 	z_stream stream;
 	if (!buf) {
 		unsigned char *unpacked;

^ permalink raw reply	[relevance 22%]

* [PATCH 1/2] write_sha1_to_fd()
  @ 2005-07-10 22:25 20% ` Daniel Barkalow
  2005-07-10 22:27 22% ` [PATCH 2/2] Remove map_sha1_file Daniel Barkalow
  1 sibling, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-07-10 22:25 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

Add write_sha1_to_fd(), which writes an object to a file descriptor. This
includes support for unpacking it and recompressing it.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
commit 264ff9f3dcde5553728b34fa08e04643b2b55946
tree 353fe33ae9c7265d7b685bca864d657e3efe2849
parent c3eb461762b1d65e424fc4ede6a1d4f3e0a679f7
author Daniel Barkalow <barkalow@iabervon.org> 1121033477 -0400
committer Daniel Barkalow <barkalow@silva-tulga.(none)> 1121033477 -0400

Index: cache.h
===================================================================
--- 545ef8191b517b7f9e4ea558edaf526038ed1895/cache.h  (mode:100644 sha1:719a77dfabb24e58abd21b7f3a4b846a114e000a)
+++ 353fe33ae9c7265d7b685bca864d657e3efe2849/cache.h  (mode:100644 sha1:38dac6d6a413f1c788e5331ef4741fc15d72d9bd)
@@ -187,6 +187,7 @@
 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 write_sha1_to_fd(int fd, const unsigned char *sha1);
 
 extern int has_sha1_pack(const unsigned char *sha1);
 extern int has_sha1_file(const unsigned char *sha1);
Index: sha1_file.c
===================================================================
--- 545ef8191b517b7f9e4ea558edaf526038ed1895/sha1_file.c  (mode:100644 sha1:27136fdba0fbf2dd943f2634cb49660cdbf95ec4)
+++ 353fe33ae9c7265d7b685bca864d657e3efe2849/sha1_file.c  (mode:100644 sha1:08560b2c7a6dff400a46160501c247081f9bb4c7)
@@ -1326,6 +1326,65 @@
 	return 0;
 }
 
+int write_sha1_to_fd(int fd, const unsigned char *sha1)
+{
+	ssize_t size;
+	unsigned long objsize;
+	int posn = 0;
+	char *buf = map_sha1_file_internal(sha1, &objsize, 0);
+	z_stream stream;
+	if (!buf) {
+		unsigned char *unpacked;
+		unsigned long len;
+		char type[20];
+		char hdr[50];
+		int hdrlen;
+		// need to unpack and recompress it by itself
+		unpacked = read_packed_sha1(sha1, type, &len);
+
+		hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+
+		/* Set it up */
+		memset(&stream, 0, sizeof(stream));
+		deflateInit(&stream, Z_BEST_COMPRESSION);
+		size = deflateBound(&stream, len + hdrlen);
+		buf = xmalloc(size);
+
+		/* Compress it */
+		stream.next_out = buf;
+		stream.avail_out = size;
+		
+		/* First header.. */
+		stream.next_in = hdr;
+		stream.avail_in = hdrlen;
+		while (deflate(&stream, 0) == Z_OK)
+			/* nothing */;
+
+		/* Then the data itself.. */
+		stream.next_in = unpacked;
+		stream.avail_in = len;
+		while (deflate(&stream, Z_FINISH) == Z_OK)
+			/* nothing */;
+		deflateEnd(&stream);
+		
+		objsize = stream.total_out;
+	}
+
+	do {
+		size = write(fd, buf + posn, objsize - posn);
+		if (size <= 0) {
+			if (!size) {
+				fprintf(stderr, "write closed");
+			} else {
+				perror("write ");
+			}
+			return -1;
+		}
+		posn += size;
+	} while (posn < objsize);
+	return 0;
+}
+
 int write_sha1_from_fd(const unsigned char *sha1, int fd)
 {
 	char *filename = sha1_file_name(sha1);
Index: ssh-push.c
===================================================================
--- 545ef8191b517b7f9e4ea558edaf526038ed1895/ssh-push.c  (mode:100644 sha1:090d6f9f8fbde2d736ac5bf563415b0fa402b5aa)
+++ 353fe33ae9c7265d7b685bca864d657e3efe2849/ssh-push.c  (mode:100644 sha1:aac70af514e0dc5507fa4997ebad54352c973215)
@@ -7,13 +7,13 @@
 static unsigned char local_version = 1;
 static unsigned char remote_version = 0;
 
+static int verbose = 0;
+
 static int serve_object(int fd_in, int fd_out) {
 	ssize_t size;
-	int posn = 0;
 	unsigned char sha1[20];
-	unsigned long objsize;
-	void *buf;
 	signed char remote;
+	int posn = 0;
 	do {
 		size = read(fd_in, sha1 + posn, 20 - posn);
 		if (size < 0) {
@@ -25,12 +25,12 @@
 		posn += size;
 	} while (posn < 20);
 	
-	/* fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1)); */
+	if (verbose)
+		fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1));
+
 	remote = 0;
 	
-	buf = map_sha1_file(sha1, &objsize);
-	
-	if (!buf) {
+	if (!has_sha1_file(sha1)) {
 		fprintf(stderr, "git-ssh-push: could not find %s\n", 
 			sha1_to_hex(sha1));
 		remote = -1;
@@ -41,20 +41,7 @@
 	if (remote < 0)
 		return 0;
 	
-	posn = 0;
-	do {
-		size = write(fd_out, buf + posn, objsize - posn);
-		if (size <= 0) {
-			if (!size) {
-				fprintf(stderr, "git-ssh-push: write closed");
-			} else {
-				perror("git-ssh-push: write ");
-			}
-			return -1;
-		}
-		posn += size;
-	} while (posn < objsize);
-	return 0;
+	return write_sha1_to_fd(fd_out, sha1);
 }
 
 static int serve_version(int fd_in, int fd_out)
@@ -76,6 +63,10 @@
 			return -1;
 		posn++;
 	} while (ref[posn - 1]);
+
+	if (verbose)
+		fprintf(stderr, "Serving %s\n", ref);
+
 	if (get_ref_sha1(ref, sha1))
 		remote = -1;
 	write(fd_out, &remote, 1);

^ permalink raw reply	[relevance 20%]

* [PATCH] tagger id
  @ 2005-07-12  4:39  8%         ` Eric W. Biederman
  0 siblings, 0 replies; 200+ results
From: Eric W. Biederman @ 2005-07-12  4:39 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List


This patch adds a command git-id for use on
the command line to see what git will set your id too,
and for use in scripts (git-tag-script) so they can get your git id.

The common code for computing the git-id is moved to ident.c

Fix parse_date to not mind being passed a constant date
to parse.

The code to compute the identifier has been restructured
to at least make a reasonable stab at error handling.  The
original version had so many unchecked return values it was
just scary to think about.

Eric

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-stages git-rev-parse git-patch-id git-pack-objects \
 	git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
 	git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
-	git-show-index
+	git-show-index git-id
 
 all: $(PROG)
 
@@ -57,7 +57,7 @@ install: $(PROG) $(SCRIPTS)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
-	 epoch.o refs.o csum-file.o pack-check.o pkt-line.o connect.o
+	 epoch.o refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h \
 	pack.h pkt-line.h refs.h
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -208,9 +208,14 @@ extern void *read_object_with_reference(
 					unsigned char *sha1_ret);
 
 const char *show_date(unsigned long time, int timezone);
-void parse_date(char *date, char *buf, int bufsize);
+void parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
 
+int git_ident(char *buf, size_t bufsize,
+	const char *env_name, const char *env_email, const char *env_date);
+int git_committer_ident(char *buf, size_t bufsize);
+int git_author_ident(char *buf, size_t bufsize);
+
 static inline void *xmalloc(size_t size)
 {
 	void *ret = malloc(size);
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -5,9 +5,10 @@
  */
 #include "cache.h"
 
-#include <pwd.h>
 #include <time.h>
 #include <ctype.h>
+#include <string.h>
+#include <errno.h>
 
 #define BLOCKING (1ul << 14)
 
@@ -45,39 +46,6 @@ static void add_buffer(char **bufp, unsi
 	memcpy(buf + size, one_line, len);
 }
 
-static void remove_special(char *p)
-{
-	char c;
-	char *dst = p, *src = p;
-
-	for (;;) {
-		c = *src;
-		src++;
-		switch(c) {
-		case '\n': case '<': case '>':
-			continue;
-		}
-		*dst++ = c;
-		if (!c)
-			break;
-	}
-
-	/*
-	 * Go back, and remove crud from the end: some people
-	 * have commas etc in their gecos field
-	 */
-	dst--;
-	while (--dst >= p) {
-		unsigned char c = *dst;
-		switch (c) {
-		case ',': case ';': case '.':
-			*dst = 0;
-			continue;
-		}
-		break;
-	}
-}
-
 static void check_valid(unsigned char *sha1, const char *expect)
 {
 	void *buf;
@@ -114,16 +82,13 @@ static int new_parent(int idx)
 
 int main(int argc, char **argv)
 {
-	int i, len;
+	int i;
 	int parents = 0;
 	unsigned char tree_sha1[20];
 	unsigned char commit_sha1[20];
-	char *gecos, *realgecos, *commitgecos;
-	char *email, *commitemail, realemail[1000];
-	char date[50], realdate[50];
-	char *audate, *cmdate;
+	char committer[1000];
+	char author[1000];
 	char comment[1000];
-	struct passwd *pw;
 	char *buffer;
 	unsigned int size;
 
@@ -142,35 +107,12 @@ int main(int argc, char **argv)
 	}
 	if (!parents)
 		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
-	pw = getpwuid(getuid());
-	if (!pw)
-		die("You don't exist. Go away!");
-	realgecos = pw->pw_gecos;
-	len = strlen(pw->pw_name);
-	memcpy(realemail, pw->pw_name, len);
-	realemail[len] = '@';
-	gethostname(realemail+len+1, sizeof(realemail)-len-1);
-	if (!strchr(realemail+len+1, '.')) {
-		strcat(realemail, ".");
-		getdomainname(realemail+strlen(realemail), sizeof(realemail)-strlen(realemail)-1);
+	if (git_author_ident(author, sizeof(author)) < 0) {
+		die("Bad author! %s", strerror(errno));
+	}
+	if (git_committer_ident(committer, sizeof(committer)) < 0) {
+		die("Bad Committer! %s", strerror(errno));
 	}
-
-	datestamp(realdate, sizeof(realdate));
-	strcpy(date, realdate);
-
-	commitgecos = gitenv("GIT_COMMITTER_NAME") ? : realgecos;
-	commitemail = gitenv("GIT_COMMITTER_EMAIL") ? : realemail;
-	gecos = gitenv("GIT_AUTHOR_NAME") ? : realgecos;
-	email = gitenv("GIT_AUTHOR_EMAIL") ? : realemail;
-	audate = gitenv("GIT_AUTHOR_DATE");
-	if (audate)
-		parse_date(audate, date, sizeof(date));
-	cmdate = gitenv("GIT_COMMITTER_DATE");
-	if (cmdate)
-		parse_date(cmdate, realdate, sizeof(realdate));
-
-	remove_special(gecos); remove_special(realgecos); remove_special(commitgecos);
-	remove_special(email); remove_special(realemail); remove_special(commitemail);
 
 	init_buffer(&buffer, &size);
 	add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
@@ -184,8 +126,8 @@ int main(int argc, char **argv)
 		add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
 
 	/* Person/date information */
-	add_buffer(&buffer, &size, "author %s <%s> %s\n", gecos, email, date);
-	add_buffer(&buffer, &size, "committer %s <%s> %s\n\n", commitgecos, commitemail, realdate);
+	add_buffer(&buffer, &size, "author %s <%s> %s\n", author);
+	add_buffer(&buffer, &size, "committer %s <%s> %s\n\n", committer);
 
 	/* And add the comment */
 	while (fgets(comment, sizeof(comment), stdin) != NULL)
diff --git a/date.c b/date.c
--- a/date.c
+++ b/date.c
@@ -224,7 +224,7 @@ static int is_date(int year, int month, 
 	return 0;
 }
 
-static int match_multi_number(unsigned long num, char c, char *date, char *end, struct tm *tm)
+static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
 {
 	long num2, num3;
 
@@ -270,7 +270,7 @@ static int match_multi_number(unsigned l
 /*
  * We've seen a digit. Time? Year? Date? 
  */
-static int match_digit(char *date, struct tm *tm, int *offset, int *tm_gmt)
+static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
 {
 	int n;
 	char *end;
@@ -361,7 +361,7 @@ static int match_digit(char *date, struc
 	return n;
 }
 
-static int match_tz(char *date, int *offp)
+static int match_tz(const char *date, int *offp)
 {
 	char *end;
 	int offset = strtoul(date+1, &end, 10);
@@ -388,7 +388,7 @@ static int match_tz(char *date, int *off
 
 /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
    (i.e. English) day/month names, and it doesn't work correctly with %z. */
-void parse_date(char *date, char *result, int maxlen)
+void parse_date(const char *date, char *result, int maxlen)
 {
 	struct tm tm;
 	int offset, sign, tm_gmt;
diff --git a/git-tag-script b/git-tag-script
--- a/git-tag-script
+++ b/git-tag-script
@@ -7,6 +7,7 @@ name="$1"
 
 object=${2:-$(cat "$GIT_DIR"/HEAD)}
 type=$(git-cat-file -t $object) || exit 1
+tagger=$(git-id) || exit 1
 
 ( echo "#"
   echo "# Write a tag message"
@@ -17,8 +18,9 @@ grep -v '^#' < .editmsg | git-stripspace
 
 [ -s .tagmsg ] || exit
 
-( echo -e "object $object\ntype $type\ntag $name\n"; cat .tagmsg ) > .tmp-tag
+( echo -e "object $object\ntype $type\ntag $name\ntagger $tagger\n"; cat .tagmsg ) > .tmp-tag
 rm -f .tmp-tag.asc .tagmsg
 gpg -bsa .tmp-tag && cat .tmp-tag.asc >> .tmp-tag
+mkdir -p "$GIT_DIR/refs/tags"
 git-mktag < .tmp-tag > "$GIT_DIR/refs/tags/$name"
 #rm .tmp-tag .tmp-tag.sig
diff --git a/id.c b/id.c
new file mode 100644
--- /dev/null
+++ b/id.c
@@ -0,0 +1,36 @@
+#include "cache.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+static char *id_usage = "git-id [--author | --committer]";
+
+int main(int argc, char **argv)
+{
+	char buf[1000];
+	int (*ident)(char *buf, size_t bufsize);
+	int i;
+
+	ident = git_committer_ident;
+	for(i = 1; i < argc; i++) {
+		char *arg = argv[i];
+		if (strcmp(arg, "--author") == 0) {
+			ident = git_author_ident;
+		}
+		else if (strcmp(arg, "--committer") == 0) {
+			ident = git_committer_ident;
+		}
+		else {
+			usage(id_usage);
+		}
+	}
+
+
+	if (ident(buf, sizeof(buf)) < 0) {
+		die("Cannot resolve ident: %s\n", strerror(errno));
+	}
+
+	printf("%s\n", buf);
+
+	return 0;
+}
diff --git a/ident.c b/ident.c
new file mode 100644
--- /dev/null
+++ b/ident.c
@@ -0,0 +1,144 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Eric Biederman, 2005
+ */
+#include "cache.h"
+
+#include <pwd.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MAX_NAME 1000
+#define MAX_EMAIL 1000
+#define MAX_DATE 50
+static void remove_special(char *p)
+{
+	char c;
+	char *dst = p, *src = p;
+
+	for (;;) {
+		c = *src;
+		src++;
+		switch(c) {
+		case '\n': case '<': case '>':
+			continue;
+		}
+		*dst++ = c;
+		if (!c)
+			break;
+	}
+
+	/*
+	 * Go back, and remove crud from the end: some people
+	 * have commas etc in their gecos field
+	 */
+	dst--;
+	while (--dst >= p) {
+		unsigned char c = *dst;
+		switch (c) {
+		case ',': case ';': case '.':
+			*dst = 0;
+			continue;
+		}
+		break;
+	}
+}
+
+int git_ident(char *buf, size_t bufsize,
+	const char *env_name, const char *env_email, const char *env_date)
+{
+	int len;
+	char name[MAX_NAME];
+	char email[MAX_EMAIL];
+	char date[MAX_DATE];
+	struct passwd *pw;
+	int count;
+	
+	/* Lookup the user in the password file */
+	pw = getpwuid(getuid());
+	if (!pw)
+		return -1;
+
+	/* Get the users full name */
+	strncpy(name, pw->pw_gecos, sizeof(name));
+	name[sizeof(name) - 1] = '\0';
+
+	/* Get the email address with error handling */
+	len = strlen(pw->pw_name);
+	if (len >= (sizeof(email) - 2)) {
+		/* Bad user name length */
+		errno = ENOMEM;
+		return -1;
+	}
+	memcpy(email, pw->pw_name, len);
+	email[len] = '@';
+	email[len + 1] = '\0';
+
+	if (gethostname(email+len+1, sizeof(email)-len-1) < 0) {
+		return -1;
+	}
+	email[sizeof(email) - 1] = '\0';
+	len = strlen(email);
+	if (!strchr(email+len+1, '.')) {
+		if (len >= (sizeof(email) - 1)) {
+			errno = ENOMEM;
+			return -1;
+		}
+		email[len] = '.';
+		if (getdomainname(email+len+1, sizeof(email) - len - 1) < 0) {
+			return -1;
+		}
+	}
+	/* Get the date */
+	datestamp(date, sizeof(date));
+
+	if (env_name) {
+		strncpy(name, env_name, sizeof(name));
+		name[sizeof(name) - 1] = '\0';
+	}
+	if (env_email) {
+		strncpy(email, env_email, sizeof(email));
+		email[sizeof(email) - 1] = '\0';
+	}
+	if (env_date) {
+		parse_date(env_date, date, sizeof(date));
+	}
+	remove_special(name);
+	remove_special(email);
+	count = snprintf(buf, bufsize, "%s <%s> %s", name, email, date);
+	if (count > bufsize) {
+		errno = ENOMEM;
+		return -1;
+	}
+	if (count < 0) {
+		return -1;
+	}
+	return 0;
+}
+
+int git_committer_ident(char *buf, size_t bufsize)
+{
+	const char *name;
+	const char *email;
+	const char *date;
+	name  = gitenv("GIT_COMMITTER_NAME");
+	email = gitenv("GIT_COMMITTER_EMAIL");
+	date  = gitenv("GIT_COMMITTER_DATE");
+	return git_ident(buf, bufsize, name, email, date);
+}
+
+int git_author_ident(char *buf, size_t bufsize)
+{
+	const char *name;
+	const char *email;
+	const char *date;
+	name  = gitenv("GIT_AUTHOR_NAME");
+	email = gitenv("GIT_AUTHOR_EMAIL");
+	date  = gitenv("GIT_AUTHOR_DATE");
+	return git_ident(buf, bufsize, name, email, date);
+}
+
diff --git a/mktag.c b/mktag.c
--- a/mktag.c
+++ b/mktag.c
@@ -42,7 +42,7 @@ static int verify_tag(char *buffer, unsi
 	int typelen;
 	char type[20];
 	unsigned char sha1[20];
-	const char *object, *type_line, *tag_line;
+	const char *object, *type_line, *tag_line, *tagger_line;
 
 	if (size < 64 || size > MAXSIZE-1)
 		return -1;
@@ -92,6 +92,12 @@ static int verify_tag(char *buffer, unsi
 		return -1;
 	}
 
+	/* Verify the tagger line */
+	tagger_line = tag_line;
+	
+	if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n'))
+		return -1;
+
 	/* The actual stuff afterwards we don't care about.. */
 	return 0;
 }
@@ -119,7 +125,7 @@ int main(int argc, char **argv)
 		size += ret;
 	}
 
-	// Verify it for some basic sanity: it needs to start with "object <sha1>\ntype "
+	// Verify it for some basic sanity: it needs to start with "object <sha1>\ntype\ntagger "
 	if (verify_tag(buffer, size) < 0)
 		die("invalid tag signature file");
 

^ permalink raw reply	[relevance 8%]

* [PATCH 1/6] Move git_author_info and git_commiter_info to ident.c
@ 2005-07-15  0:50 18% Eric W. Biederman
  0 siblings, 0 replies; 200+ results
From: Eric W. Biederman @ 2005-07-15  0:50 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git


Moving these functions allows all of the logic for figuring out what
these values are to be shared between programs.
---

 cache.h       |    2 ++
 commit-tree.c |   10 ----------
 ident.c       |   10 ++++++++++
 3 files changed, 12 insertions(+), 10 deletions(-)

c6f1b65729df142a8968441ca441f6b69926127a
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -223,6 +223,8 @@ void datestamp(char *buf, int bufsize);
 
 extern int setup_ident(void);
 extern char *get_ident(const char *name, const char *email, const char *date_str);
+extern char *git_author_info(void);
+extern char *git_committer_info(void);
 
 static inline void *xmalloc(size_t size)
 {
diff --git a/commit-tree.c b/commit-tree.c
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -79,16 +79,6 @@ static int new_parent(int idx)
 	return 1;
 }
 
-static char *git_author_info(void)
-{
-	return get_ident(gitenv("GIT_AUTHOR_NAME"), gitenv("GIT_AUTHOR_EMAIL"), gitenv("GIT_AUTHOR_DATE"));
-}
-
-static char *git_committer_info(void)
-{
-	return get_ident(gitenv("GIT_COMMITTER_NAME"), gitenv("GIT_COMMITTER_EMAIL"), gitenv("GIT_COMMITTER_DATE"));
-}
-
 int main(int argc, char **argv)
 {
 	int i;
diff --git a/ident.c b/ident.c
--- a/ident.c
+++ b/ident.c
@@ -136,3 +136,13 @@ char *get_ident(const char *name, const 
 	buffer[i] = 0;
 	return buffer;
 }
+
+char *git_author_info(void)
+{
+	return get_ident(gitenv("GIT_AUTHOR_NAME"), gitenv("GIT_AUTHOR_EMAIL"), gitenv("GIT_AUTHOR_DATE"));
+}
+
+char *git_committer_info(void)
+{
+	return get_ident(gitenv("GIT_COMMITTER_NAME"), gitenv("GIT_COMMITTER_EMAIL"), gitenv("GIT_COMMITTER_DATE"));
+}

^ permalink raw reply	[relevance 18%]

* [PATCH 4/6] Add update-server-info.
@ 2005-07-24  0:54 12% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-24  0:54 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

The git-update-server-info command prepares informational files
to help clients discover the contents of a repository, and pull
from it via a dumb transport protocols.  Currently, the
following files are produced.

 - The $repo/info/refs file lists the name of heads and tags
   available in the $repo/refs/ directory, along with their
   SHA1.  This can be used by git-ls-remote command running on
   the client side.

 - The $repo/info/rev-cache file describes the commit ancestry
   reachable from references in the $repo/refs/ directory.  This
   file is in an append-only binary format to make the server
   side friendly to rsync mirroring scheme, and can be read by
   git-show-rev-cache command.

 - The $repo/objects/info/pack file lists the name of the packs
   available, the interdependencies among them, and the head
   commits and tags contained in them.  Along with the other two
   files, this is designed to help clients to make smart pull
   decisions.

The git-receive-pack command is changed to invoke it at the end,
so just after a push to a public repository finishes via "git
push", the server info is automatically updated.

In addition, building of the rev-cache file can be done by a
standalone git-build-rev-cache command separately.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 Makefile             |   11 +
 build-rev-cache.c    |   56 +++++
 cache.h              |    3 
 receive-pack.c       |    1 
 rev-cache.c          |  320 ++++++++++++++++++++++++++++
 rev-cache.h          |   29 +++
 server-info.c        |  565 ++++++++++++++++++++++++++++++++++++++++++++++++++
 show-rev-cache.c     |   18 ++
 update-server-info.c |   23 ++
 9 files changed, 1025 insertions(+), 1 deletions(-)
 create mode 100644 build-rev-cache.c
 create mode 100644 rev-cache.c
 create mode 100644 rev-cache.h
 create mode 100644 server-info.c
 create mode 100644 show-rev-cache.c
 create mode 100644 update-server-info.c

895f412b3df0a9a4884db6231bb590fd1e388db7
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,8 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-stages git-rev-parse git-patch-id git-pack-objects \
 	git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
 	git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
-	git-show-index git-daemon git-var git-peek-remote
+	git-show-index git-daemon git-var git-peek-remote \
+	git-update-server-info git-show-rev-cache git-build-rev-cache
 
 all: $(PROG)
 
@@ -65,6 +66,9 @@ LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h \
 	pack.h pkt-line.h refs.h
 
+LIB_H += rev-cache.h
+LIB_OBJS += rev-cache.o
+
 LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
 
@@ -76,6 +80,7 @@ LIB_OBJS += diff.o diffcore-rename.o dif
 	count-delta.o diffcore-break.o diffcore-order.o
 
 LIB_OBJS += gitenv.o
+LIB_OBJS += server-info.o
 
 LIBS = $(LIB_FILE)
 LIBS += -lz
@@ -152,6 +157,9 @@ git-prune-packed: prune-packed.c
 git-fetch-pack: fetch-pack.c
 git-var: var.c
 git-peek-remote: peek-remote.c
+git-update-server-info: update-server-info.c
+git-build-rev-cache: build-rev-cache.c
+git-show-rev-cache: show-rev-cache.c
 
 git-http-pull: LIBS += -lcurl
 git-rev-list: LIBS += -lssl
@@ -165,6 +173,7 @@ object.o: $(LIB_H)
 read-cache.o: $(LIB_H)
 sha1_file.o: $(LIB_H)
 usage.o: $(LIB_H)
+rev-cache.o: $(LIB_H)
 strbuf.o: $(LIB_H)
 gitenv.o: $(LIB_H)
 entry.o: $(LIB_H)
diff --git a/build-rev-cache.c b/build-rev-cache.c
new file mode 100644
--- /dev/null
+++ b/build-rev-cache.c
@@ -0,0 +1,56 @@
+#include "refs.h"
+#include "cache.h"
+#include "commit.h"
+#include "rev-cache.h"
+
+static void process_head_list(int verbose)
+{
+	char buf[512];
+
+	while (fgets(buf, sizeof(buf), stdin)) {
+		unsigned char sha1[20];
+		struct commit *commit;
+
+		if (get_sha1_hex(buf, sha1)) {
+			error("ignoring: %s", buf);
+			continue;
+		}
+		if (!(commit = lookup_commit_reference(sha1))) {
+			error("not a commit: %s", sha1_to_hex(sha1));
+			continue;
+		}
+		record_rev_cache(commit->object.sha1, verbose ? stderr : NULL);
+	}
+}
+
+
+static const char *build_rev_cache_usage =
+"git-build-rev-cache <rev-cache-file> < list-of-heads";
+
+int main(int ac, char **av)
+{
+	int verbose = 0;
+	const char *path;
+
+	while (1 < ac && av[1][0] == '-') {
+		if (!strcmp(av[1], "-v"))
+			verbose = 1;
+		else
+			usage(build_rev_cache_usage);
+		ac--; av++;
+	}
+
+	if (ac != 2)
+		usage(build_rev_cache_usage);
+
+	path = av[1];
+
+	/* read existing rev-cache */
+	read_rev_cache(path, NULL, 0);
+
+	process_head_list(verbose);
+
+	/* update the rev-cache database by appending newly found one to it */
+	write_rev_cache(path, path);
+	return 0;
+}
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -308,4 +308,7 @@ extern int find_pack_entry_one(const uns
 extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
 extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, int *, unsigned char *);
 
+/* Dumb servers support */
+extern int update_server_info(int);
+
 #endif /* CACHE_H */
diff --git a/receive-pack.c b/receive-pack.c
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -110,6 +110,7 @@ static void execute_commands(void)
 		update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
 		cmd = cmd->next;
 	}
+	update_server_info(0);
 }
 
 static void read_head_info(void)
diff --git a/rev-cache.c b/rev-cache.c
new file mode 100644
--- /dev/null
+++ b/rev-cache.c
@@ -0,0 +1,320 @@
+#include "refs.h"
+#include "cache.h"
+#include "rev-cache.h"
+
+struct rev_cache **rev_cache;
+int nr_revs, alloc_revs;
+
+struct rev_list_elem *rle_free;
+
+#define BATCH_SIZE 512
+
+int find_rev_cache(const unsigned char *sha1)
+{
+	int lo = 0, hi = nr_revs;
+	while (lo < hi) {
+		int mi = (lo + hi) / 2;
+		struct rev_cache *ri = rev_cache[mi];
+		int cmp = memcmp(sha1, ri->sha1, 20);
+		if (!cmp)
+			return mi;
+		if (cmp < 0)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo - 1;
+}
+
+static struct rev_list_elem *alloc_list_elem(void)
+{
+	struct rev_list_elem *rle;
+	if (!rle_free) {
+		int i;
+
+		rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
+		for (i = 0; i < BATCH_SIZE - 1; i++) {
+			rle[i].ri = NULL;
+			rle[i].next = &rle[i + 1];
+		}
+		rle[BATCH_SIZE - 1].ri = NULL;
+		rle[BATCH_SIZE - 1].next = NULL;
+		rle_free = rle;
+	}
+	rle = rle_free;
+	rle_free = rle->next;
+	return rle;
+}
+
+static struct rev_cache *create_rev_cache(const unsigned char *sha1)
+{
+	struct rev_cache *ri;
+	int pos = find_rev_cache(sha1);
+
+	if (0 <= pos)
+		return rev_cache[pos];
+	pos = -pos - 1;
+	if (alloc_revs <= ++nr_revs) {
+		alloc_revs = alloc_nr(alloc_revs);
+		rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
+	}
+	if (pos < nr_revs)
+		memmove(rev_cache + pos + 1, rev_cache + pos,
+			(nr_revs - pos - 1) * sizeof(ri));
+	ri = xcalloc(1, sizeof(*ri));
+	memcpy(ri->sha1, sha1, 20);
+	rev_cache[pos] = ri;
+	return ri;
+}
+
+static unsigned char last_sha1[20];
+
+static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
+{
+	unsigned char flag;
+	struct rev_list_elem *rle;
+
+	if (ri->written)
+		return;
+
+	if (ri->parsed) {
+		/* We use last_sha1 compression only for the first parent;
+		 * otherwise the resulting rev-cache would lose the parent
+		 * order information.
+		 */
+		if (ri->parents &&
+		    !memcmp(ri->parents->ri->sha1, last_sha1, 20))
+			flag = (ri->num_parents - 1) | 0x80;
+		else
+			flag = ri->num_parents;
+
+		fwrite(ri->sha1, 20, 1, rev_cache_file);
+		fwrite(&flag, 1, 1, rev_cache_file);
+		for (rle = ri->parents; rle; rle = rle->next) {
+			if (flag & 0x80 && rle == ri->parents)
+				continue;
+			fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
+		}
+		memcpy(last_sha1, ri->sha1, 20);
+		ri->written = 1;
+	}
+	/* recursively write children depth first */
+	for (rle = ri->children; rle; rle = rle->next)
+		write_one_rev_cache(rev_cache_file, rle->ri);
+}
+
+void write_rev_cache(const char *newpath, const char *oldpath)
+{
+	/* write the following commit ancestry information in
+	 * $GIT_DIR/info/rev-cache.
+	 *
+	 * The format is:
+	 * 20-byte SHA1 (commit ID)
+	 * 1-byte flag:
+	 * - bit 0-6 records "number of parent commit SHA1s to
+	 *   follow" (i.e. up to 127 children can be listed).
+	 * - when the bit 7 is on, then "the entry immediately
+	 *   before this entry is one of the parents of this
+         *   commit".
+	 * N x 20-byte SHA1 (parent commit IDs)
+	 */
+	FILE *rev_cache_file;
+	int i;
+	struct rev_cache *ri;
+
+	if (!strcmp(newpath, oldpath)) {
+		/* If we are doing it in place */
+		rev_cache_file = fopen(newpath, "a");
+	}
+	else {
+		char buf[8096];
+		size_t sz;
+		FILE *oldfp = fopen(oldpath, "r");
+		rev_cache_file = fopen(newpath, "w");
+		if (oldfp) {
+			while (1) {
+				sz = fread(buf, 1, sizeof(buf), oldfp);
+				if (sz == 0)
+					break;
+				fwrite(buf, 1, sz, rev_cache_file);
+			}
+			fclose(oldfp);
+		}
+	}
+
+	memset(last_sha1, 0, 20);
+
+	/* Go through available rev_cache structures, starting from
+	 * parentless ones first, so that we would get most out of
+	 * last_sha1 optimization by the depth first behaviour of
+	 * write_one_rev_cache().
+	 */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		if (ri->num_parents)
+			continue;
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+	/* Then the rest */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+	fclose(rev_cache_file);
+}
+
+static void add_parent(struct rev_cache *child,
+		       const unsigned char *parent_sha1)
+{
+	struct rev_cache *parent = create_rev_cache(parent_sha1);
+	struct rev_list_elem *e = alloc_list_elem();
+
+	/* Keep the parent list ordered in the same way the commit
+	 * object records them.
+	 */
+	e->ri = parent;
+	e->next = NULL;
+	if (!child->parents_tail)
+		child->parents = e;
+	else
+		child->parents_tail->next = e;
+	child->parents_tail = e;
+	child->num_parents++;
+
+	/* There is no inherent order of the children so we just
+	 * LIFO them together.
+	 */
+	e = alloc_list_elem();
+	e->next = parent->children;
+	parent->children = e;
+	e->ri = child;
+	parent->num_children++;
+}
+
+int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
+{
+	unsigned char *map;
+	int fd;
+	struct stat st;
+	unsigned long ofs, len;
+	struct rev_cache *ri = NULL;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		if (dry_run)
+			return error("cannot open %s", path);
+		if (errno == ENOENT)
+			return 0;
+		return -1;
+	}
+	if (fstat(fd, &st)) {
+		close(fd);
+		return -1;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	memset(last_sha1, 0, 20);
+	ofs = 0;
+	len = st.st_size;
+	while (ofs < len) {
+		unsigned char sha1[20];
+		int flag, cnt, i;
+		if (len < ofs + 21)
+			die("rev-cache too short");
+		memcpy(sha1, map + ofs, 20);
+		flag = map[ofs + 20];
+		ofs += 21;
+		cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
+		if (len < ofs + (flag & 0x7f) * 20)
+			die("rev-cache too short to have %d more parents",
+			    (flag & 0x7f));
+		if (dumpfile)
+			fprintf(dumpfile, "%s", sha1_to_hex(sha1));
+		if (!dry_run) {
+			ri = create_rev_cache(sha1);
+			if (!ri)
+				die("cannot create rev-cache for %s",
+				    sha1_to_hex(sha1));
+			ri->written = ri->parsed = 1;
+		}
+		i = 0;
+		if (flag & 0x80) {
+			if (!dry_run)
+				add_parent(ri, last_sha1);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			i++;
+		}
+		while (i++ < cnt) {
+			if (!dry_run)
+				add_parent(ri, map + ofs);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			ofs += 20;
+		}
+		if (dumpfile)
+			fprintf(dumpfile, "\n");
+		memcpy(last_sha1, sha1, 20);
+	}
+	if (ofs != len)
+		die("rev-cache truncated?");
+	munmap(map, len);
+	return 0;
+}
+
+int record_rev_cache(const unsigned char *sha1, FILE *dumpfile)
+{
+	unsigned char parent[20];
+	char type[20];
+	unsigned long size, ofs;
+	unsigned int cnt, i;
+	void *buf;
+	struct rev_cache *ri;
+
+	buf = read_sha1_file(sha1, type, &size);
+	if (!buf)
+		return error("%s: not found", sha1_to_hex(sha1));
+	if (strcmp(type, "commit")) {
+		free(buf);
+		return error("%s: not a commit but a %s",
+			     sha1_to_hex(sha1), type);
+	}
+	ri = create_rev_cache(sha1);
+	if (ri->parsed)
+		return 0;
+	if (dumpfile)
+		fprintf(dumpfile, "commit %s\n", sha1_to_hex(sha1));
+
+	cnt = 0;
+	ofs = 46; /* "tree " + hex-sha1 + "\n" */
+	while (!memcmp(buf + ofs, "parent ", 7) &&
+	       !get_sha1_hex(buf + ofs + 7, parent)) {
+		ofs += 48;
+		cnt++;
+	}
+	if (cnt * 48 + 46 != ofs) {
+		free(buf);
+		die("internal error in record_rev_cache");
+	}
+
+	ri = create_rev_cache(sha1);
+	ri->parsed = 1;
+
+	for (i = 0; i < cnt; i++) {
+		unsigned char parent_sha1[20];
+
+		ofs = 46 + i * 48 + 7;
+		get_sha1_hex(buf + ofs, parent_sha1);
+		add_parent(ri, parent_sha1);
+		record_rev_cache(parent_sha1, dumpfile);
+	}
+	free(buf);
+	return 0;
+}
diff --git a/rev-cache.h b/rev-cache.h
new file mode 100644
--- /dev/null
+++ b/rev-cache.h
@@ -0,0 +1,29 @@
+#ifndef REV_CACHE_H
+#define REV_CACHE_H
+
+extern struct rev_cache {
+	struct rev_cache *head_list;
+	struct rev_list_elem *children;
+	struct rev_list_elem *parents;
+	struct rev_list_elem *parents_tail;
+	unsigned short num_parents;
+	unsigned short num_children;
+	unsigned int written : 1;
+	unsigned int parsed : 1;
+	unsigned int work : 30;
+	void *work_ptr;
+	unsigned char sha1[20];
+} **rev_cache;
+extern int nr_revs, alloc_revs;
+
+struct rev_list_elem {
+	struct rev_list_elem *next;
+	struct rev_cache *ri;
+};
+
+extern int find_rev_cache(const unsigned char *);
+extern int read_rev_cache(const char *, FILE *, int);
+extern int record_rev_cache(const unsigned char *, FILE *);
+extern void write_rev_cache(const char *new, const char *old);
+
+#endif
diff --git a/server-info.c b/server-info.c
new file mode 100644
--- /dev/null
+++ b/server-info.c
@@ -0,0 +1,565 @@
+#include "cache.h"
+#include "refs.h"
+#include "object.h"
+#include "commit.h"
+#include "rev-cache.h"
+
+/* refs */
+static FILE *info_ref_fp;
+static unsigned long info_ref_time;
+static int info_ref_is_stale = 0;
+
+static int stat_ref(const char *path, const unsigned char *sha1)
+{
+	struct stat st;
+	if (!stat(path, &st) && info_ref_time < st.st_mtime)
+		info_ref_is_stale = 1;
+	return 0;
+}
+
+static int add_info_ref(const char *path, const unsigned char *sha1)
+{
+	fprintf(info_ref_fp, "%s	%s\n", sha1_to_hex(sha1), path);
+	return 0;
+}
+
+static int update_info_refs(int force)
+{
+	struct stat st;
+	char *path0 = strdup(git_path("info/refs"));
+	int len = strlen(path0);
+	char *path1 = xmalloc(len + 2);
+
+	strcpy(path1, path0);
+	strcpy(path1 + len, "+");
+
+	if (!force) {
+		if (stat(path0, &st)) {
+			if (errno == ENOENT)
+				info_ref_is_stale = 1;
+			else
+				return error("cannot stat %s", path0);
+		}
+		else {
+			info_ref_time = st.st_mtime;
+			for_each_ref(stat_ref);
+		}
+		if (!info_ref_is_stale)
+			return 0;
+	}
+
+	safe_create_leading_directories(path0);
+	info_ref_fp = fopen(path1, "w");
+	if (!info_ref_fp)
+		return error("unable to update %s", path0);
+	for_each_ref(add_info_ref);
+	fclose(info_ref_fp);
+	rename(path1, path0);
+	free(path0);
+	free(path1);
+	return 0;
+}
+
+/* packs */
+struct pack_info {
+	unsigned long latest;
+	struct packed_git *p;
+	int old_num;
+	int new_num;
+	int nr_alloc;
+	int nr_heads;
+	unsigned char (*head)[20];
+	char dep[0]; /* more */
+} **info;
+static int num_pack;
+static const char *objdir;
+static int objdirlen;
+
+static struct object *parse_object_cheap(const unsigned char *sha1)
+{
+	struct object *o;
+
+	if ((o = parse_object(sha1)) == NULL)
+		return NULL;
+	if (o->type == commit_type) {
+		struct commit *commit = (struct commit *)o;
+		free(commit->buffer);
+		commit->buffer = NULL;
+	}
+	return o;
+}
+
+static struct pack_info *find_pack_by_name(const char *name)
+{
+	int i;
+	for (i = 0; i < num_pack; i++) {
+		struct packed_git *p = info[i]->p;
+		/* skip "/pack/" after ".git/objects" */
+		if (!strcmp(p->pack_name + objdirlen + 6, name))
+			return info[i];
+	}
+	return NULL;
+}
+
+static struct pack_info *find_pack_by_old_num(int old_num)
+{
+	int i;
+	for (i = 0; i < num_pack; i++)
+		if (info[i]->old_num == old_num)
+			return info[i];
+	return NULL;
+}
+
+static int add_head_def(struct pack_info *this, unsigned char *sha1)
+{
+	if (this->nr_alloc <= this->nr_heads) {
+		this->nr_alloc = alloc_nr(this->nr_alloc);
+		this->head = xrealloc(this->head, this->nr_alloc * 20);
+	}
+	memcpy(this->head[this->nr_heads++], sha1, 20);
+	return 0;
+}
+
+/* Returns non-zero when we detect that the info in the
+ * old file is useless.
+ */
+static int parse_pack_def(const char *line, int old_cnt)
+{
+	struct pack_info *i = find_pack_by_name(line + 2);
+	if (i) {
+		i->old_num = old_cnt;
+		return 0;
+	}
+	else {
+		/* The file describes a pack that is no longer here;
+		 * dependencies between packs needs to be recalculated.
+		 */
+		return 1;
+	}
+}
+
+/* Returns non-zero when we detect that the info in the
+ * old file is useless.
+ */
+static int parse_depend_def(char *line)
+{
+	unsigned long num;
+	char *cp, *ep;
+	struct pack_info *this, *that;
+
+	cp = line + 2;
+	num = strtoul(cp, &ep, 10);
+	if (ep == cp)
+		return error("invalid input %s", line);
+	this = find_pack_by_old_num(num);
+	if (!this)
+		return 0;
+	while (ep && *(cp = ep)) {
+		num = strtoul(cp, &ep, 10);
+		if (ep == cp)
+			break;
+		that = find_pack_by_old_num(num);
+		if (!that)
+			/* The pack this one depends on does not
+			 * exist; this should not happen because
+			 * we write out the list of packs first and
+			 * then dependency information, but it means
+			 * the file is useless anyway.
+			 */
+			return 1;
+		this->dep[that->new_num] = 1;
+	}
+	return 0;
+}
+
+/* Returns non-zero when we detect that the info in the
+ * old file is useless.
+ */
+static int parse_head_def(char *line)
+{
+	unsigned char sha1[20];
+	unsigned long num;
+	char *cp, *ep;
+	struct pack_info *this;
+	struct object *o;
+
+	cp = line + 2;
+	num = strtoul(cp, &ep, 10);
+	if (ep == cp || *ep++ != ' ')
+		return error("invalid input ix %s", line);
+	this = find_pack_by_old_num(num);
+	if (!this)
+		return 1; /* You know the drill. */
+	if (get_sha1_hex(ep, sha1) || ep[40] != ' ')
+		return error("invalid input sha1 %s (%s)", line, ep);
+	if ((o = parse_object_cheap(sha1)) == NULL)
+		return error("no such object: %s", line);
+	return add_head_def(this, sha1);
+}
+
+/* Returns non-zero when we detect that the info in the
+ * old file is useless.
+ */
+static int read_pack_info_file(const char *infofile)
+{
+	FILE *fp;
+	char line[1000];
+	int old_cnt = 0;
+
+	fp = fopen(infofile, "r");
+	if (!fp)
+		return 1; /* nonexisting is not an error. */
+
+	while (fgets(line, sizeof(line), fp)) {
+		int len = strlen(line);
+		if (line[len-1] == '\n')
+			line[len-1] = 0;
+
+		switch (line[0]) {
+		case 'P': /* P name */
+			if (parse_pack_def(line, old_cnt++))
+				goto out_stale;
+			break;
+		case 'D': /* D ix dep-ix1 dep-ix2... */
+			if (parse_depend_def(line))
+				goto out_stale;
+			break;
+		case 'T': /* T ix sha1 type */
+			if (parse_head_def(line))
+				goto out_stale;
+			break;
+		default:
+			error("unrecognized: %s", line);
+			break;
+		}
+	}
+	fclose(fp);
+	return 0;
+ out_stale:
+	fclose(fp);
+	return 1;
+}
+
+/* We sort the packs according to the date of the latest commit.  That
+ * in turn indicates how young the pack is, and in general we would
+ * want to depend on younger packs.
+ */
+static unsigned long get_latest_commit_date(struct packed_git *p)
+{
+	unsigned char sha1[20];
+	struct object *o;
+	int num = num_packed_objects(p);
+	int i;
+	unsigned long latest = 0;
+
+	for (i = 0; i < num; i++) {
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("corrupt pack file %s?", p->pack_name);
+		if ((o = parse_object_cheap(sha1)) == NULL)
+			die("cannot parse %s", sha1_to_hex(sha1));
+		if (o->type == commit_type) {
+			struct commit *commit = (struct commit *)o;
+			if (latest < commit->date)
+				latest = commit->date;
+		}
+	}
+	return latest;
+}
+
+static int compare_info(const void *a_, const void *b_)
+{
+	struct pack_info * const* a = a_;
+	struct pack_info * const* b = b_;
+
+	if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
+		/* Keep the order in the original */
+		return (*a)->old_num - (*b)->old_num;
+	else if (0 <= (*a)->old_num)
+		/* Only A existed in the original so B is obviously newer */
+		return -1;
+	else if (0 <= (*b)->old_num)
+		/* The other way around. */
+		return 1;
+
+	if ((*a)->latest < (*b)->latest)
+		return -1;
+	else if ((*a)->latest == (*b)->latest)
+		return 0;
+	else
+		return 1;
+}
+
+static void init_pack_info(const char *infofile, int force)
+{
+	struct packed_git *p;
+	int stale;
+	int i = 0;
+	char *dep_temp;
+
+	objdir = get_object_directory();
+	objdirlen = strlen(objdir);
+
+	prepare_packed_git();
+	for (p = packed_git; p; p = p->next) {
+		/* we ignore things on alternate path since they are
+		 * not available to the pullers in general.
+		 */
+		if (strncmp(p->pack_name, objdir, objdirlen) ||
+		    strncmp(p->pack_name + objdirlen, "/pack/", 6))
+			continue;
+		i++;
+	}
+	num_pack = i;
+	info = xcalloc(num_pack, sizeof(struct pack_info *));
+	for (i = 0, p = packed_git; p; p = p->next) {
+		if (strncmp(p->pack_name, objdir, objdirlen) ||
+		    p->pack_name[objdirlen] != '/')
+			continue;
+		info[i] = xcalloc(1, sizeof(struct pack_info) + num_pack);
+		info[i]->p = p;
+		info[i]->old_num = -1;
+		i++;
+	}
+
+	if (infofile && !force)
+		stale = read_pack_info_file(infofile);
+	else
+		stale = 1;
+
+	for (i = 0; i < num_pack; i++) {
+		if (stale) {
+			info[i]->old_num = -1;
+			memset(info[i]->dep, 0, num_pack);
+			info[i]->nr_heads = 0;
+		}
+		if (info[i]->old_num < 0)
+			info[i]->latest = get_latest_commit_date(info[i]->p);
+	}
+
+	qsort(info, num_pack, sizeof(info[0]), compare_info);
+	for (i = 0; i < num_pack; i++)
+		info[i]->new_num = i;
+
+	/* we need to fix up the dependency information
+	 * for the old ones.
+	 */
+	dep_temp = NULL;
+	for (i = 0; i < num_pack; i++) {
+		int old;
+
+		if (info[i]->old_num < 0)
+			continue;
+		if (! dep_temp)
+			dep_temp = xmalloc(num_pack);
+		memset(dep_temp, 0, num_pack);
+		for (old = 0; old < num_pack; old++) {
+			struct pack_info *base;
+			if (!info[i]->dep[old])
+				continue;
+			base = find_pack_by_old_num(old);
+			if (!base)
+				die("internal error renumbering");
+			dep_temp[base->new_num] = 1;
+		}
+		memcpy(info[i]->dep, dep_temp, num_pack);
+	}
+	free(dep_temp);
+}
+
+static void write_pack_info_file(FILE *fp)
+{
+	int i, j;
+	for (i = 0; i < num_pack; i++)
+		fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
+
+	for (i = 0; i < num_pack; i++) {
+		fprintf(fp, "D %1d", i);
+		for (j = 0; j < num_pack; j++) {
+			if ((i == j) || !(info[i]->dep[j]))
+				continue;
+			fprintf(fp, " %1d", j);
+		}
+		fputc('\n', fp);
+	}
+
+	for (i = 0; i < num_pack; i++) {
+		struct pack_info *this = info[i];
+		for (j = 0; j < this->nr_heads; j++) {
+			struct object *o = lookup_object(this->head[j]);
+			fprintf(fp, "T %1d %s %s\n",
+				i, sha1_to_hex(this->head[j]), o->type);
+		}
+	}
+
+}
+
+#define REFERENCED 01
+#define INTERNAL  02
+#define EMITTED   04
+
+static void show(struct object *o, int pack_ix)
+{
+	/*
+	 * We are interested in objects that are not referenced,
+	 * and objects that are referenced but not internal.
+	 */
+	if (o->flags & EMITTED)
+		return;
+
+	if (!(o->flags & REFERENCED))
+		add_head_def(info[pack_ix], o->sha1);
+	else if ((o->flags & REFERENCED) && !(o->flags & INTERNAL)) {
+		int i;
+
+		/* Which pack contains this object?  That is what
+		 * pack_ix can depend on.  We earlier sorted info
+		 * array from youngest to oldest, so try newer packs
+		 * first to favor them here.
+		 */
+		for (i = num_pack - 1; 0 <= i; i--) {
+			struct packed_git *p = info[i]->p;
+			struct pack_entry ent;
+			if (find_pack_entry_one(o->sha1, &ent, p)) {
+				info[pack_ix]->dep[i] = 1;
+				break;
+			}
+		}
+	}
+	o->flags |= EMITTED;
+}
+
+static void find_pack_info_one(int pack_ix)
+{
+	unsigned char sha1[20];
+	struct object *o;
+	struct object_list *ref;
+	int i;
+	struct packed_git *p = info[pack_ix]->p;
+	int num = num_packed_objects(p);
+
+	/* Scan objects, clear flags from all the edge ones and
+	 * internal ones, possibly marked in the previous round.
+	 */
+	for (i = 0; i < num; i++) {
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("corrupt pack file %s?", p->pack_name);
+		if ((o = lookup_object(sha1)) == NULL)
+			die("cannot parse %s", sha1_to_hex(sha1));
+		for (ref = o->refs; ref; ref = ref->next)
+			ref->item->flags = 0;
+		o->flags = 0;
+	}
+
+	/* Mark all the internal ones */
+	for (i = 0; i < num; i++) {
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("corrupt pack file %s?", p->pack_name);
+		if ((o = lookup_object(sha1)) == NULL)
+			die("cannot find %s", sha1_to_hex(sha1));
+		for (ref = o->refs; ref; ref = ref->next)
+			ref->item->flags |= REFERENCED;
+		o->flags |= INTERNAL;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (nth_packed_object_sha1(p, i, sha1))
+			die("corrupt pack file %s?", p->pack_name);
+		if ((o = lookup_object(sha1)) == NULL)
+			die("cannot find %s", sha1_to_hex(sha1));
+
+		show(o, pack_ix);
+		for (ref = o->refs; ref; ref = ref->next)
+			show(ref->item, pack_ix);
+	}
+
+}
+
+static void find_pack_info(void)
+{
+	int i;
+	for (i = 0; i < num_pack; i++) {
+		/* The packed objects are cast in stone, and a head
+		 * in a pack will stay as head, so is the set of missing
+		 * objects.  If the repo has been reorganized and we
+		 * are missing some packs available back then, we have
+		 * already discarded the info read from the file, so
+		 * we will find (old_num < 0) in that case.
+		 */
+		if (0 <= info[i]->old_num)
+			continue;
+		find_pack_info_one(i);
+	}
+}
+
+static int update_info_packs(int force)
+{
+	char infofile[PATH_MAX];
+	char name[PATH_MAX];
+	int namelen;
+	FILE *fp;
+
+	namelen = sprintf(infofile, "%s/info/packs", get_object_directory());
+	strcpy(name, infofile);
+	strcpy(name + namelen, "+");
+
+	init_pack_info(infofile, force);
+	find_pack_info();
+
+	safe_create_leading_directories(name);
+	fp = fopen(name, "w");
+	if (!fp)
+		return error("cannot open %s", name);
+	write_pack_info_file(fp);
+	fclose(fp);
+	rename(name, infofile);
+	return 0;
+}
+
+/* rev-cache */
+static int record_rev_cache_ref(const char *path, const unsigned char *sha1)
+{
+	struct commit *commit;
+	if (!(commit = lookup_commit_reference(sha1)))
+		return error("not a commit: %s", sha1_to_hex(sha1));
+	return record_rev_cache(commit->object.sha1, NULL);
+}
+
+static int update_info_revs(int force)
+{
+	char *path0 = strdup(git_path("info/rev-cache"));
+	int len = strlen(path0);
+	char *path1 = xmalloc(len + 2);
+
+	strcpy(path1, path0);
+	strcpy(path1 + len, "+");
+
+	/* read existing rev-cache */
+	if (!force)
+		read_rev_cache(path0, NULL, 0);
+	safe_create_leading_directories(path0);
+
+	for_each_ref(record_rev_cache_ref);
+
+	/* update the rev-cache database */
+	write_rev_cache(path1, force ? "/dev/null" : path0);
+	rename(path1, path0);
+	free(path1);
+	free(path0);
+	return 0;
+}
+
+/* public */
+int update_server_info(int force)
+{
+	/* We would add more dumb-server support files later,
+	 * including index of available pack files and their
+	 * intended audiences.
+	 */
+	int errs = 0;
+
+	errs = errs | update_info_refs(force);
+	errs = errs | update_info_packs(force);
+	errs = errs | update_info_revs(force);
+
+	return errs;
+}
diff --git a/show-rev-cache.c b/show-rev-cache.c
new file mode 100644
--- /dev/null
+++ b/show-rev-cache.c
@@ -0,0 +1,18 @@
+#include "cache.h"
+#include "rev-cache.h"
+
+static char *show_rev_cache_usage =
+"git-show-rev-cache <rev-cache-file>";
+
+int main(int ac, char **av)
+{
+	while (1 < ac && av[0][1] == '-') {
+		/* do flags here */
+		break;
+		ac--; av++;
+	}
+	if (ac != 2)
+		usage(show_rev_cache_usage);
+
+	return read_rev_cache(av[1], stdout, 1);
+}
diff --git a/update-server-info.c b/update-server-info.c
new file mode 100644
--- /dev/null
+++ b/update-server-info.c
@@ -0,0 +1,23 @@
+#include "cache.h"
+
+static const char update_server_info_usage[] =
+"git-update-server-info [--force]";
+
+int main(int ac, char **av)
+{
+	int i;
+	int force = 0;
+	for (i = 1; i < ac; i++) {
+		if (av[i][0] == '-') {
+			if (!strcmp("--force", av[i]) ||
+			    !strcmp("-f", av[i]))
+				force = 1;
+			else
+				usage(update_server_info_usage);
+		}
+	}
+	if (i != ac)
+		usage(update_server_info_usage);
+
+	return !!update_server_info(force);
+}

^ permalink raw reply	[relevance 12%]

* [PATCH] Teach parse_commit_buffer about grafting.
  @ 2005-07-30  8:00 13%         ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-30  8:00 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

Introduce a new file $GIT_DIR/info/grafts (or $GIT_GRAFT_FILE)
which is a list of "fake commit parent records".  Each line of
this file is a commit ID, followed by parent commit IDs, all
40-byte hex SHA1 separated by a single SP in between.  The
records override the parent information we would normally read
from the commit objects, allowing both adding "fake" parents
(i.e. grafting), and pretending as if a commit is not a child of
some of its real parents (i.e. cauterizing).

Bugs are mine, but the credits for the idea and implementation
outline all go to Linus, who kept hinting how this thing should
work.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h     |    2 +
 commit.c    |  114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 sha1_file.c |   13 ++++++-
 3 files changed, 127 insertions(+), 2 deletions(-)

0f16b172aa7f0757b2af50ec7be58dc0e23913a6
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -127,10 +127,12 @@ extern unsigned int active_nr, active_al
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
+#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
 
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
 extern char *get_index_file(void);
+extern char *get_graft_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -91,11 +91,108 @@ static unsigned long parse_commit_date(c
 	return date;
 }
 
+static struct commit_graft {
+	unsigned char sha1[20];
+	int nr_parent;
+	unsigned char parent[0][20]; /* more */
+} **commit_graft;
+static int commit_graft_alloc, commit_graft_nr;
+
+static int commit_graft_pos(const unsigned char *sha1)
+{
+	int lo, hi;
+	lo = 0;
+	hi = commit_graft_nr;
+	while (lo < hi) {
+		int mi = (lo + hi) / 2;
+		struct commit_graft *graft = commit_graft[mi];
+		int cmp = memcmp(sha1, graft->sha1, 20);
+		if (!cmp)
+			return mi;
+		if (cmp < 0)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo - 1;
+}
+
+static void prepare_commit_graft(void)
+{
+	char *graft_file = get_graft_file();
+	FILE *fp = fopen(graft_file, "r");
+	char buf[1024];
+	if (!fp) {
+		commit_graft = (struct commit_graft **) "hack";
+		return;
+	}
+	while (fgets(buf, sizeof(buf), fp)) {
+		/* The format is just "Commit Parent1 Parent2 ...\n" */
+		int len = strlen(buf);
+		int i;
+		struct commit_graft *graft = NULL;
+
+		if (buf[len-1] == '\n')
+			buf[--len] = 0;
+		if (buf[0] == '#')
+			continue;
+		if ((len + 1) % 41) {
+		bad_graft_data:
+			error("bad graft data: %s", buf);
+			free(graft);
+			continue;
+		}
+		i = (len + 1) / 41 - 1;
+		graft = xmalloc(sizeof(*graft) + 20 * i);
+		graft->nr_parent = i;
+		if (get_sha1_hex(buf, graft->sha1))
+			goto bad_graft_data;
+		for (i = 40; i < len; i += 41) {
+			if (buf[i] != ' ')
+				goto bad_graft_data;
+			if (get_sha1_hex(buf + i + 1, graft->parent[i/41]))
+				goto bad_graft_data;
+		}
+		i = commit_graft_pos(graft->sha1);
+		if (0 <= i) {
+			error("duplicate graft data: %s", buf);
+			free(graft);
+			continue;
+		}
+		i = -i - 1;
+		if (commit_graft_alloc <= ++commit_graft_nr) {
+			commit_graft_alloc = alloc_nr(commit_graft_alloc);
+			commit_graft = xrealloc(commit_graft,
+						sizeof(*commit_graft) *
+						commit_graft_alloc);
+		}
+		if (i < commit_graft_nr)
+			memmove(commit_graft + i + 1,
+				commit_graft + i,
+				(commit_graft_nr - i - 1) *
+				sizeof(*commit_graft));
+		commit_graft[i] = graft;
+	}
+	fclose(fp);
+}
+
+static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
+{
+	int pos;
+	if (!commit_graft)
+		prepare_commit_graft();
+	pos = commit_graft_pos(sha1);
+	if (pos < 0)
+		return NULL;
+	return commit_graft[pos];
+}
+
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 {
 	char *bufptr = buffer;
 	unsigned char parent[20];
 	struct commit_list **pptr;
+	struct commit_graft *graft;
 
 	if (item->object.parsed)
 		return 0;
@@ -109,17 +206,32 @@ int parse_commit_buffer(struct commit *i
 		add_ref(&item->object, &item->tree->object);
 	bufptr += 46; /* "tree " + "hex sha1" + "\n" */
 	pptr = &item->parents;
+
+	graft = lookup_commit_graft(item->object.sha1);
 	while (!memcmp(bufptr, "parent ", 7)) {
 		struct commit *new_parent;
 
 		if (get_sha1_hex(bufptr + 7, parent) || bufptr[47] != '\n')
 			return error("bad parents in commit %s", sha1_to_hex(item->object.sha1));
+		bufptr += 48;
+		if (graft)
+			continue;
 		new_parent = lookup_commit(parent);
 		if (new_parent) {
 			pptr = &commit_list_insert(new_parent, pptr)->next;
 			add_ref(&item->object, &new_parent->object);
 		}
-		bufptr += 48;
+	}
+	if (graft) {
+		int i;
+		struct commit *new_parent;
+		for (i = 0; i < graft->nr_parent; i++) {
+			new_parent = lookup_commit(graft->parent[i]);
+			if (!new_parent)
+				continue;
+			pptr = &commit_list_insert(new_parent, pptr)->next;
+			add_ref(&item->object, &new_parent->object);
+		}
 	}
 	item->date = parse_commit_date(bufptr);
 	return 0;
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -61,7 +61,8 @@ static int get_sha1_file(const char *pat
 	return get_sha1_hex(buffer, result);
 }
 
-static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir;
+static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
+	*git_graft_file;
 static void setup_git_env(void)
 {
 	git_dir = gitenv(GIT_DIR_ENVIRONMENT);
@@ -79,6 +80,9 @@ static void setup_git_env(void)
 		git_index_file = xmalloc(strlen(git_dir) + 7);
 		sprintf(git_index_file, "%s/index", git_dir);
 	}
+	git_graft_file = gitenv(GRAFT_ENVIRONMENT);
+	if (!git_graft_file)
+		git_graft_file = strdup(git_path("info/grafts"));
 }
 
 char *get_object_directory(void)
@@ -102,6 +106,13 @@ char *get_index_file(void)
 	return git_index_file;
 }
 
+char *get_graft_file(void)
+{
+	if (!git_graft_file)
+		setup_git_env();
+	return git_graft_file;
+}
+
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path;

^ permalink raw reply	[relevance 13%]

* [PATCH 1/2] Functions for managing the set of packs the library is using
  @ 2005-07-31 20:10 12% ` barkalow
  2005-08-01  0:53 12% ` [PATCH 1/2] Functions for managing the set of packs the library is using (whitespace fixed) barkalow
  1 sibling, 0 replies; 200+ results
From: barkalow @ 2005-07-31 20:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This adds support for reading an uninstalled index, and installing a
pack file that was added while the program was running, as well as
functions for determining where to put the file.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---

  cache.h     |   13 ++++++
  sha1_file.c |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 135 insertions(+), 1 deletions(-)

20fcc8f66a6780cf9bbd2fc2ba3b918c33696a67
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -172,6 +172,8 @@ extern void rollback_index_file(struct c
  extern char *mkpath(const char *fmt, ...);
  extern char *git_path(const char *fmt, ...);
  extern char *sha1_file_name(const unsigned char *sha1);
+extern char *sha1_pack_name(const unsigned char *sha1);
+extern char *sha1_pack_index_name(const unsigned char *sha1);

  int safe_create_leading_directories(char *path);

@@ -200,6 +202,9 @@ extern int write_sha1_to_fd(int fd, cons
  extern int has_sha1_pack(const unsigned char *sha1);
  extern int has_sha1_file(const unsigned char *sha1);

+extern int has_pack_file(const unsigned char *sha1);
+extern int has_pack_index(const unsigned char *sha1);
+
  /* Convert to/from hex/sha1 representation */
  extern int get_sha1(const char *str, unsigned char *sha1);
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
@@ -276,6 +281,7 @@ extern struct packed_git {
  	void *pack_base;
  	unsigned int pack_last_used;
  	unsigned int pack_use_cnt;
+	unsigned char sha1[20];
  	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
  } *packed_git;

@@ -298,7 +304,14 @@ extern int path_match(const char *path,
  extern int get_ack(int fd, unsigned char *result_sha1);
  extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);

+extern struct packed_git *parse_pack_index(unsigned char *sha1);
+
  extern void prepare_packed_git(void);
+extern void install_packed_git(struct packed_git *pack);
+
+extern struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+					 struct packed_git *packs);
+
  extern int use_packed_git(struct packed_git *);
  extern void unuse_packed_git(struct packed_git *);
  extern struct packed_git *add_packed_git(char *, int);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -200,6 +200,56 @@ char *sha1_file_name(const unsigned char
  	return base;
  }

+char *sha1_pack_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.pack", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+ 
+	return base;
+}
+
+char *sha1_pack_index_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.idx", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+ 
+	return base;
+}
+
  struct alternate_object_database *alt_odb;

  /*
@@ -360,6 +410,14 @@ void unuse_packed_git(struct packed_git

  int use_packed_git(struct packed_git *p)
  {
+	if (!p->pack_size) {
+		struct stat st;
+		// We created the struct before we had the pack
+		stat(p->pack_name, &st);
+		if (!S_ISREG(st.st_mode))
+			die("packfile %s not a regular file", p->pack_name);
+		p->pack_size = st.st_size;
+	}
  	if (!p->pack_base) {
  		int fd;
  		struct stat st;
@@ -387,8 +445,10 @@ int use_packed_git(struct packed_git *p)
  		 * this is cheap.
  		 */
  		if (memcmp((char*)(p->index_base) + p->index_size - 40,
-			   p->pack_base + p->pack_size - 20, 20))
+			   p->pack_base + p->pack_size - 20, 20)) {
+
  			die("packfile %s does not match index.", p->pack_name);
+		}
  	}
  	p->pack_last_used = pack_used_ctr++;
  	p->pack_use_cnt++;
@@ -426,6 +486,37 @@ struct packed_git *add_packed_git(char *
  	return p;
  }

+struct packed_git *parse_pack_index(unsigned char *sha1)
+{
+	struct packed_git *p;
+	unsigned long idx_size;
+	void *idx_map;
+	char *path = sha1_pack_index_name(sha1);
+
+	if (check_packed_git_idx(path, &idx_size, &idx_map))
+		return NULL;
+
+	path = sha1_pack_name(sha1);
+
+	p = xmalloc(sizeof(*p) + strlen(path) + 2);
+	strcpy(p->pack_name, path);
+	p->index_size = idx_size;
+	p->pack_size = 0;
+	p->index_base = idx_map;
+	p->next = NULL;
+	p->pack_base = NULL;
+	p->pack_last_used = 0;
+	p->pack_use_cnt = 0;
+	memcpy(p->sha1, sha1, 20);
+	return p;
+}
+
+void install_packed_git(struct packed_git *pack)
+{
+	pack->next = packed_git;
+	packed_git = pack;
+}
+
  static void prepare_packed_git_one(char *objdir)
  {
  	char path[PATH_MAX];
@@ -989,6 +1080,20 @@ static int find_pack_entry(const unsigne
  	return 0;
  }

+struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+				  struct packed_git *packs)
+{
+	struct packed_git *p;
+	struct pack_entry e;
+
+	for (p = packs; p; p = p->next) {
+		if (find_pack_entry_one(sha1, &e, p))
+			return p;
+	}
+	return NULL;
+ 
+}
+
  int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
  {
  	int status;
@@ -1335,6 +1440,22 @@ int write_sha1_from_fd(const unsigned ch
  	return 0;
  }

+int has_pack_index(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_index_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
+int has_pack_file(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
  int has_sha1_pack(const unsigned char *sha1)
  {
  	struct pack_entry e;

^ permalink raw reply	[relevance 12%]

* [PATCH 1/2] Functions for managing the set of packs the library is using (whitespace fixed)
    2005-07-31 20:10 12% ` [PATCH 1/2] Functions for managing the set of packs the library is using barkalow
@ 2005-08-01  0:53 12% ` barkalow
  1 sibling, 0 replies; 200+ results
From: barkalow @ 2005-08-01  0:53 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This adds support for reading an uninstalled index, and installing a
pack file that was added while the program was running, as well as
functions for determining where to put the file.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---

 cache.h     |   13 ++++++
 sha1_file.c |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 135 insertions(+), 1 deletions(-)

20fcc8f66a6780cf9bbd2fc2ba3b918c33696a67
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -172,6 +172,8 @@ extern void rollback_index_file(struct c
 extern char *mkpath(const char *fmt, ...);
 extern char *git_path(const char *fmt, ...);
 extern char *sha1_file_name(const unsigned char *sha1);
+extern char *sha1_pack_name(const unsigned char *sha1);
+extern char *sha1_pack_index_name(const unsigned char *sha1);
 
 int safe_create_leading_directories(char *path);
 
@@ -200,6 +202,9 @@ extern int write_sha1_to_fd(int fd, cons
 extern int has_sha1_pack(const unsigned char *sha1);
 extern int has_sha1_file(const unsigned char *sha1);
 
+extern int has_pack_file(const unsigned char *sha1);
+extern int has_pack_index(const unsigned char *sha1);
+
 /* Convert to/from hex/sha1 representation */
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
@@ -276,6 +281,7 @@ extern struct packed_git {
 	void *pack_base;
 	unsigned int pack_last_used;
 	unsigned int pack_use_cnt;
+	unsigned char sha1[20];
 	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
 } *packed_git;
 
@@ -298,7 +304,14 @@ extern int path_match(const char *path, 
 extern int get_ack(int fd, unsigned char *result_sha1);
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);
 
+extern struct packed_git *parse_pack_index(unsigned char *sha1);
+
 extern void prepare_packed_git(void);
+extern void install_packed_git(struct packed_git *pack);
+
+extern struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+					 struct packed_git *packs);
+
 extern int use_packed_git(struct packed_git *);
 extern void unuse_packed_git(struct packed_git *);
 extern struct packed_git *add_packed_git(char *, int);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -200,6 +200,56 @@ char *sha1_file_name(const unsigned char
 	return base;
 }
 
+char *sha1_pack_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.pack", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	
+	return base;
+}
+
+char *sha1_pack_index_name(const unsigned char *sha1)
+{
+	static const char hex[] = "0123456789abcdef";
+	static char *name, *base, *buf;
+	int i;
+
+	if (!base) {
+		const char *sha1_file_directory = get_object_directory();
+		int len = strlen(sha1_file_directory);
+		base = xmalloc(len + 60);
+		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.idx", sha1_file_directory);
+		name = base + len + 11;
+	}
+
+	buf = name;
+
+	for (i = 0; i < 20; i++) {
+		unsigned int val = *sha1++;
+		*buf++ = hex[val >> 4];
+		*buf++ = hex[val & 0xf];
+	}
+	
+	return base;
+}
+
 struct alternate_object_database *alt_odb;
 
 /*
@@ -360,6 +410,14 @@ void unuse_packed_git(struct packed_git 
 
 int use_packed_git(struct packed_git *p)
 {
+	if (!p->pack_size) {
+		struct stat st;
+		// We created the struct before we had the pack
+		stat(p->pack_name, &st);
+		if (!S_ISREG(st.st_mode))
+			die("packfile %s not a regular file", p->pack_name);
+		p->pack_size = st.st_size;
+	}
 	if (!p->pack_base) {
 		int fd;
 		struct stat st;
@@ -387,8 +445,10 @@ int use_packed_git(struct packed_git *p)
 		 * this is cheap.
 		 */
 		if (memcmp((char*)(p->index_base) + p->index_size - 40,
-			   p->pack_base + p->pack_size - 20, 20))
+			   p->pack_base + p->pack_size - 20, 20)) {
+			      
 			die("packfile %s does not match index.", p->pack_name);
+		}
 	}
 	p->pack_last_used = pack_used_ctr++;
 	p->pack_use_cnt++;
@@ -426,6 +486,37 @@ struct packed_git *add_packed_git(char *
 	return p;
 }
 
+struct packed_git *parse_pack_index(unsigned char *sha1)
+{
+	struct packed_git *p;
+	unsigned long idx_size;
+	void *idx_map;
+	char *path = sha1_pack_index_name(sha1);
+
+	if (check_packed_git_idx(path, &idx_size, &idx_map))
+		return NULL;
+
+	path = sha1_pack_name(sha1);
+
+	p = xmalloc(sizeof(*p) + strlen(path) + 2);
+	strcpy(p->pack_name, path);
+	p->index_size = idx_size;
+	p->pack_size = 0;
+	p->index_base = idx_map;
+	p->next = NULL;
+	p->pack_base = NULL;
+	p->pack_last_used = 0;
+	p->pack_use_cnt = 0;
+	memcpy(p->sha1, sha1, 20);
+	return p;
+}
+
+void install_packed_git(struct packed_git *pack)
+{
+	pack->next = packed_git;
+	packed_git = pack;
+}
+
 static void prepare_packed_git_one(char *objdir)
 {
 	char path[PATH_MAX];
@@ -989,6 +1080,20 @@ static int find_pack_entry(const unsigne
 	return 0;
 }
 
+struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+				  struct packed_git *packs)
+{
+	struct packed_git *p;
+	struct pack_entry e;
+
+	for (p = packs; p; p = p->next) {
+		if (find_pack_entry_one(sha1, &e, p))
+			return p;
+	}
+	return NULL;
+	
+}
+
 int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
 {
 	int status;
@@ -1335,6 +1440,22 @@ int write_sha1_from_fd(const unsigned ch
 	return 0;
 }
 
+int has_pack_index(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_index_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
+int has_pack_file(const unsigned char *sha1)
+{
+	struct stat st;
+	if (stat(sha1_pack_name(sha1), &st))
+		return 0;
+	return 1;
+}
+
 int has_sha1_pack(const unsigned char *sha1)
 {
 	struct pack_entry e;

^ permalink raw reply	[relevance 12%]

* [PATCH 3/3] Parallelize pulling by ssh
  @ 2005-08-02 23:46 14% ` barkalow
  0 siblings, 0 replies; 200+ results
From: barkalow @ 2005-08-02 23:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This causes ssh-pull to request objects in prefetch() and read then in
fetch(), such that it reduces the unpipelined round-trip time.

This also makes sha1_write_from_fd() support having a buffer of data
which it accidentally read from the fd after the object; this was
formerly not a problem, because it would always get a short read at
the end of an object, because the next object had not been
requested. This is no longer true.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---

 cache.h     |    3 ++-
 sha1_file.c |   37 ++++++++++++++++++++++---------------
 ssh-pull.c  |   44 ++++++++++++++++++++++++++++++++++++--------
 3 files changed, 60 insertions(+), 24 deletions(-)

9bd15230cb65acc78a97550c9467f98a04720ee8
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -198,7 +198,8 @@ extern int check_sha1_signature(const un
 /* Read a tree into the cache */
 extern int read_tree(void *buffer, unsigned long size, int stage, const char **paths);
 
-extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
+extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
+			      size_t bufsize, size_t *bufposn);
 extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
 
 extern int has_sha1_pack(const unsigned char *sha1);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1389,14 +1389,14 @@ int write_sha1_to_fd(int fd, const unsig
 	return 0;
 }
 
-int write_sha1_from_fd(const unsigned char *sha1, int fd)
+int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
+		       size_t bufsize, size_t *bufposn)
 {
 	char *filename = sha1_file_name(sha1);
 
 	int local;
 	z_stream stream;
 	unsigned char real_sha1[20];
-	unsigned char buf[4096];
 	unsigned char discard[4096];
 	int ret;
 	SHA_CTX c;
@@ -1414,7 +1414,24 @@ int write_sha1_from_fd(const unsigned ch
 
 	do {
 		ssize_t size;
-		size = read(fd, buf, 4096);
+		if (*bufposn) {
+			stream.avail_in = *bufposn;
+			stream.next_in = buffer;
+			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);
+			write(local, buffer, *bufposn - stream.avail_in);
+			memmove(buffer, buffer + *bufposn - stream.avail_in,
+				stream.avail_in);
+			*bufposn = stream.avail_in;
+			if (ret != Z_OK)
+				break;
+		}
+		size = read(fd, buffer + *bufposn, bufsize - *bufposn);
 		if (size <= 0) {
 			close(local);
 			unlink(filename);
@@ -1423,18 +1440,8 @@ int write_sha1_from_fd(const unsigned ch
 			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);
+		*bufposn += size;
+	} while (1);
 	inflateEnd(&stream);
 
 	close(local);
diff --git a/ssh-pull.c b/ssh-pull.c
--- a/ssh-pull.c
+++ b/ssh-pull.c
@@ -10,24 +10,49 @@ static int fd_out;
 static unsigned char remote_version = 0;
 static unsigned char local_version = 1;
 
+ssize_t force_write(int fd, void *buffer, size_t length)
+{
+	ssize_t ret = 0;
+	while (ret < length) {
+		ssize_t size = write(fd, buffer + ret, length - ret);
+		if (size < 0) {
+			return size;
+		}
+		if (size == 0) {
+			return ret;
+		}
+		ret += size;
+	}
+	return ret;
+}
+
 void prefetch(unsigned char *sha1)
 {
+	char type = 'o';
+	force_write(fd_out, &type, 1);
+	force_write(fd_out, sha1, 20);
+	//memcpy(requested + 20 * prefetches++, sha1, 20);
 }
 
+static char conn_buf[4096];
+static size_t conn_buf_posn = 0;
+
 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 (conn_buf_posn) {
+		remote = conn_buf[0];
+		memmove(conn_buf, conn_buf + 1, --conn_buf_posn);
+	} else {
+		if (read(fd_in, &remote, 1) < 1)
+			return -1;
+	}
+	//fprintf(stderr, "Got %d\n", remote);
 	if (remote < 0)
 		return remote;
-	ret = write_sha1_from_fd(sha1, fd_in);
+	ret = write_sha1_from_fd(sha1, fd_in, conn_buf, 4096, &conn_buf_posn);
 	if (!ret)
 		pull_say("got %s\n", sha1_to_hex(sha1));
 	return ret;

^ permalink raw reply	[relevance 14%]

* [PATCH] Install sample hooks
@ 2005-08-03  6:23 11% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-03  6:23 UTC (permalink / raw)
  To: git

Josef Weidendorfer made a good suggestion to throw in sample
hooks, disabled by default, to newly created repositories.  Here
is a proposed patch.  I will advance it to the master branch if
I do not hear objections, probably by the end of the week.

------------
A template mechanism to populate newly initialized repository
with default set of files is introduced.  Use it to ship example
hooks that can be used for update and post update checks, as
Josef Weidendorfer suggests.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 Makefile                     |    5 +
 cache.h                      |    4 +
 init-db.c                    |  142 ++++++++++++++++++++++++++++++++++++++++++
 templates/Makefile           |   19 ++++++
 templates/hooks--post-update |    8 ++
 templates/hooks--update      |   21 ++++++
 6 files changed, 199 insertions(+), 0 deletions(-)
 create mode 100644 templates/Makefile
 create mode 100644 templates/hooks--post-update
 create mode 100644 templates/hooks--update

a03cd67d2ff5dd0cf43a0be53e6f35e4cb684b8e
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,8 @@ CFLAGS+=$(COPTS) -Wall $(DEFINES)
 
 prefix=$(HOME)
 bindir=$(prefix)/bin
+etcdir=$(prefix)/etc
+etcgitdir=$(etcdir)/git-core
 # dest=
 
 CC?=gcc
@@ -143,6 +145,7 @@ endif
 endif
 
 CFLAGS += '-DSHA1_HEADER=$(SHA1_HEADER)'
+CFLAGS += '-DDEFAULT_GIT_TEMPLATE_ENVIRONMENT="$(etcgitdir)/templates"'
 
 
 
@@ -195,6 +198,7 @@ check:
 install: $(PROG) $(SCRIPTS)
 	$(INSTALL) -m755 -d $(dest)$(bindir)
 	$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bindir)
+	$(MAKE) -C templates install
 
 install-tools:
 	$(MAKE) -C tools install
@@ -235,4 +239,5 @@ clean:
 	rm -f git-core-*.tar.gz git-core.spec
 	$(MAKE) -C tools/ clean
 	$(MAKE) -C Documentation/ clean
+	$(MAKE) -C templates/ clean
 	$(MAKE) -C t/ clean
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -128,6 +128,10 @@ extern unsigned int active_nr, active_al
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIRECTORY"
+#ifndef DEFAULT_GIT_TEMPLATE_ENVIRONMENT
+#define DEFAULT_GIT_TEMPLATE_ENVIRONMENT "/etc/git-core/templates"
+#endif
 
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
diff --git a/init-db.c b/init-db.c
--- a/init-db.c
+++ b/init-db.c
@@ -15,6 +15,147 @@ static void safe_create_dir(const char *
 	}
 }
 
+static int copy_file(const char *dst, const char *src, int mode)
+{
+	int fdi, fdo;
+
+	mode = (mode & 0111) ? 0777 : 0666;
+	if ((fdi = open(src, O_RDONLY)) < 0)
+		return fdi;
+	if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
+		close(fdi);
+		return fdo;
+	}
+	while (1) {
+		char buf[BUFSIZ];
+		ssize_t leni, leno, ofs;
+		leni = read(fdi, buf, sizeof(buf));
+		if (leni < 0) {
+		error_return:
+			close(fdo);
+			close(fdi);
+			return -1;
+		}
+		if (!leni)
+			break;
+		ofs = 0;
+		do {
+			leno = write(fdo, buf+ofs, leni);
+			if (leno < 0)
+				goto error_return;
+			leni -= leno;
+			ofs += leno;
+		} while (0 < leni);
+	}
+	close(fdo);
+	close(fdi);
+	return 0;
+}
+
+static void copy_templates_1(char *path, int baselen,
+			     char *template, int template_baselen,
+			     DIR *dir)
+{
+	struct dirent *de;
+
+	/* Note: if ".git/hooks" file exists in the repository being
+	 * re-initialized, /etc/core-git/templates/hooks/update would
+	 * cause git-init-db to fail here.  I think this is sane but
+	 * it means that the set of templates we ship by default, along
+	 * with the way the namespace under .git/ is organized, should
+	 * be really carefully chosen.
+	 */
+	safe_create_dir(path);
+	while ((de = readdir(dir)) != NULL) {
+		struct stat st_git, st_template;
+		int namelen;
+		int exists = 0;
+
+		if (de->d_name[0] == '.')
+			continue;
+		namelen = strlen(de->d_name);
+		if ((PATH_MAX <= baselen + namelen) ||
+		    (PATH_MAX <= template_baselen + namelen))
+			die("insanely long template name %s", de->d_name);
+		memcpy(path + baselen, de->d_name, namelen+1);
+		memcpy(template + template_baselen, de->d_name, namelen+1);
+		if (lstat(path, &st_git)) {
+			if (errno != ENOENT)
+				die("cannot stat %s", path);
+		}
+		else
+			exists = 1;
+
+		if (lstat(template, &st_template))
+			die("cannot stat template %s", template);
+
+		if (S_ISDIR(st_template.st_mode)) {
+			DIR *subdir = opendir(template);
+			int baselen_sub = baselen + namelen;
+			int template_baselen_sub = template_baselen + namelen;
+			if (!subdir)
+				die("cannot opendir %s", template);
+			path[baselen_sub++] =
+				template[template_baselen_sub++] = '/';
+			path[baselen_sub] =
+				template[template_baselen_sub] = 0;
+			copy_templates_1(path, baselen_sub,
+					 template, template_baselen_sub,
+					 subdir);
+			closedir(subdir);
+		}
+		else if (exists)
+			continue;
+		else if (S_ISLNK(st_template.st_mode)) {
+			char lnk[256];
+			int len;
+			len = readlink(template, lnk, sizeof(lnk));
+			if (len < 0)
+				die("cannot readlink %s", template);
+			if (sizeof(lnk) <= len)
+				die("insanely long symlink %s", template);
+			lnk[len] = 0;
+			if (symlink(lnk, path))
+				die("cannot symlink %s %s", lnk, path);
+		}
+		else if (S_ISREG(st_template.st_mode)) {
+			if (copy_file(path, template, st_template.st_mode))
+				die("cannot copy %s to %s", template, path);
+		}
+		else
+			error("ignoring template %s", template);
+	}
+}
+
+static void copy_templates(const char *git_dir)
+{
+	char path[PATH_MAX];
+	char template_path[PATH_MAX];
+	char *template_dir;
+	int len, template_len;
+	DIR *dir;
+
+	strcpy(path, git_dir);
+	len = strlen(path);
+	template_dir = gitenv(TEMPLATE_DIR_ENVIRONMENT);
+	if (!template_dir)
+		template_dir = DEFAULT_GIT_TEMPLATE_ENVIRONMENT;
+	strcpy(template_path, template_dir);
+	template_len = strlen(template_path);
+	if (template_path[template_len-1] != '/') {
+		template_path[template_len++] = '/';
+		template_path[template_len] = 0;
+	}
+
+	dir = opendir(template_path);
+	if (!dir)
+		return;
+	copy_templates_1(path, len,
+			 template_path, template_len,
+			 dir);
+	closedir(dir);
+}
+
 static void create_default_files(const char *git_dir)
 {
 	unsigned len = strlen(git_dir);
@@ -48,6 +189,7 @@ static void create_default_files(const c
 			exit(1);
 		}
 	}
+	copy_templates(path);
 }
 
 /*
diff --git a/templates/Makefile b/templates/Makefile
new file mode 100644
--- /dev/null
+++ b/templates/Makefile
@@ -0,0 +1,19 @@
+# make
+
+INSTALL=install
+prefix=$(HOME)
+etcdir=$(prefix)/etc
+etcgitdir=$(etcdir)/git-core
+templatedir=$(etcgitdir)/templates
+# dest=
+
+all:
+clean:
+
+install:
+	$(INSTALL) -d -m755 $(dest)$(templatedir)/hooks/
+	$(foreach s,$(wildcard hooks--*),\
+		$(INSTALL) -m644 $s \
+		$(dest)$(templatedir)/hooks/$(patsubst hooks--%,%,$s);)
+	$(INSTALL) -d -m755 $(dest)$(templatedir)/info
+	$(INSTALL) -d -m755 $(dest)$(templatedir)/branches
diff --git a/templates/hooks--post-update b/templates/hooks--post-update
new file mode 100644
--- /dev/null
+++ b/templates/hooks--post-update
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, make this file executable by "chmod +x post-update".
+
+exec git-update-server-info
diff --git a/templates/hooks--update b/templates/hooks--update
new file mode 100644
--- /dev/null
+++ b/templates/hooks--update
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# An example hook script to mail out commit update information.
+#
+# To enable this hook:
+# (1) change the recipient e-mail address
+# (2) make this file executable by "chmod +x update".
+#
+
+recipient="commit-list@mydomain.xz"
+
+if expr "$2" : '0*$' >/dev/null
+then
+	echo "Created a new ref, with the following commits:"
+	git-rev-list --pretty "$2"
+else
+	echo "New commits:"
+	git-rev-list --pretty "$3" "^$2"
+fi |
+mail -s "Changes to ref $1" "$recipient"
+exit 0

^ permalink raw reply	[relevance 11%]

* [PATCH] (preview) Renaming push.
  @ 2005-08-03 23:25  8%         ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-03 23:25 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

Linus Torvalds <torvalds@osdl.org> writes:

> The real problem with git-send-pack is that the local and remote names 
> have to be the same, which is a bug, really. It _should_ be perfectly fine 
> to do something like
>
> 	git-send-pack ..dest.. localname:remotename
>
> which would push the local "localname" branch to the remote "remotename" 
> branch.

Yes, and that is what I have been cooking today ;-).

This patch is a preview, only because I have not converted the
pull side yet.  My limited testing shows that you can push refs
under different names fine with this patch.

The plan is to also let people say the renaming for pull side
like this.

        git-fetch-pack <remote> remotename:localname...

Note that remote/local is confusing when we consider both pull
and push sides, so we should call them srcname and dstname.  The
commit message uses these words.

-jc

------------
This allows git-send-pack to push local refs to a destination
repository under different names.

Here is the name mapping rules for refs.

* If there is no ref mapping on the command line:

 - if '--all' is specified, it is equivalent to specifying
   <local> ":" <local> for all the existing local refs on the
   command line
 - otherwise, it is equivalent to specifying <ref> ":" <ref> for
   all the refs that exist on both sides.

* <name> is just a shorthand for <name> ":" <name>

* <src> ":" <dst>

  push ref that matches <src> to ref that matches <dst>.

  - It is an error if <src> does not match exactly one of local
    refs.

  - It is an error if <dst> matches more than one remote refs.

  - If <dst> does not match any remote refs, either

    - it has to start with "refs/"; <dst> is used as the
      destination literally in this case.

    - <src> == <dst> and the ref that matched the <src> must not
      exist in the set of remote refs; the ref matched <src>
      locally is used as the name of the destination.

For example,

  - "git-send-pack --all <remote>" works exactly as before;

  - "git-send-pack <remote> master:upstream" pushes local master
    to remote ref that matches "upstream".  If there is no such
    ref, it is an error.

  - "git-send-pack <remote> master:refs/heads/upstream" pushes
    local master to remote refs/heads/upstream, even when
    refs/heads/upstream does not exist.

  - "git-send-pack <remote> master" into an empty remote
    repository pushes the local ref/heads/master to the remote
    ref/heads/master.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h     |    3 +
 connect.c   |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 send-pack.c |  146 ++++++++++++++++++++------------------------------
 3 files changed, 230 insertions(+), 91 deletions(-)

b959d297c7206b0b634160ac015122f70389415b
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -298,12 +298,15 @@ struct ref {
 	struct ref *next;
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
+	struct ref *peer_ref; /* when renaming */
 	char name[0];
 };
 
 extern int git_connect(int fd[2], char *url, const char *prog);
 extern int finish_connect(pid_t pid);
 extern int path_match(const char *path, int nr, char **match);
+extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+		      int nr_refspec, char **refspec, int all);
 extern int get_ack(int fd, unsigned char *result_sha1);
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);
 
diff --git a/connect.c b/connect.c
--- a/connect.c
+++ b/connect.c
@@ -31,11 +31,9 @@ struct ref **get_remote_heads(int in, st
 		name = buffer + 41;
 		if (nr_match && !path_match(name, nr_match, match))
 			continue;
-		ref = xmalloc(sizeof(*ref) + len - 40);
+		ref = xcalloc(1, sizeof(*ref) + len - 40);
 		memcpy(ref->old_sha1, old_sha1, 20);
-		memset(ref->new_sha1, 0, 20);
 		memcpy(ref->name, buffer + 41, len - 40);
-		ref->next = NULL;
 		*list = ref;
 		list = &ref->next;
 	}
@@ -81,6 +79,174 @@ int path_match(const char *path, int nr,
 	return 0;
 }
 
+struct refspec {
+	char *src;
+	char *dst;
+};
+
+static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
+{
+	int i;
+	struct refspec *rs = xmalloc(sizeof(*rs) * (nr_refspec + 1));
+	for (i = 0; i < nr_refspec; i++) {
+		char *sp, *dp, *ep;
+		sp = refspec[i];
+		ep = strchr(sp, ':');
+		if (ep) {
+			dp = ep + 1;
+			*ep = 0;
+		}
+		else
+			dp = sp;
+		rs[i].src = sp;
+		rs[i].dst = dp;
+	}
+	rs[nr_refspec].src = rs[nr_refspec].dst = NULL;
+	return rs;
+}
+
+static int count_refspec_match(const char *pattern,
+			       struct ref *refs,
+			       struct ref **matched_ref)
+{
+	int match;
+	int patlen = strlen(pattern);
+
+	for (match = 0; refs; refs = refs->next) {
+		char *name = refs->name;
+		int namelen = strlen(name);
+		if (namelen < patlen ||
+		    memcmp(name + namelen - patlen, pattern, patlen))
+			continue;
+		if (namelen != patlen && name[namelen - patlen - 1] != '/')
+			continue;
+		match++;
+		*matched_ref = refs;
+	}
+	return match;
+}
+
+static void link_dst_tail(struct ref *ref, struct ref ***tail)
+{
+	**tail = ref;
+	*tail = &ref->next;
+	**tail = NULL;
+}
+
+static int match_explicit_refs(struct ref *src, struct ref *dst,
+			       struct ref ***dst_tail, struct refspec *rs)
+{
+	int i, errs;
+	for (i = errs = 0; rs[i].src; i++) {
+		struct ref *matched_src, *matched_dst;
+
+		matched_src = matched_dst = NULL;
+		switch (count_refspec_match(rs[i].src, src, &matched_src)) {
+		case 1:
+			break;
+		case 0:
+			errs = 1;
+			error("src refspec %s does not match any.");
+			break;
+		default:
+			errs = 1;
+			error("src refspec %s matches more than one.",
+			      rs[i].src);
+			break;
+		}
+		switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
+		case 1:
+			break;
+		case 0:
+			if (!memcmp(rs[i].dst, "refs/", 5)) {
+				int len = strlen(rs[i].dst) + 1;
+				matched_dst = xcalloc(1, sizeof(*dst) + len);
+				memcpy(matched_dst->name, rs[i].dst, len);
+				link_dst_tail(matched_dst, dst_tail);
+			}
+			else if (!strcmp(rs[i].src, rs[i].dst) &&
+				 matched_src) {
+				/* pushing "master:master" when
+				 * remote does not have master yet.
+				 */
+				int len = strlen(matched_src->name);
+				matched_dst = xcalloc(1, sizeof(*dst) + len);
+				memcpy(matched_dst->name, matched_src->name,
+				       len);
+				link_dst_tail(matched_dst, dst_tail);
+			}
+			else {
+				errs = 1;
+				error("dst refspec %s does not match any "
+				      "existing ref on the remote and does "
+				      "not start with refs/.", rs[i].dst);
+			}
+			break;
+		default:
+			errs = 1;
+			error("dst refspec %s matches more than one.",
+			      rs[i].dst);
+			break;
+		}
+		if (errs)
+			continue;
+		if (matched_src->peer_ref) {
+			errs = 1;
+			error("src ref %s is sent to more than one dst.",
+			      matched_src->name);
+		}
+		else
+			matched_src->peer_ref = matched_dst;
+		if (matched_dst->peer_ref) {
+			errs = 1;
+			error("dst ref %s receives from more than one src.",
+			      matched_dst->name);
+		}
+		else
+			matched_dst->peer_ref = matched_src;
+	}
+	return -errs;
+}
+
+static struct ref *find_ref_by_name(struct ref *list, const char *name)
+{
+	for ( ; list; list = list->next)
+		if (!strcmp(list->name, name))
+			return list;
+	return NULL;
+}
+
+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+	       int nr_refspec, char **refspec, int all)
+{
+	struct refspec *rs = parse_ref_spec(nr_refspec, refspec);
+
+	if (nr_refspec)
+		return match_explicit_refs(src, dst, dst_tail, rs);
+
+	/* pick the remainder */
+	for ( ; src; src = src->next) {
+		struct ref *dst_peer;
+		if (src->peer_ref)
+			continue;
+		dst_peer = find_ref_by_name(dst, src->name);
+		if (dst_peer && dst_peer->peer_ref)
+			continue;
+		if (!dst_peer) {
+			if (!all)
+				continue;
+			/* Create a new one and link it */
+			int len = strlen(src->name) + 1;
+			dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
+			memcpy(dst_peer->name, src->name, len);
+			memcpy(dst_peer->new_sha1, src->new_sha1, 20);
+			link_dst_tail(dst_peer, dst_tail);
+		}
+		dst_peer->peer_ref = src;
+	}
+	return 0;
+}
+
 enum protocol {
 	PROTO_LOCAL = 1,
 	PROTO_SSH,
diff --git a/send-pack.c b/send-pack.c
--- a/send-pack.c
+++ b/send-pack.c
@@ -43,7 +43,8 @@ static void exec_rev_list(struct ref *re
 		char *buf = malloc(100);
 		if (i > 900)
 			die("git-rev-list environment overflow");
-		if (!is_zero_sha1(refs->old_sha1)) {
+		if (!is_zero_sha1(refs->old_sha1) &&
+		    has_sha1_file(refs->old_sha1)) {
 			args[i++] = buf;
 			snprintf(buf, 50, "^%s", sha1_to_hex(refs->old_sha1));
 			buf += 50;
@@ -103,21 +104,6 @@ static int pack_objects(int fd, struct r
 	return 0;
 }
 
-static int read_ref(const char *ref, unsigned char *sha1)
-{
-	int fd, ret;
-	char buffer[60];
-
-	fd = open(git_path("%s", ref), O_RDONLY);
-	if (fd < 0)
-		return -1;
-	ret = -1;
-	if (read(fd, buffer, sizeof(buffer)) >= 40)
-		ret = get_sha1_hex(buffer, sha1);
-	close(fd);
-	return ret;
-}
-
 static int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 {
 	struct commit *new, *old;
@@ -143,108 +129,92 @@ static int ref_newer(const unsigned char
 	return 0;
 }
 
-static int local_ref_nr_match;
-static char **local_ref_match;
-static struct ref *local_ref_list;
-static struct ref **local_last_ref;
+static struct ref *local_refs, **local_tail;
+static struct ref *remote_refs, **remote_tail;
 
-static int try_to_match(const char *refname, const unsigned char *sha1)
+static int one_local_ref(const char *refname, const unsigned char *sha1)
 {
 	struct ref *ref;
-	int len;
-
-	if (!path_match(refname, local_ref_nr_match, local_ref_match)) {
-		if (!send_all)
-			return 0;
-
-		/* If we have it listed already, skip it */
-		for (ref = local_ref_list ; ref ; ref = ref->next) {
-			if (!strcmp(ref->name, refname))
-				return 0;
-		}
-	}
-
-	len = strlen(refname)+1;
-	ref = xmalloc(sizeof(*ref) + len);
-	memset(ref->old_sha1, 0, 20);
+	int len = strlen(refname) + 1;
+	ref = xcalloc(1, sizeof(*ref) + len);
 	memcpy(ref->new_sha1, sha1, 20);
 	memcpy(ref->name, refname, len);
-	ref->next = NULL;
-	*local_last_ref = ref;
-	local_last_ref = &ref->next;
+	*local_tail = ref;
+	local_tail = &ref->next;
 	return 0;
 }
 
-static int send_pack(int in, int out, int nr_match, char **match)
+static void get_local_heads(void)
+{
+	local_tail = &local_refs;
+	for_each_ref(one_local_ref);
+}
+
+static int send_pack(int in, int out, int nr_refspec, char **refspec)
 {
-	struct ref *ref_list, **last_ref;
 	struct ref *ref;
 	int new_refs;
 
-	/* First we get all heads, whether matching or not.. */
-	last_ref = get_remote_heads(in, &ref_list, 0, NULL);
-
+	/* No funny business with the matcher */
+	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL);
+	get_local_heads();
+
+	/* match them up */
+	if (!remote_tail)
+		remote_tail = &remote_refs;
+	if (match_refs(local_refs, remote_refs, &remote_tail,
+		       nr_refspec, refspec, send_all))
+		return -1;
 	/*
-	 * Go through the refs, see if we want to update
-	 * any of them..
+	 * Finally, tell the other end!
 	 */
-	for (ref = ref_list; ref; ref = ref->next) {
-		unsigned char new_sha1[20];
-		char *name = ref->name;
-
-		if (nr_match && !path_match(name, nr_match, match))
-			continue;
-
-		if (read_ref(name, new_sha1) < 0)
-			continue;
-
-		if (!memcmp(ref->old_sha1, new_sha1, 20)) {
-			fprintf(stderr, "'%s' unchanged\n", name);
+	new_refs = 0;
+	for (ref = remote_refs; ref; ref = ref->next) {
+		char old_hex[60], *new_hex;
+		if (!ref->peer_ref)
 			continue;
+		if (!is_zero_sha1(ref->old_sha1)) {
+			if (!has_sha1_file(ref->old_sha1)) {
+				error("remote '%s' object %s does not "
+				      "exist on local",
+				      ref->name, sha1_to_hex(ref->old_sha1));
+				continue;
+			}
+			if (!ref_newer(ref->peer_ref->new_sha1,
+				       ref->old_sha1)) {
+				error("remote ref '%s' is not a strict "
+				      "subset of local ref '%s'.", ref->name,
+				      ref->peer_ref->name);
+				continue;
+			}
 		}
-
-		if (!ref_newer(new_sha1, ref->old_sha1)) {
-			error("remote '%s' isn't a strict parent of local", name);
+		if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
+			fprintf(stderr, "'%s': up-to-date\n", ref->name);
 			continue;
 		}
-
-		/* Ok, mark it for update */
-		memcpy(ref->new_sha1, new_sha1, 20);
-	}
-
-	/*
-	 * See if we have any refs that the other end didn't have
-	 */
-	if (nr_match || send_all) {
-		local_ref_nr_match = nr_match;
-		local_ref_match = match;
-		local_ref_list = ref_list;
-		local_last_ref = last_ref;
-		for_each_ref(try_to_match);
-	}
-
-	/*
-	 * Finally, tell the other end!
-	 */
-	new_refs = 0;
-	for (ref = ref_list; ref; ref = ref->next) {
-		char old_hex[60], *new_hex;
-		if (is_zero_sha1(ref->new_sha1))
+		memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
+		if (is_zero_sha1(ref->new_sha1)) {
+			error("cannot happen anymore");
 			continue;
+		}
 		new_refs++;
 		strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 		new_hex = sha1_to_hex(ref->new_sha1);
 		packet_write(out, "%s %s %s", old_hex, new_hex, ref->name);
-		fprintf(stderr, "'%s': updating from %s to %s\n", ref->name, old_hex, new_hex);
+		fprintf(stderr, "updating '%s'", ref->name);
+		if (strcmp(ref->name, ref->peer_ref->name))
+			fprintf(stderr, " using '%s'", ref->peer_ref->name);
+		fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
 	}
-	
+
 	packet_flush(out);
 	if (new_refs)
-		pack_objects(out, ref_list);
+		pack_objects(out, remote_refs);
 	close(out);
 	return 0;
 }
 
+
 int main(int argc, char **argv)
 {
 	int i, nr_heads = 0;

^ permalink raw reply	[relevance 8%]

* [PATCH 1/1] git: add git_mkstemp()
@ 2005-08-04 20:43 18% Holger Eitzenberger
  0 siblings, 0 replies; 200+ results
From: Holger Eitzenberger @ 2005-08-04 20:43 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Hi,

the following snippet adds git_mkstemp() to libgit (path.c).

/holger

[-- Attachment #2: git_add_git_mkstemp.patch --]
[-- Type: text/x-patch, Size: 1720 bytes --]

add git_mkstemp() to libgit

---
commit 1a1f2cb5c27ed26e6ef8dd34209e561bdf256c22
tree 868b67b55978394d288ac4f2ca8edcbbad4355bd
parent 10833f5e7d0da63ca976607864282d41b5faff1b
author Holger Eitzenberger <holger@my-eitzenberger.de> Thu, 04 Aug 2005 22:28:32 +0200
committer Holger Eitzenberger <holger@elmo.intranet.astaro.de> Thu, 04 Aug 2005 22:28:32 +0200

 cache.h |    3 +++
 path.c  |   26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -174,7 +174,10 @@ extern char *mkpath(const char *fmt, ...
 extern char *git_path(const char *fmt, ...);
 extern char *sha1_file_name(const unsigned char *sha1);
 
+int git_mkstemp(char *path, size_t n, const char *template);
+
 int safe_create_leading_directories(char *path);
+char *safe_strncpy(char *, const char *, size_t);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
diff --git a/path.c b/path.c
--- a/path.c
+++ b/path.c
@@ -58,3 +58,29 @@ char *git_path(const char *fmt, ...)
 		return bad_path;
 	return cleanup_path(pathname);
 }
+
+
+/* git_mkstemp() - create tmp file honoring TMPDIR variable */
+int git_mkstemp(char *path, size_t len, const char *template)
+{
+	char *env, *pch = path;
+
+	if ((env = getenv("TMPDIR")) == NULL) {
+		strcpy(pch, "/tmp/");
+		len -= 5;
+	} else
+		len -= snprintf(pch, len, "%s/", env);
+
+	safe_strncpy(pch, template, len);
+
+	return mkstemp(path);
+}
+
+
+char *safe_strncpy(char *dest, const char *src, size_t n)
+{
+	strncpy(dest, src, n);
+	dest[n - 1] = '\0';
+
+	return dest;
+}

^ permalink raw reply	[relevance 18%]

* [PATCH] -Werror fixes
@ 2005-08-09 15:30 21% Timo Sirainen
  0 siblings, 0 replies; 200+ results
From: Timo Sirainen @ 2005-08-09 15:30 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 6828 bytes --]

GCC's format __attribute__ is good for checking errors, especially with
-Werror=2 parameter. Patch below fixes most of the reported problems
against 2005-08-09 snapshot.

Also how about trying to implement some kind of generically usable
string object? Now the code uses sprintf/snprintf/etc. in various
different ways with their own memory allocations, and it looks all messy
and difficult to verify their correctness.

diff -ru git-current/apply.c git-modified/apply.c
--- git-current/apply.c	2005-08-09 18:00:06.000000000 +0300
+++ git-modified/apply.c	2005-08-09 17:50:13.712911497 +0300
@@ -563,7 +563,7 @@
 			struct fragment dummy;
 			if (parse_fragment_header(line, len, &dummy) < 0)
 				continue;
-			error("patch fragment without header at line %d: %.*s", linenr, len-1, line);
+			error("patch fragment without header at line %d: %.*s", linenr, (int)len-1, line);
 		}
 
 		if (size < len + 6)
@@ -968,7 +968,7 @@
 
 	while (frag) {
 		if (apply_one_fragment(desc, frag) < 0)
-			return error("patch failed: %s:%d", patch->old_name, frag->oldpos);
+			return error("patch failed: %s:%ld", patch->old_name, frag->oldpos);
 		frag = frag->next;
 	}
 	return 0;
diff -ru git-current/cache.h git-modified/cache.h
--- git-current/cache.h	2005-08-09 18:00:06.000000000 +0300
+++ git-modified/cache.h	2005-08-09 18:14:37.858158948 +0300
@@ -40,6 +40,10 @@
 #define NORETURN
 #endif
 
+#ifndef __attribute__
+#define __attribute(x)
+#endif
+
 /*
  * Intensive research over the course of many years has shown that
  * port 9418 is totally unused by anything else. Or
@@ -171,8 +175,8 @@
 #define TYPE_CHANGED    0x0040
 
 /* Return a statically allocated filename matching the sha1 signature */
-extern char *mkpath(const char *fmt, ...);
-extern char *git_path(const char *fmt, ...);
+extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
 extern char *sha1_pack_name(const unsigned char *sha1);
 extern char *sha1_pack_index_name(const unsigned char *sha1);
@@ -218,8 +222,8 @@
 
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
-extern void die(const char *err, ...) NORETURN;
-extern int error(const char *err, ...);
+extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
 
 extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
diff -ru git-current/clone-pack.c git-modified/clone-pack.c
--- git-current/clone-pack.c	2005-08-09 18:00:06.000000000 +0300
+++ git-modified/clone-pack.c	2005-08-09 17:53:32.295922222 +0300
@@ -30,7 +30,7 @@
 
 static void write_one_ref(struct ref *ref)
 {
-	char *path = git_path(ref->name);
+	char *path = git_path("%s", ref->name);
 	int fd;
 	char *hex;
 
diff -ru git-current/connect.c git-modified/connect.c
--- git-current/connect.c	2005-08-09 18:00:06.000000000 +0300
+++ git-modified/connect.c	2005-08-09 17:46:35.187838763 +0300
@@ -166,7 +166,8 @@
 			if (matched_src)
 				break;
 			errs = 1;
-			error("src refspec %s does not match any.");
+			error("src refspec %s does not match any.",
+			      rs[i].src);
 			break;
 		default:
 			errs = 1;
diff -ru git-current/csum-file.h git-modified/csum-file.h
--- git-current/csum-file.h	2005-08-09 18:00:06.000000000 +0300
+++ git-modified/csum-file.h	2005-08-09 18:02:33.825363592 +0300
@@ -11,7 +11,7 @@
 };
 
 extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1create(const char *fmt, ...);
+extern struct sha1file *sha1create(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern int sha1close(struct sha1file *, unsigned char *, int);
 extern int sha1write(struct sha1file *, void *, unsigned int);
 extern int sha1write_compressed(struct sha1file *, void *, unsigned int);
diff -ru git-current/pack-check.c git-modified/pack-check.c
--- git-current/pack-check.c	2005-08-09 18:00:07.000000000 +0300
+++ git-modified/pack-check.c	2005-08-09 17:46:24.084918180 +0300
@@ -15,7 +15,7 @@
 	/* Header consistency check */
 	hdr = p->pack_base;
 	if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
-		return error("Packfile signature mismatch", p->pack_name);
+		return error("Packfile %s signature mismatch", p->pack_name);
 	if (hdr->hdr_version != htonl(PACK_VERSION))
 		return error("Packfile version %d different from ours %d",
 			     ntohl(hdr->hdr_version), PACK_VERSION);
diff -ru git-current/pkt-line.h git-modified/pkt-line.h
--- git-current/pkt-line.h	2005-08-09 18:00:07.000000000 +0300
+++ git-modified/pkt-line.h	2005-08-09 18:02:56.637125022 +0300
@@ -5,7 +5,7 @@
  * Silly packetized line writing interface
  */
 void packet_flush(int fd);
-void packet_write(int fd, const char *fmt, ...);
+void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 
 int packet_read_line(int fd, char *buffer, unsigned size);
 
diff -ru git-current/refs.c git-modified/refs.c
--- git-current/refs.c	2005-08-09 18:00:07.000000000 +0300
+++ git-modified/refs.c	2005-08-09 17:53:25.318217137 +0300
@@ -6,7 +6,7 @@
 static int read_ref(const char *refname, unsigned char *sha1)
 {
 	int ret = -1;
-	int fd = open(git_path(refname), O_RDONLY);
+	int fd = open(git_path("%s", refname), O_RDONLY);
 
 	if (fd >= 0) {
 		char buffer[60];
@@ -20,7 +20,7 @@
 static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1))
 {
 	int retval = 0;
-	DIR *dir = opendir(git_path(base));
+	DIR *dir = opendir(git_path("%s", base));
 
 	if (dir) {
 		struct dirent *de;
@@ -46,7 +46,7 @@
 			if (namelen > 255)
 				continue;
 			memcpy(path + baselen, de->d_name, namelen+1);
-			if (lstat(git_path(path), &st) < 0)
+			if (lstat(git_path("%s", path), &st) < 0)
 				continue;
 			if (S_ISDIR(st.st_mode)) {
 				retval = do_for_each_ref(path, fn);
diff -ru git-current/tar-tree.c git-modified/tar-tree.c
--- git-current/tar-tree.c	2005-08-09 18:00:07.000000000 +0300
+++ git-modified/tar-tree.c	2005-08-09 17:49:27.512564400 +0300
@@ -325,8 +325,8 @@
 	memcpy(&header[257], "ustar", 6);
 	memcpy(&header[263], "00", 2);
 
-	printf(&header[329], "%07o", 0);	/* devmajor */
-	printf(&header[337], "%07o", 0);	/* devminor */
+	sprintf(&header[329], "%07o", 0);	/* devmajor */
+	sprintf(&header[337], "%07o", 0);	/* devminor */
 
 	memset(&header[148], ' ', 8);
 	for (i = 0; i < RECORDSIZE; i++)


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 21%]

* [PATCH] Alternate object pool mechanism updates.
@ 2005-08-13  9:09 14% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-13  9:09 UTC (permalink / raw)
  To: git

It was a mistake to use GIT_ALTERNATE_OBJECT_DIRECTORIES
environment variable to specify what alternate object pools to
look for missing objects when working with an object database.
It is not a property of the process running the git commands,
but a property of the object database that is partial and needs
other object pools to complete the set of objects it lacks.

This patch allows you to have $GIT_OBJECT_DIRECTORY/info/alt
file whose contents is in exactly the same format as the
environment variable, to let an object database name alternate
object pools it depends on.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 cache.h      |    5 +-
 fsck-cache.c |    8 ++-
 sha1_file.c  |  146 ++++++++++++++++++++++++++++++++--------------------------
 3 files changed, 88 insertions(+), 71 deletions(-)

8150a422f79cc461316052b52263289b851d4820
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -278,9 +278,10 @@ struct checkout {
 extern int checkout_entry(struct cache_entry *ce, struct checkout *state);
 
 extern struct alternate_object_database {
-	char *base;
+	struct alternate_object_database *next;
 	char *name;
-} *alt_odb;
+	char base[0]; /* more */
+} *alt_odb_list;
 extern void prepare_alt_odb(void);
 
 extern struct packed_git {
diff --git a/fsck-cache.c b/fsck-cache.c
--- a/fsck-cache.c
+++ b/fsck-cache.c
@@ -456,13 +456,13 @@ int main(int argc, char **argv)
 	fsck_head_link();
 	fsck_object_dir(get_object_directory());
 	if (check_full) {
-		int j;
+		struct alternate_object_database *alt;
 		struct packed_git *p;
 		prepare_alt_odb();
-		for (j = 0; alt_odb[j].base; j++) {
+		for (alt = alt_odb_list; alt; alt = alt->next) {
 			char namebuf[PATH_MAX];
-			int namelen = alt_odb[j].name - alt_odb[j].base;
-			memcpy(namebuf, alt_odb[j].base, namelen);
+			int namelen = alt->name - alt->base;
+			memcpy(namebuf, alt->base, namelen);
 			namebuf[namelen - 1] = 0;
 			fsck_object_dir(namebuf);
 		}
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -222,84 +222,100 @@ char *sha1_pack_index_name(const unsigne
 	return base;
 }
 
-struct alternate_object_database *alt_odb;
+struct alternate_object_database *alt_odb_list;
+static struct alternate_object_database **alt_odb_tail;
 
 /*
  * Prepare alternate object database registry.
- * alt_odb points at an array of struct alternate_object_database.
- * This array is terminated with an element that has both its base
- * and name set to NULL.  alt_odb[n] comes from n'th non-empty
- * element from colon separated ALTERNATE_DB_ENVIRONMENT environment
- * variable, and its base points at a statically allocated buffer
- * that contains "/the/directory/corresponding/to/.git/objects/...",
- * while its name points just after the slash at the end of
- * ".git/objects/" in the example above, and has enough space to hold
- * 40-byte hex SHA1, an extra slash for the first level indirection,
- * and the terminating NUL.
- * This function allocates the alt_odb array and all the strings
- * pointed by base fields of the array elements with one xmalloc();
- * the string pool immediately follows the array.
+ *
+ * The variable alt_odb_list points at the list of struct
+ * alternate_object_database.  The elements on this list come from
+ * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
+ * environment variable, and $GIT_OBJECT_DIRECTORY/info/alt file,
+ * whose contents is exactly in the same format as that environment
+ * variable.  Its base points at a statically allocated buffer that
+ * contains "/the/directory/corresponding/to/.git/objects/...", while
+ * its name points just after the slash at the end of ".git/objects/"
+ * in the example above, and has enough space to hold 40-byte hex
+ * SHA1, an extra slash for the first level indirection, and the
+ * terminating NUL.
  */
-void prepare_alt_odb(void)
+static void link_alt_odb_entries(const char *alt, const char *ep)
 {
-	int pass, totlen, i;
 	const char *cp, *last;
-	char *op = NULL;
-	const char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
+	struct alternate_object_database *ent;
+
+	last = alt;
+	do {
+		for (cp = last; cp < ep && *cp != ':'; cp++)
+			;
+		if (last != cp) {
+			/* 43 = 40-byte + 2 '/' + terminating NUL */
+			int pfxlen = cp - last;
+			int entlen = pfxlen + 43;
+
+			ent = xmalloc(sizeof(*ent) + entlen);
+			*alt_odb_tail = ent;
+			alt_odb_tail = &(ent->next);
+			ent->next = NULL;
+
+			memcpy(ent->base, last, pfxlen);
+			ent->name = ent->base + pfxlen + 1;
+			ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
+			ent->base[entlen-1] = 0;
+		}
+		while (cp < ep && *cp == ':')
+			cp++;
+		last = cp;
+	} while (cp < ep);
+}
+
+void prepare_alt_odb(void)
+{
+	char path[PATH_MAX];
+	char *map, *ep;
+	int fd;
+	struct stat st;
+	char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
 
-	if (alt_odb)
+	sprintf(path, "%s/info/alt", get_object_directory());
+	if (alt_odb_tail)
+		return;
+	alt_odb_tail = &alt_odb_list;
+	link_alt_odb_entries(alt, alt + strlen(alt));
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return;
+	if (fstat(fd, &st) || (st.st_size == 0)) {
+		close(fd);
 		return;
-	/* The first pass counts how large an area to allocate to
-	 * hold the entire alt_odb structure, including array of
-	 * structs and path buffers for them.  The second pass fills
-	 * the structure and prepares the path buffers for use by
-	 * fill_sha1_path().
-	 */
-	for (totlen = pass = 0; pass < 2; pass++) {
-		last = alt;
-		i = 0;
-		do {
-			cp = strchr(last, ':') ? : last + strlen(last);
-			if (last != cp) {
-				/* 43 = 40-byte + 2 '/' + terminating NUL */
-				int pfxlen = cp - last;
-				int entlen = pfxlen + 43;
-				if (pass == 0)
-					totlen += entlen;
-				else {
-					alt_odb[i].base = op;
-					alt_odb[i].name = op + pfxlen + 1;
-					memcpy(op, last, pfxlen);
-					op[pfxlen] = op[pfxlen + 3] = '/';
-					op[entlen-1] = 0;
-					op += entlen;
-				}
-				i++;
-			}
-			while (*cp && *cp == ':')
-				cp++;
-			last = cp;
-		} while (*cp);
-		if (pass)
-			break;
-		alt_odb = xmalloc(sizeof(*alt_odb) * (i + 1) + totlen);
-		alt_odb[i].base = alt_odb[i].name = NULL;
-		op = (char*)(&alt_odb[i+1]);
 	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	close(fd);
+	if (map == MAP_FAILED)
+		return;
+
+	/* Remove the trailing newline */
+	for (ep = map + st.st_size - 1; map < ep && ep[-1] == '\n'; ep--)
+		;
+	link_alt_odb_entries(map, ep);
+	munmap(map, st.st_size);
 }
 
 static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
 {
-	int i;
 	char *name = sha1_file_name(sha1);
+	struct alternate_object_database *alt;
 
 	if (!stat(name, st))
 		return name;
 	prepare_alt_odb();
-	for (i = 0; (name = alt_odb[i].name) != NULL; i++) {
+	for (alt = alt_odb_list; alt; alt = alt->next) {
+		name = alt->name;
 		fill_sha1_path(name, sha1);
-		if (!stat(alt_odb[i].base, st))
-			return alt_odb[i].base;
+		if (!stat(alt->base, st))
+			return alt->base;
 	}
 	return NULL;
 }
@@ -522,18 +538,18 @@ static void prepare_packed_git_one(char 
 
 void prepare_packed_git(void)
 {
-	int i;
 	static int run_once = 0;
+	struct alternate_object_database *alt;
 
-	if (run_once++)
+	if (run_once)
 		return;
-
 	prepare_packed_git_one(get_object_directory());
 	prepare_alt_odb();
-	for (i = 0; alt_odb[i].base != NULL; i++) {
-		alt_odb[i].name[0] = 0;
-		prepare_packed_git_one(alt_odb[i].base);
+	for (alt = alt_odb_list; alt; alt = alt->next) {
+		alt->name[0] = 0;
+		prepare_packed_git_one(alt->base);
 	}
+	run_once = 1;
 }
 
 int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)

^ permalink raw reply	[relevance 14%]

* [PATCH] Add function to read an index file from an arbitrary filename.
  @ 2005-08-16  4:10 18% ` Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-08-16  4:10 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Note that the pack file has to be in the usual location if it gets
installed later.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---

 cache.h     |    2 ++
 sha1_file.c |   10 ++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

59e5c6d163edae5da6136560d48a4750cceacdc6
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -319,6 +319,8 @@ extern int get_ack(int fd, unsigned char
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
+extern struct packed_git *parse_pack_index_file(unsigned char *sha1, 
+						char *idx_path);
 
 extern void prepare_packed_git(void);
 extern void install_packed_git(struct packed_git *pack);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -476,12 +476,18 @@ struct packed_git *add_packed_git(char *
 
 struct packed_git *parse_pack_index(unsigned char *sha1)
 {
+	char *path = sha1_pack_index_name(sha1);
+	return parse_pack_index_file(sha1, path);
+}
+
+struct packed_git *parse_pack_index_file(unsigned char *sha1, char *idx_path)
+{
 	struct packed_git *p;
 	unsigned long idx_size;
 	void *idx_map;
-	char *path = sha1_pack_index_name(sha1);
+	char *path;
 
-	if (check_packed_git_idx(path, &idx_size, &idx_map))
+	if (check_packed_git_idx(idx_path, &idx_size, &idx_map))
 		return NULL;
 
 	path = sha1_pack_name(sha1);

^ permalink raw reply	[relevance 18%]

* [RFC PATCH] Add support for figuring out where in the git archive we are
@ 2005-08-16 22:45 15% Linus Torvalds
    0 siblings, 1 reply; 200+ results
From: Linus Torvalds @ 2005-08-16 22:45 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List

    
This does only "git-diff-cache" and "git-diff-files", but the concept
should work for any command that uses the working tree.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
This is really partly a serious patch, but also just a query whether 
people would want git to work in subdirectories, not just the top-level 
directory.

So you can be in linux/drivers, and if you do a

	git-diff-files -p char

then it will automatically be turned into the full pathname, and do the
right thing (ie do a diff of drivers/char only).

I didn't want to do it originally, but that was largely a complexity
issue, and an issue of there being many more things up in the air at that
time. Now, things have calmed down a bit, the interfaces are fairly
stable, and it turns out to be not that difficult to just walk up the
chain of directories until we hit the one that has the ".git" directory in
it.

I only converted "git-diff-files" and "git-diff-cache" to do this, because
so far it's a technology demo. And the "git-diff-script" file (and the
git-sh-setup-script in particular) does _not_ accept this "automatically 
figure out where we are" thing, so it's really only the native git diff 
commands that do it.

But if people think it's a good idea, I can pretty trivially convert the 
rest. It's done in a way that makes it very easy to convert programs to 
take advantage of the auto-git-directory-finding thing.

If you use the GIT_DIR environment variable approach, it assumes that all
filenames you give it are absolute and acts the way it always did before.

Comments? Like? Dislike?

		Linus

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ LIB_H=cache.h object.h blob.h tree.h com
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
 	 refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \
-	 sha1_name.o
+	 sha1_name.o setup.o
 
 LIB_H += rev-cache.h
 LIB_OBJS += rev-cache.o
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -140,6 +140,8 @@ extern char *get_graft_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
+extern char **setup_git_directory(char **pathspec);
+
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -179,15 +179,12 @@ int main(int argc, const char **argv)
 	int allow_options = 1;
 	int i;
 
-	read_cache();
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
 		if (!allow_options || *arg != '-') {
-			if (tree_name) {
-				pathspec = argv + i;
+			if (tree_name)
 				break;
-			}
 			tree_name = arg;
 			continue;
 		}
@@ -265,12 +262,16 @@ int main(int argc, const char **argv)
 		usage(diff_cache_usage);
 	}
 
+	pathspec = setup_git_directory(argv + i);
+
 	if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
 		usage(diff_cache_usage);
 
 	if (!tree_name || get_sha1(tree_name, sha1))
 		usage(diff_cache_usage);
 
+	read_cache();
+
 	/* The rest is for paths restriction. */
 	diff_setup(diff_setup_opt);
 
diff --git a/diff-files.c b/diff-files.c
--- a/diff-files.c
+++ b/diff-files.c
@@ -45,8 +45,7 @@ int main(int argc, const char **argv)
 {
 	static const unsigned char null_sha1[20] = { 0, };
 	const char **pathspec;
-	int entries = read_cache();
-	int i;
+	int entries, i;
 
 	while (1 < argc && argv[1][0] == '-') {
 		if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
@@ -95,8 +94,9 @@ int main(int argc, const char **argv)
 		argv++; argc--;
 	}
 
-	/* Do we have a pathspec? */
-	pathspec = (argc > 1) ? argv + 1 : NULL;
+	/* Find the directory, and set up the pathspec */
+	pathspec = setup_git_directory(argv + 1);
+	entries = read_cache();
 
 	if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
 		usage(diff_files_usage);
diff --git a/setup.c b/setup.c
new file mode 100644
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,66 @@
+#include "cache.h"
+
+char **setup_git_directory(char **pathspec)
+{
+	static char *spec[2], **p;
+	static char cwd[PATH_MAX+1];
+	int len, offset;
+
+	/*
+	 * If GIT_DIR is set explicitly, we're not going
+	 * to do any discovery
+	 */
+	if (gitenv(GIT_DIR_ENVIRONMENT))
+		return *pathspec ? pathspec : NULL;
+
+	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+		die("Unable to read current working directory");
+
+	offset = len = strlen(cwd);
+	for (;;) {
+		/*
+		 * We always want to see a .git/HEAD and a .git/refs/
+		 * subdirectory
+		 */
+		if (!access(".git/HEAD", R_OK) && !access(".git/refs/", X_OK)) {
+			/*
+			 * Then we need either a GIT_OBJECT_DIRECTORY define
+			 * or a .git/objects/ directory
+			 */
+			if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
+				break;
+		}
+		chdir("..");
+		do {
+			if (!offset)
+				die("Not a git repository");
+		} while (cwd[--offset] != '/');
+	}
+
+	if (offset == len)
+		return *pathspec ? pathspec : NULL;
+
+	/* Make "offset" point to past the '/', and add a '/' at the end */
+	offset++;
+	cwd[len++] = '/';
+	cwd[len] = 0;
+
+	/* An empty pathspec gets turned into the directory we were in */
+	if (!*pathspec) {
+		spec[0] = cwd + offset;
+		spec[1] = NULL;
+		return spec;
+	}
+
+	/* Otherwise we have to re-write the entries.. */
+	p = pathspec;
+	do {
+		int speclen = strlen(*p);
+		char *n = xmalloc(speclen + len - offset + 1);
+		memcpy(n, cwd + offset, len - offset);
+		memcpy(n + len - offset, *p, speclen+1);
+		*p = n;
+	} while (*++p);
+	return pathspec;
+}
+

^ permalink raw reply	[relevance 15%]

* Re: [RFC PATCH] Add support for figuring out where in the git archive we are
  @ 2005-08-17  1:06 13%       ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-08-17  1:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List



On Tue, 16 Aug 2005, Junio C Hamano wrote:
> 
> The developement history would look nicer if you did the latter,
> but I am easy and can go either way.

Here is.

> > I'd do at least the "git-diff-tree" part and the "./" and "../" handling,
> > and convert at least the "git diff" thing to the new world order and away
> > from git-sh-setup-script?
> 
> Sounds like fun.

Mostly done. It actually works from inside subdirectories, but "." at the
top-level is still not done. Small detail. Will fix later. But it would
help if you would apply this, since I'm going to be off for dinner..

The "../" handling was pretty straightforward.

		Linus

----
Make "git diff" work inside relative subdirectories

We always show the diff as an absolute path, but pathnames to diff are
taken relative to the current working directory (and if no pathnames are
given, the default ends up being all of the current working directory).

Note that "../xyz" also works, so you can do

	cd linux/drivers/char
	git diff ../block

and it will generate a diff of the linux/drivers/block changes.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ LIB_H=cache.h object.h blob.h tree.h com
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
 	 tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
 	 refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \
-	 sha1_name.o
+	 sha1_name.o setup.o
 
 LIB_H += rev-cache.h
 LIB_OBJS += rev-cache.o
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -140,6 +140,9 @@ extern char *get_graft_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
+extern const char **get_pathspec(const char *prefix, char **pathspec);
+extern const char *setup_git_directory(void);
+
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -168,10 +168,11 @@ static const char diff_cache_usage[] =
 "[<common diff options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
 	const char *tree_name = NULL;
 	unsigned char sha1[20];
+	const char *prefix = setup_git_directory();
 	const char **pathspec = NULL;
 	void *tree;
 	unsigned long size;
@@ -179,15 +180,12 @@ int main(int argc, const char **argv)
 	int allow_options = 1;
 	int i;
 
-	read_cache();
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
 		if (!allow_options || *arg != '-') {
-			if (tree_name) {
-				pathspec = argv + i;
+			if (tree_name)
 				break;
-			}
 			tree_name = arg;
 			continue;
 		}
@@ -265,12 +263,16 @@ int main(int argc, const char **argv)
 		usage(diff_cache_usage);
 	}
 
+	pathspec = get_pathspec(prefix, argv + i);
+
 	if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
 		usage(diff_cache_usage);
 
 	if (!tree_name || get_sha1(tree_name, sha1))
 		usage(diff_cache_usage);
 
+	read_cache();
+
 	/* The rest is for paths restriction. */
 	diff_setup(diff_setup_opt);
 
diff --git a/diff-files.c b/diff-files.c
--- a/diff-files.c
+++ b/diff-files.c
@@ -41,12 +41,12 @@ static void show_modified(int oldmode, i
 	diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
 }
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
 	static const unsigned char null_sha1[20] = { 0, };
 	const char **pathspec;
-	int entries = read_cache();
-	int i;
+	const char *prefix = setup_git_directory();
+	int entries, i;
 
 	while (1 < argc && argv[1][0] == '-') {
 		if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
@@ -95,8 +95,9 @@ int main(int argc, const char **argv)
 		argv++; argc--;
 	}
 
-	/* Do we have a pathspec? */
-	pathspec = (argc > 1) ? argv + 1 : NULL;
+	/* Find the directory, and set up the pathspec */
+	pathspec = get_pathspec(prefix, argv + 1);
+	entries = read_cache();
 
 	if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
 		usage(diff_files_usage);
diff --git a/diff-tree.c b/diff-tree.c
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -395,16 +395,25 @@ static int diff_tree_stdin(char *line)
 	return diff_tree_commit(commit, line);
 }
 
+static int count_paths(const char **paths)
+{
+	int i = 0;
+	while (*paths++)
+		i++;
+	return i;
+}
+
 static const char diff_tree_usage[] =
 "git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] "
 "[<common diff options>] <tree-ish> <tree-ish>"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
 	int nr_sha1;
 	char line[1000];
 	unsigned char sha1[2][20];
+	const char *prefix = setup_git_directory();
 
 	nr_sha1 = 0;
 	for (;;) {
@@ -523,11 +532,11 @@ int main(int argc, const char **argv)
 	if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
 		usage(diff_tree_usage);
 
-	if (argc > 0) {
+	paths = get_pathspec(prefix, argv);
+	if (paths) {
 		int i;
 
-		paths = argv;
-		nr_paths = argc;
+		nr_paths = count_paths(paths);
 		pathlens = xmalloc(nr_paths * sizeof(int));
 		for (i=0; i<nr_paths; i++)
 			pathlens[i] = strlen(paths[i]);
diff --git a/git-diff-script b/git-diff-script
--- a/git-diff-script
+++ b/git-diff-script
@@ -1,7 +1,5 @@
 #!/bin/sh
-. git-sh-setup-script || die "Not a git archive"
-
-rev=($(git-rev-parse --revs-only "$@"))
+rev=($(git-rev-parse --revs-only "$@")) || exit
 flags=($(git-rev-parse --no-revs --flags "$@"))
 files=($(git-rev-parse --no-revs --no-flags "$@"))
 case "${#rev[*]}" in
diff --git a/rev-parse.c b/rev-parse.c
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -134,7 +134,8 @@ int main(int argc, char **argv)
 {
 	int i, as_is = 0;
 	unsigned char sha1[20];
-
+	const char *prefix = setup_git_directory();
+	
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
 		char *dotdot;
@@ -189,6 +190,10 @@ int main(int argc, char **argv)
 				for_each_ref(show_reference);
 				continue;
 			}
+			if (!strcmp(arg, "--show-prefix")) {
+				puts(prefix);
+				continue;
+			}
 			show_arg(arg);
 			continue;
 		}
diff --git a/setup.c b/setup.c
new file mode 100644
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,110 @@
+#include "cache.h"
+
+const char **get_pathspec(const char *prefix, char **pathspec)
+{
+	char *entry = *pathspec;
+	char **p;
+	int prefixlen;
+
+	if (!prefix) {
+		char **p;
+		if (!entry)
+			return NULL;
+		p = pathspec;
+		do {
+			if (*entry != '.')
+				continue;
+			/* fixup ? */
+		} while ((entry = *++p) != NULL);
+		return (const char **) pathspec;
+	}
+
+	if (!entry) {
+		static const char *spec[2];
+		spec[0] = prefix;
+		spec[1] = NULL;
+		return spec;
+	}
+
+	/* Otherwise we have to re-write the entries.. */
+	prefixlen = strlen(prefix);
+	p = pathspec;
+	do {
+		int speclen, len = prefixlen;
+		char *n;
+
+		for (;;) {
+			if (!strcmp(entry, ".")) {
+				entry++;
+				break;
+			}
+			if (!strncmp(entry, "./", 2)) {
+				entry += 2;
+				continue;
+			}
+			if (!strncmp(entry, "../", 3)) {
+				do {
+					if (!len)
+						die("'%s' is outside repository", *p);
+					len--;
+				} while (len && prefix[len-1] != '/');
+				entry += 3;
+				continue;
+			}
+			break;
+		}
+		speclen = strlen(entry);
+		n = xmalloc(speclen + len + 1);
+		
+		memcpy(n, prefix, len);
+		memcpy(n + len, entry, speclen+1);
+		*p = n;
+	} while ((entry = *++p) != NULL);
+	return (const char **) pathspec;
+}
+
+const char *setup_git_directory(void)
+{
+	static char cwd[PATH_MAX+1];
+	int len, offset;
+
+	/*
+	 * If GIT_DIR is set explicitly, we're not going
+	 * to do any discovery
+	 */
+	if (gitenv(GIT_DIR_ENVIRONMENT))
+		return NULL;
+
+	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+		die("Unable to read current working directory");
+
+	offset = len = strlen(cwd);
+	for (;;) {
+		/*
+		 * We always want to see a .git/HEAD and a .git/refs/
+		 * subdirectory
+		 */
+		if (!access(".git/HEAD", R_OK) && !access(".git/refs/", X_OK)) {
+			/*
+			 * Then we need either a GIT_OBJECT_DIRECTORY define
+			 * or a .git/objects/ directory
+			 */
+			if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
+				break;
+		}
+		chdir("..");
+		do {
+			if (!offset)
+				die("Not a git repository");
+		} while (cwd[--offset] != '/');
+	}
+
+	if (offset == len)
+		return NULL;
+
+	/* Make "offset" point to past the '/', and add a '/' at the end */
+	offset++;
+	cwd[len++] = '/';
+	cwd[len] = 0;
+	return cwd + offset;
+}

^ permalink raw reply	[relevance 13%]

* [PATCH 1/2] Export relative path handling "prefix_path()" function
@ 2005-08-17 20:31 19% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-08-17 20:31 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


Not all programs necessarily have a pathspec array of pathnames, some of
them (like git-update-cache) want to do things one file at a time.  So
export the single-path interface too.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

 cache.h |    1 +
 setup.c |    2 +-
 2 files changed, 2 insertions(+), 1 deletions(-)

c06157a36e49182c34e1e92aa7b329bde5dca3f9
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -142,6 +142,7 @@ extern char *get_graft_file(void);
 
 extern const char **get_pathspec(const char *prefix, char **pathspec);
 extern const char *setup_git_directory(void);
+extern char *prefix_path(const char *prefix, int len, char *path);
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
diff --git a/setup.c b/setup.c
--- a/setup.c
+++ b/setup.c
@@ -1,6 +1,6 @@
 #include "cache.h"
 
-static char *prefix_path(const char *prefix, int len, char *path)
+char *prefix_path(const char *prefix, int len, char *path)
 {
 	char *orig = path;
 	for (;;) {

^ permalink raw reply	[relevance 19%]

* [PATCH] Spell __attribute__ correctly in cache.h.
@ 2005-08-19  4:10 19% Jason Riedy
  2005-08-19  9:04 19% ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Jason Riedy @ 2005-08-19  4:10 UTC (permalink / raw)
  To: git

Sun's cc doesn't know __attribute__.

Signed-off-by: Jason Riedy <ejr@cs.berkeley.edu>
---

 cache.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

4181b19f615b3d56f9fae5f3accd435480aa7d2f
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -41,7 +41,7 @@
 #endif
 
 #ifndef __attribute__
-#define __attribute(x)
+#define __attribute__(x)
 #endif
 
 /*

^ permalink raw reply	[relevance 19%]

* Re: [PATCH] Spell __attribute__ correctly in cache.h.
  2005-08-19  4:10 19% [PATCH] Spell __attribute__ correctly in cache.h Jason Riedy
@ 2005-08-19  9:04 19% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-19  9:04 UTC (permalink / raw)
  To: Jason Riedy; +Cc: git

Jason Riedy <ejr@cs.berkeley.edu> writes:

> Sun's cc doesn't know __attribute__.

It turns out that your patch breaks GCC build (#ifndef
__attribute__ is true there, and it should be---what it does
cannot be done in preprocessor alone).  I am going to work it
around like this.  Could you try it with Sun cc please?

---
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -38,11 +38,10 @@
 #define NORETURN __attribute__((__noreturn__))
 #else
 #define NORETURN
-#endif
-
 #ifndef __attribute__
 #define __attribute__(x)
 #endif
+#endif
 
 /*
  * Intensive research over the course of many years has shown that

^ permalink raw reply	[relevance 19%]

* [PATCH] Possible cleanups for local-pull.c
@ 2005-09-02 12:17 17% Peter Hagervall
  0 siblings, 0 replies; 200+ results
From: Peter Hagervall @ 2005-09-02 12:17 UTC (permalink / raw)
  To: junkio; +Cc: git

Hi. This patch contains the following possible cleanups:

 * Make some needlessly global functions in local-pull.c static
 * Change 'char *' to 'const char *' where appropriate

Signed-off-by: Peter Hagervall <hager@cs.umu.se>

---

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -327,7 +327,7 @@ extern int get_ack(int fd, unsigned char
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
-extern struct packed_git *parse_pack_index_file(unsigned char *sha1, 
+extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
 						char *idx_path);
 
 extern void prepare_packed_git(void);
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -17,7 +17,7 @@ void prefetch(unsigned char *sha1)
 
 static struct packed_git *packs = NULL;
 
-void setup_index(unsigned char *sha1)
+static void setup_index(unsigned char *sha1)
 {
 	struct packed_git *new_pack;
 	char filename[PATH_MAX];
@@ -30,7 +30,7 @@ void setup_index(unsigned char *sha1)
 	packs = new_pack;
 }
 
-int setup_indices()
+static int setup_indices(void)
 {
 	DIR *dir;
 	struct dirent *de;
@@ -49,7 +49,7 @@ int setup_indices()
 	return 0;
 }
 
-int copy_file(const char *source, const char *dest, const char *hex)
+static int copy_file(const char *source, const char *dest, const char *hex)
 {
 	if (use_link) {
 		if (!link(source, dest)) {
@@ -97,7 +97,7 @@ int copy_file(const char *source, const 
 	return -1;
 }
 
-int fetch_pack(unsigned char *sha1)
+static int fetch_pack(const unsigned char *sha1)
 {
 	struct packed_git *target;
 	char filename[PATH_MAX];
@@ -125,7 +125,7 @@ int fetch_pack(unsigned char *sha1)
 	return 0;
 }
 
-int fetch_file(unsigned char *sha1)
+static int fetch_file(const unsigned char *sha1)
 {
 	static int object_name_start = -1;
 	static char filename[PATH_MAX];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -487,7 +487,7 @@ struct packed_git *parse_pack_index(unsi
 	return parse_pack_index_file(sha1, path);
 }
 
-struct packed_git *parse_pack_index_file(unsigned char *sha1, char *idx_path)
+struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path)
 {
 	struct packed_git *p;
 	nsigned long idx_size;

^ permalink raw reply	[relevance 17%]

* [PATCH 13/22] move purge_cache() to read-cache.c
    2005-09-12 14:55 16% ` [PATCH 01/22] introduce facility to walk through the active cache Chuck Lever
  2005-09-12 14:56 18% ` [PATCH 12/22] simplify write_cache() calling sequence Chuck Lever
@ 2005-09-12 14:56 20% ` Chuck Lever
  2005-09-12 14:56 20% ` [PATCH 14/22] move read_cache_unmerged into read-cache.c Chuck Lever
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:56 UTC (permalink / raw)
  To: git

Functions that manipulate active_cache and active_nr should be in one place.

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 cache.h      |    1 +
 ls-files.c   |   28 +---------------------------
 read-cache.c |   26 ++++++++++++++++++++++++++
 3 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -165,6 +165,7 @@ extern int cache_name_pos(const char *na
 extern int add_cache_entry(struct cache_entry *ce, int option);
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(char *path);
+extern void prune_cache(const char *prefix, int prefix_len);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
 extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
diff --git a/ls-files.c b/ls-files.c
--- a/ls-files.c
+++ b/ls-files.c
@@ -463,32 +463,6 @@ static void show_files(void)
 		walk_cache(show_one_deleted);
 }
 
-/*
- * Prune the index to only contain stuff starting with "prefix"
- */
-static void prune_cache(void)
-{
-	int pos = cache_name_pos(prefix, prefix_len);
-	unsigned int first, last;
-
-	if (pos < 0)
-		pos = -pos-1;
-	active_cache += pos;
-	active_nr -= pos;
-	first = 0;
-	last = active_nr;
-	while (last > first) {
-		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
-		if (!strncmp(ce->name, prefix, prefix_len)) {
-			first = next+1;
-			continue;
-		}
-		last = next;
-	}
-	active_nr = last;
-}
-
 static void verify_pathspec(void)
 {
 	const char **p, *n, *prev;
@@ -643,7 +617,7 @@ int main(int argc, char **argv)
 	if (read_cache() < 0)
 		die("unable to read index file");
 	if (prefix)
-		prune_cache();
+		prune_cache(prefix, prefix_len);
 	show_files();
 	return 0;
 }
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -165,6 +165,32 @@ int remove_file_from_cache(char *path)
 	return 0;
 }
 
+/*
+ * Prune the index to only contain stuff starting with "prefix"
+ */
+void prune_cache(const char *prefix, int prefix_len)
+{
+	int pos = cache_name_pos(prefix, prefix_len);
+	unsigned int first, last;
+
+	if (pos < 0)
+		pos = -pos-1;
+	active_cache += pos;
+	active_nr -= pos;
+	first = 0;
+	last = active_nr;
+	while (last > first) {
+		int next = (last + first) >> 1;
+		struct cache_entry *ce = active_cache[next];
+		if (!strncmp(ce->name, prefix, prefix_len)) {
+			first = next+1;
+			continue;
+		}
+		last = next;
+	}
+	active_nr = last;
+}
+
 int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 {
 	int len = ce_namelen(a);

^ permalink raw reply	[relevance 20%]

* [PATCH 14/22] move read_cache_unmerged into read-cache.c
                     ` (2 preceding siblings ...)
  2005-09-12 14:56 20% ` [PATCH 13/22] move purge_cache() to read-cache.c Chuck Lever
@ 2005-09-12 14:56 20% ` Chuck Lever
  2005-09-12 14:56 19% ` [PATCH 15/22] replace cache_name_pos Chuck Lever
  2005-09-12 14:56 13% ` [PATCH 22/22] teach read-cache.c to use cache_find_name() Chuck Lever
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:56 UTC (permalink / raw)
  To: git

Clean-up: put read_cache_unmerged() right next to read_cache().
read_cache_unmerged() will likely need to be reconstructed if
the active cache data type changes.

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 cache.h      |    1 +
 read-cache.c |   31 +++++++++++++++++++++++++++++++
 read-tree.c  |   28 ----------------------------
 3 files changed, 32 insertions(+), 28 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -157,6 +157,7 @@ extern char *prefix_path(const char *pre
 
 /* Initialize and use the cache information */
 extern int read_cache(void);
+extern int read_cache_unmerged(void);
 extern int write_cache(int newfd);
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -453,6 +453,37 @@ unmap:
 	return error("verify header failed");
 }
 
+static int deleted = 0;
+static struct cache_cursor dst;
+
+static int read_one_unmerged(struct cache_cursor *cc, struct cache_entry *ce)
+{
+	if (ce_stage(ce)) {
+		deleted++;
+		goto out;
+	}
+	if (deleted)
+		set_ce_at_cursor(&dst, ce);
+	next_cc(&dst);
+out:
+	next_cc(cc);
+	return 0;
+}
+
+/*
+ * Read in the cache, then throw away the unmerged entries
+ */
+int read_cache_unmerged(void)
+{
+	if (read_cache() > 0) {
+		init_cc(&dst);
+		walk_cache(read_one_unmerged);
+	}
+
+	active_nr -= deleted;
+	return deleted;
+}
+
 #define WRITE_BUFFER_SIZE 8192
 static unsigned char write_buffer[WRITE_BUFFER_SIZE];
 static unsigned long write_buffer_len;
diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c
@@ -555,34 +555,6 @@ static int oneway_merge(struct cache_ent
 	return merged_entry(a, NULL);
 }
 
-static int deleted = 0;
-static struct cache_cursor dst;
-
-static int read_one_unmerged(struct cache_cursor *cc, struct cache_entry *ce)
-{
-	if (ce_stage(ce)) {
-		deleted++;
-		goto out;
-	}
-	if (deleted)
-		set_ce_at_cursor(&dst, ce);
-	next_cc(&dst);
-out:
-	next_cc(cc);
-	return 0;
-}
-
-static int read_cache_unmerged(void)
-{
-	if (read_cache() > 0) {
-		init_cc(&dst);
-		walk_cache(read_one_unmerged);
-	}
-
-	active_nr -= deleted;
-	return deleted;
-}
-
 static const char read_tree_usage[] = "git-read-tree (<sha> | -m [-u] <sha1> [<sha2> [<sha3>]])";
 
 static struct cache_file cache_file;

^ permalink raw reply	[relevance 20%]

* [PATCH 12/22] simplify write_cache() calling sequence
    2005-09-12 14:55 16% ` [PATCH 01/22] introduce facility to walk through the active cache Chuck Lever
@ 2005-09-12 14:56 18% ` Chuck Lever
  2005-09-12 14:56 20% ` [PATCH 13/22] move purge_cache() to read-cache.c Chuck Lever
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:56 UTC (permalink / raw)
  To: git

Clean-up:  Hide some external references to "active_cache" and "active_nr"
by simplifying the calling sequence of write_cache().

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 apply.c          |    3 +--
 cache.h          |    2 +-
 checkout-index.c |    3 +--
 read-cache.c     |   41 +++++++++++++++++++++++++++--------------
 read-tree.c      |    3 +--
 update-index.c   |    3 +--
 6 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/apply.c b/apply.c
--- a/apply.c
+++ b/apply.c
@@ -1440,8 +1440,7 @@ static int apply_patch(int fd)
 		write_out_results(list, skipped_patch);
 
 	if (write_index) {
-		if (write_cache(newfd, active_cache, active_nr) ||
-		    commit_index_file(&cache_file))
+		if (write_cache(newfd) || commit_index_file(&cache_file))
 			die("Unable to write new cachefile");
 	}
 
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -157,7 +157,7 @@ extern char *prefix_path(const char *pre
 
 /* Initialize and use the cache information */
 extern int read_cache(void);
-extern int write_cache(int newfd, struct cache_entry **cache, int entries);
+extern int write_cache(int newfd);
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
diff --git a/checkout-index.c b/checkout-index.c
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -138,8 +138,7 @@ int main(int argc, char **argv)
 	}
 
 	if (0 <= newfd &&
-	    (write_cache(newfd, active_cache, active_nr) ||
-	     commit_index_file(&cache_file)))
+	    (write_cache(newfd) || commit_index_file(&cache_file)))
 		die("Unable to write new cachefile");
 	return 0;
 }
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -470,30 +470,43 @@ static int ce_flush(SHA_CTX *context, in
 	return 0;
 }
 
-int write_cache(int newfd, struct cache_entry **cache, int entries)
+static int fd, removed = 0;
+static SHA_CTX c;
+
+static int count_removed(struct cache_cursor *cc, struct cache_entry *ce)
+{
+	if (ce->ce_mode == 0)
+		removed++;
+	next_cc(cc);
+	return 0;
+}
+
+static int write_one_cache_entry(struct cache_cursor *cc, struct cache_entry *ce)
+{
+	if (ce->ce_mode != 0)
+		if (ce_write(&c, fd, ce, ce_size(ce)) < 0)
+			return -1;
+	next_cc(cc);
+	return 0;
+}
+
+int write_cache(int newfd)
 {
-	SHA_CTX c;
 	struct cache_header hdr;
-	int i, removed;
 
-	for (i = removed = 0; i < entries; i++)
-		if (!cache[i]->ce_mode)
-			removed++;
+	walk_cache(count_removed);
 
 	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
 	hdr.hdr_version = htonl(2);
-	hdr.hdr_entries = htonl(entries - removed);
+	hdr.hdr_entries = htonl(active_nr - removed);
 
 	SHA1_Init(&c);
 	if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
 		return -1;
 
-	for (i = 0; i < entries; i++) {
-		struct cache_entry *ce = cache[i];
-		if (!ce->ce_mode)
-			continue;
-		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
-			return -1;
-	}
+	fd = newfd;
+	if (walk_cache(write_one_cache_entry))
+		return -1;
+
 	return ce_flush(&c, newfd);
 }
diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c
@@ -670,8 +670,7 @@ int main(int argc, char **argv)
 	}
 
 	unpack_trees(fn);
-	if (write_cache(newfd, active_cache, active_nr) ||
-	    commit_index_file(&cache_file))
+	if (write_cache(newfd) || commit_index_file(&cache_file))
 		die("unable to write new index file");
 	return 0;
 }
diff --git a/update-index.c b/update-index.c
--- a/update-index.c
+++ b/update-index.c
@@ -393,8 +393,7 @@ int main(int argc, char **argv)
 		if (add_file_to_cache(path))
 			die("Unable to add %s to database; maybe you want to use --add option?", path);
 	}
-	if (write_cache(newfd, active_cache, active_nr) ||
-	    commit_index_file(&cache_file))
+	if (write_cache(newfd) || commit_index_file(&cache_file))
 		die("Unable to write new cachefile");
 
 	return has_errors ? 1 : 0;

^ permalink raw reply	[relevance 18%]

* [PATCH 15/22] replace cache_name_pos
                     ` (3 preceding siblings ...)
  2005-09-12 14:56 20% ` [PATCH 14/22] move read_cache_unmerged into read-cache.c Chuck Lever
@ 2005-09-12 14:56 19% ` Chuck Lever
  2005-09-12 14:56 13% ` [PATCH 22/22] teach read-cache.c to use cache_find_name() Chuck Lever
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:56 UTC (permalink / raw)
  To: git

Clean up: Introduce an interface to return a cache_cursor instead of
an integer.  Note we can also eliminate the need to overload the
return value of cache_name_pos to return a negative "pos" value to
signal an insertion point rather than a found entry.

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 cache.h      |   13 +++++++++++++
 read-cache.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -160,6 +160,8 @@ extern int read_cache(void);
 extern int read_cache_unmerged(void);
 extern int write_cache(int newfd);
 extern int cache_name_pos(const char *name, int namelen);
+extern int cache_find_name(const char *name, int namelen, struct cache_cursor *cc);
+
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
 #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
@@ -350,6 +352,17 @@ static inline int walk_cache(cache_itera
 	return 0;
 }
 
+static inline int cache_find_entry(const char *name, int namelen, struct cache_entry **ce)
+{
+	struct cache_cursor cc;
+	int result;
+
+	result = cache_find_name(name, namelen, &cc);
+	if (ce)
+		*ce = active_cache[cc.pos];
+	return result;
+}
+
 struct checkout {
 	const char *base_dir;
 	int base_dir_len;
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -144,6 +144,50 @@ int cache_name_pos(const char *name, int
 	return -first-1;
 }
 
+/*
+ * Given a name, find the first cache entry that matches.  Returning 1
+ * means the cursor points to the cache entry with a matching name.
+ * Returning 0 means the name wasn't found, but the cursor points to an
+ * appropriate insertion point.
+ */
+int cache_find_name(const char *name, int namelen, struct cache_cursor *cc)
+{
+	int first, last;
+
+	/*
+	 * Look for the right name
+	 */
+	cc->pos = first = 0;
+	last = active_nr;
+	while (last > first) {
+		struct cache_entry *ce;
+		int cmp;
+		cc->pos = (last + first) >> 1;
+		ce = active_cache[cc->pos];
+		cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->ce_flags));
+		if (!cmp) {
+			/* found it */
+			return 1;
+		}
+		if (cmp < 0) {
+			/* next: search [first, cc->pos] */
+			last = cc->pos;
+			continue;
+		}
+		/* next: search [cc->pos + 1, last] */
+		first = cc->pos + 1;
+	}
+
+	/*
+	 * Name not found, so return an insertion point.
+	 *
+	 * On return, callers insert *before* the insertion point,
+	 * not after it, to maintain proper list order.
+	 */
+	cc->pos = first;
+	return 0;
+}
+
 /* Remove entry, return true if there are more entries to go.. */
 int remove_cache_entry_at(int pos)
 {

^ permalink raw reply	[relevance 19%]

* [PATCH 01/22] introduce facility to walk through the active cache
  @ 2005-09-12 14:55 16% ` Chuck Lever
  2005-09-12 14:56 18% ` [PATCH 12/22] simplify write_cache() calling sequence Chuck Lever
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:55 UTC (permalink / raw)
  To: git

Introduce a mechanism that allows functions to walk through entries
in the active cache in order and execute an function on each entry.

We also introduce the concept of "cache cursor".  A cursor is simply
a type-independent way of referring to a unique position in the cache.
The cache is strongly ordered, so cursors also provide a type-
independent way of exposing the ordering of the cache positions:
ie next, previous, and eof?

This facility makes no changes to struct cache_entry, which also
happens to be the on-disk format of a cache entry.  By mmapping the
file that contains the cache entries, no data copying is required
to read in the cache.

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 cache.h |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,12 @@ static inline unsigned int create_ce_mod
 extern struct cache_entry **active_cache;
 extern unsigned int active_nr, active_alloc, active_cache_changed;
 
+struct cache_cursor {
+	int pos;
+};
+
+typedef int (*cache_iterator_fn_t) (struct cache_cursor *cc, struct cache_entry *ce);
+
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
@@ -273,6 +279,75 @@ static inline void *xcalloc(size_t nmemb
 	return ret;
 }
 
+static inline void init_cc(struct cache_cursor *cc)
+{
+	cc->pos = 0;
+}
+
+static inline void next_cc(struct cache_cursor *cc)
+{
+	cc->pos++;
+}
+
+static inline void prev_cc(struct cache_cursor *cc)
+{
+	cc->pos--;
+}
+
+static inline struct cache_entry *cc_to_ce(struct cache_cursor *cc)
+{
+	return active_cache[cc->pos];
+}
+
+static inline void set_ce_at_cursor(struct cache_cursor *cc, struct cache_entry *new)
+{
+	active_cache[cc->pos] = new;
+	active_cache_changed = 1;
+}
+
+static inline int cache_empty(void)
+{
+	return active_cache == NULL;
+}
+
+static inline int cache_eof(struct cache_cursor *cc)
+{
+	if (cc->pos < active_nr)
+		return 0;
+	return -1;
+}
+
+static inline int read_cache_needed(void)
+{
+	return cache_empty();
+}
+
+static inline void next_name(struct cache_cursor *cc, struct cache_entry *ce)
+{
+	do {
+		next_cc(cc);
+	} while (!cache_eof(cc) && ce_same_name(ce, cc_to_ce(cc)));
+}
+
+/*
+ * Walk the entire active cache, invoking "func" on each entry
+ *
+ * "func" is responsible for updating the cache_cursor.  To break
+ * out of the loop, "func" can return a negative result.
+ */
+static inline int walk_cache(cache_iterator_fn_t func)
+{
+	struct cache_cursor cc;
+
+	init_cc(&cc);
+	while (!cache_eof(&cc)) {
+		int status = func(&cc, cc_to_ce(&cc));
+		if (status < 0)
+			return status;
+	}
+	return 0;
+}
+
 struct checkout {
 	const char *base_dir;
 	int base_dir_len;

^ permalink raw reply	[relevance 16%]

* [PATCH 22/22] teach read-cache.c to use cache_find_name()
                     ` (4 preceding siblings ...)
  2005-09-12 14:56 19% ` [PATCH 15/22] replace cache_name_pos Chuck Lever
@ 2005-09-12 14:56 13% ` Chuck Lever
  5 siblings, 0 replies; 200+ results
From: Chuck Lever @ 2005-09-12 14:56 UTC (permalink / raw)
  To: git

Fix up the functions in read-cache.c to use cache cursors and
cache_find_name().  As a bonus, cache_name_pos() is no longer
needed.

We've now replaced all logic that depends on a negative result
from cache_name_pos to detect cache insertion points.

Signed-off-by: Chuck Lever <cel@netapp.com>
---

 cache.h      |    3 -
 read-cache.c |  118 ++++++++++++++++++++++++----------------------------------
 read-tree.c  |    2 -
 3 files changed, 51 insertions(+), 72 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -159,14 +159,13 @@ extern char *prefix_path(const char *pre
 extern int read_cache(void);
 extern int read_cache_unmerged(void);
 extern int write_cache(int newfd);
-extern int cache_name_pos(const char *name, int namelen);
 extern int cache_find_name(const char *name, int namelen, struct cache_cursor *cc);
 
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
 #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
 extern int add_cache_entry(struct cache_entry *ce, int option);
-extern int remove_cache_entry_at(int pos);
+extern int remove_cache_entry_at(struct cache_cursor *cc);
 extern int remove_file_from_cache(char *path);
 extern void prune_cache(const char *prefix, int prefix_len);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
diff --git a/read-cache.c b/read-cache.c
--- a/read-cache.c
+++ b/read-cache.c
@@ -123,27 +123,6 @@ int cache_name_compare(const char *name1
 	return 0;
 }
 
-int cache_name_pos(const char *name, int namelen)
-{
-	int first, last;
-
-	first = 0;
-	last = active_nr;
-	while (last > first) {
-		int next = (last + first) >> 1;
-		struct cache_entry *ce = active_cache[next];
-		int cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->ce_flags));
-		if (!cmp)
-			return next;
-		if (cmp < 0) {
-			last = next;
-			continue;
-		}
-		first = next+1;
-	}
-	return -first-1;
-}
-
 /*
  * Given a name, find the first cache entry that matches.  Returning 1
  * means the cursor points to the cache entry with a matching name.
@@ -189,11 +168,13 @@ int cache_find_name(const char *name, in
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-int remove_cache_entry_at(int pos)
+int remove_cache_entry_at(struct cache_cursor *cc)
 {
+	int pos = cc->pos;
+
 	active_cache_changed = 1;
 	active_nr--;
-	if (pos >= active_nr)
+	if (cache_eof(cc))
 		return 0;
 	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
 	return 1;
@@ -201,11 +182,11 @@ int remove_cache_entry_at(int pos)
 
 int remove_file_from_cache(char *path)
 {
-	int pos = cache_name_pos(path, strlen(path));
-	if (pos < 0)
-		pos = -pos-1;
-	while (pos < active_nr && !strcmp(active_cache[pos]->name, path))
-		remove_cache_entry_at(pos);
+	struct cache_cursor cc;
+
+	cache_find_name(path, strlen(path), &cc);
+	while (!cache_eof(&cc) && !strcmp(cc_to_ce(&cc)->name, path))
+		remove_cache_entry_at(&cc);
 	return 0;
 }
 
@@ -214,13 +195,12 @@ int remove_file_from_cache(char *path)
  */
 void prune_cache(const char *prefix, int prefix_len)
 {
-	int pos = cache_name_pos(prefix, prefix_len);
+	struct cache_cursor cc;
 	unsigned int first, last;
 
-	if (pos < 0)
-		pos = -pos-1;
-	active_cache += pos;
-	active_nr -= pos;
+	cache_find_name(prefix, prefix_len, &cc);
+	active_cache += cc.pos;
+	active_nr -= cc.pos;
 	first = 0;
 	last = active_nr;
 	while (last > first) {
@@ -237,7 +217,8 @@ void prune_cache(const char *prefix, int
 
 int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 {
-	int len = ce_namelen(a);
+	int len;
+	len = ce_namelen(a);
 	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
@@ -271,28 +252,30 @@ int ce_path_match(const struct cache_ent
  * Do we have another file that has the beginning components being a
  * proper superset of the name we're trying to add?
  */
-static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replace)
+static int has_file_name(const struct cache_entry *ce, struct cache_cursor *cc, int ok_to_replace)
 {
 	int retval = 0;
 	int len = ce_namelen(ce);
 	int stage = ce_stage(ce);
 	const char *name = ce->name;
 
-	while (pos < active_nr) {
-		struct cache_entry *p = active_cache[pos++];
+	while (!cache_eof(cc)) {
+		struct cache_entry *p = cc_to_ce(cc);
 
 		if (len >= ce_namelen(p))
 			break;
 		if (memcmp(name, p->name, len))
 			break;
 		if (ce_stage(p) != stage)
-			continue;
+			goto next;
 		if (p->name[len] != '/')
-			continue;
+			goto next;
 		retval = -1;
 		if (!ok_to_replace)
 			break;
-		remove_cache_entry_at(--pos);
+		remove_cache_entry_at(cc);
+next:
+		next_cc(cc);
 	}
 	return retval;
 }
@@ -301,8 +284,9 @@ static int has_file_name(const struct ca
  * Do we have another file with a pathname that is a proper
  * subset of the name we're trying to add?
  */
-static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
+static int has_dir_name(const struct cache_entry *ce, int ok_to_replace)
 {
+	struct cache_cursor cc;
 	int retval = 0;
 	int stage = ce_stage(ce);
 	const char *name = ce->name;
@@ -319,12 +303,11 @@ static int has_dir_name(const struct cac
 		}
 		len = slash - name;
 
-		pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
-		if (pos >= 0) {
+		if (cache_find_name(name, ntohs(create_ce_flags(len, stage)), &cc)) {
 			retval = -1;
 			if (ok_to_replace)
 				break;
-			remove_cache_entry_at(pos);
+			remove_cache_entry_at(&cc);
 			continue;
 		}
 
@@ -333,9 +316,8 @@ static int has_dir_name(const struct cac
 		 * already matches the sub-directory, then we know
 		 * we're ok, and we can exit.
 		 */
-		pos = -pos-1;
-		while (pos < active_nr) {
-			struct cache_entry *p = active_cache[pos];
+		while (!cache_eof(&cc)) {
+			struct cache_entry *p = cc_to_ce(&cc);
 			if ((ce_namelen(p) <= len) ||
 			    (p->name[len] != '/') ||
 			    memcmp(p->name, name, len))
@@ -347,7 +329,7 @@ static int has_dir_name(const struct cac
 				 * level or anything shorter.
 				 */
 				return retval;
-			pos++;
+			next_cc(&cc);
 		}
 	}
 	return retval;
@@ -362,45 +344,41 @@ static int has_dir_name(const struct cac
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
  */
-static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
+static int check_file_directory_conflict(const struct cache_entry *ce, struct cache_cursor *cc, int ok_to_replace)
 {
+	struct cache_cursor cd = *cc;
 	/*
 	 * We check if the path is a sub-path of a subsequent pathname
 	 * first, since removing those will not change the position
 	 * in the array
 	 */
-	int retval = has_file_name(ce, pos, ok_to_replace);
+	int retval = has_file_name(ce, &cd, ok_to_replace);
 	/*
 	 * Then check if the path might have a clashing sub-directory
 	 * before it.
 	 */
-	return retval + has_dir_name(ce, pos, ok_to_replace);
+	return retval + has_dir_name(ce, ok_to_replace);
 }
 
 int add_cache_entry(struct cache_entry *ce, int option)
 {
-	int pos;
+	struct cache_cursor cc;
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
 	int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
-	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it */
-	if (pos >= 0) {
-		active_cache_changed = 1;
-		active_cache[pos] = ce;
-		return 0;
-	}
-	pos = -pos-1;
+	if (cache_find_name(ce->name, ntohs(ce->ce_flags), &cc))
+		goto out;
 
 	/*
 	 * Inserting a merged entry ("stage 0") into the index
 	 * will always replace all non-merged entries..
 	 */
-	if (pos < active_nr && ce_stage(ce) == 0) {
-		while (ce_same_name(active_cache[pos], ce)) {
+	if (!cache_eof(&cc) && ce_stage(ce) == 0) {
+		while (ce_same_name(cc_to_ce(&cc), ce)) {
 			ok_to_add = 1;
-			if (!remove_cache_entry_at(pos))
+			if (!remove_cache_entry_at(&cc))
 				break;
 		}
 	}
@@ -408,11 +386,10 @@ int add_cache_entry(struct cache_entry *
 	if (!ok_to_add)
 		return -1;
 
-	if (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) {
+	if (!skip_df_check && check_file_directory_conflict(ce, &cc, ok_to_replace)) {
 		if (!ok_to_replace)
 			return -1;
-		pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
-		pos = -pos-1;
+		cache_find_name(ce->name, ntohs(ce->ce_flags), &cc);
 	}
 
 	/* Make sure the array is big enough .. */
@@ -423,10 +400,13 @@ int add_cache_entry(struct cache_entry *
 
 	/* Add it in.. */
 	active_nr++;
-	if (active_nr > pos)
+	if (!cache_eof(&cc)) {
+		int pos = cc.pos;
 		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
-	active_cache[pos] = ce;
-	active_cache_changed = 1;
+	}
+
+out:
+	set_ce_at_cursor(&cc, ce);
 	return 0;
 }
 
@@ -456,7 +436,7 @@ int read_cache(void)
 	struct cache_header *hdr;
 
 	errno = EBUSY;
-	if (active_cache)
+	if (!read_cache_needed())
 		return error("more than one cachefile");
 	errno = ENOENT;
 	fd = open(get_index_file(), O_RDONLY);
diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c
@@ -135,7 +135,7 @@ static int unpack_trees_rec(struct tree_
 		if (cache_name && !strcmp(cache_name, first)) {
 			any_files = 1;
 			src[0] = cc_to_ce(cc);
-			remove_cache_entry_at(cc->pos);
+			remove_cache_entry_at(cc);
 		}
 
 		for (i = 0; i < len; i++) {

^ permalink raw reply	[relevance 13%]

* Add note about IANA confirmation
@ 2005-09-12 18:23 18% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-09-12 18:23 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano


The git port (9418) is officially listed by IANA now.

So document it.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Btw, another thing happened yesterday too: I'm now officially using a
packed archive for my core kernel stuff. The format hasn't changed in
I-don't-know-how-long, and I can't recall any pack-specific bug either
(apart from the obvious lack of support by some of the client-side stuff).

Goodie. Me happy.

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -50,6 +50,17 @@
  *	Your search - "port 9418" - did not match any documents.
  *
  * as www.google.com puts it.
+ *
+ * This port has been properly assigned for git use by IANA:
+ * git (Assigned-9418) [I06-050728-0001].
+ *
+ *	git  9418/tcp   git pack transfer service
+ *	git  9418/udp   git pack transfer service
+ *
+ * with Linus Torvalds <torvalds@osdl.org> as the point of
+ * contact. September 2005.
+ *
+ * See http://www.iana.org/assignments/port-numbers
  */
 #define DEFAULT_GIT_PORT 9418
 

^ permalink raw reply	[relevance 18%]

* Re: dumb transports not being welcomed..
  @ 2005-09-14 10:45 19%       ` Sven Verdoolaege
  0 siblings, 0 replies; 200+ results
From: Sven Verdoolaege @ 2005-09-14 10:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sam Ravnborg, git

On Tue, Sep 13, 2005 at 03:11:42PM -0700, Junio C Hamano wrote:
> The file $GIT_DIR/info/refs was introduced to solve this by
> listing the available refs for discovery, and hooks/post-update,
> when enabled, runs update-server-info to update the file (among
> other things) whenever you push into the repository.  

It doesn't help that update-server-info crashes if you run
it for the first time on an old repo.
Maybe it should create the appropriate directory structure on the fly,
but the patch below at least checks whether new rev-cache could
be created.

skimo
--

write_rev_cache: check whether new cache could be created.

---
commit d30b87459c690ff68e65dfe8ecdc585dab64323a
tree 51127c1af00f8fd63e7b996384e86d7d31ad5562
parent 2ba6c47be1762726ad0c1d5779064c489150d789
author Sven Verdoolaege <skimo@liacs.nl> Wed, 14 Sep 2005 12:40:28 +0200
committer Sven Verdoolaege <skimo@liacs.nl> Wed, 14 Sep 2005 12:40:28 +0200

 rev-cache.c   |    8 +++++++-
 rev-cache.h   |    2 +-
 server-info.c |    7 ++++---
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/rev-cache.c b/rev-cache.c
--- a/rev-cache.c
+++ b/rev-cache.c
@@ -103,7 +103,7 @@ static void write_one_rev_cache(FILE *re
 		write_one_rev_cache(rev_cache_file, rle->ri);
 }
 
-void write_rev_cache(const char *newpath, const char *oldpath)
+int write_rev_cache(const char *newpath, const char *oldpath)
 {
 	/* write the following commit ancestry information in
 	 * $GIT_DIR/info/rev-cache.
@@ -131,6 +131,11 @@ void write_rev_cache(const char *newpath
 		size_t sz;
 		FILE *oldfp = fopen(oldpath, "r");
 		rev_cache_file = fopen(newpath, "w");
+		if (!rev_cache_file) {
+			if (oldfp)
+				fclose(oldfp);
+			return error("cannot open %s", newpath);
+		}
 		if (oldfp) {
 			while (1) {
 				sz = fread(buf, 1, sizeof(buf), oldfp);
@@ -161,6 +166,7 @@ void write_rev_cache(const char *newpath
 		write_one_rev_cache(rev_cache_file, ri);
 	}
 	fclose(rev_cache_file);
+	return 0;
 }
 
 static void add_parent(struct rev_cache *child,
diff --git a/rev-cache.h b/rev-cache.h
--- a/rev-cache.h
+++ b/rev-cache.h
@@ -24,6 +24,6 @@ struct rev_list_elem {
 extern int find_rev_cache(const unsigned char *);
 extern int read_rev_cache(const char *, FILE *, int);
 extern int record_rev_cache(const unsigned char *, FILE *);
-extern void write_rev_cache(const char *new, const char *old);
+extern int write_rev_cache(const char *new, const char *old);
 
 #endif
diff --git a/server-info.c b/server-info.c
--- a/server-info.c
+++ b/server-info.c
@@ -536,6 +536,7 @@ static int update_info_revs(int force)
 	char *path0 = strdup(git_path("info/rev-cache"));
 	int len = strlen(path0);
 	char *path1 = xmalloc(len + 2);
+	int errs = 0;
 
 	strcpy(path1, path0);
 	strcpy(path1 + len, "+");
@@ -548,11 +549,11 @@ static int update_info_revs(int force)
 	for_each_ref(record_rev_cache_ref);
 
 	/* update the rev-cache database */
-	write_rev_cache(path1, force ? "/dev/null" : path0);
-	rename(path1, path0);
+	errs = errs || write_rev_cache(path1, force ? "/dev/null" : path0);
+	errs = errs || rename(path1, path0);
 	free(path1);
 	free(path0);
-	return 0;
+	return errs;
 }
 
 /* public */

^ permalink raw reply	[relevance 19%]

* [PATCH/RFC] Build a shared / renamed / "stable" version of the library?
@ 2005-09-16 12:37  9% Matthias Urlichs
  0 siblings, 0 replies; 200+ results
From: Matthias Urlichs @ 2005-09-16 12:37 UTC (permalink / raw)
  To: git

Build (and use) libgit.so instead of libgit.a.

--- 

I have written this nice Python extension that gives me fast access to
git objects. Python extensions are built as shared libraries. Linking
shared and non-shared objects into one library results in a couple of
linker warnings on i386; other architectures are far less forgiving.

So the best choice I seem to have is to build a shared libgit.so.

Unfortunately, libgit doesn't have nice symbol names. I dunno how you
all would feel about a big patch which renames absoutely every foo()
function in libgit to be git_foo() instead (or one that #ifdef's them)...
so I'm taking the easy way out, and use versioned symbols. That should
prevent symbol name conflicts with other libraries.

I've had to redefine usage(), error() and die() to git_*(), because
they're just too conflict-ish. "error" is even a weak symbol in libc. :-/

To summarize, the choices seem to be:
- don't do anything => no script language extensions, need to fork off
  a git program for absolutely everything. Bah.
- build libgit.a with -fpic'd objects => doesn't work on all
  architectures.
- build libgit.shared.a and use that for building script language
  extensions => works now, but may cause name conflicts down the road.
- build a "normal" libgit.so => ditto on the name conflicts.
- build a libgit.so with symbol versions => no name conflicts expected,
  but works only with the GNU linker.
- rename all library functions and globals => quite a bit of work,
  and more typing down the road.
- add "#define foo git_foo" to all library functions => ugly.

Opinions?

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,8 @@ ALL_CFLAGS = $(CFLAGS) $(PLATFORM_DEFINE
 
 prefix = $(HOME)
 bindir = $(prefix)/bin
+libdir = $(prefix)/lib
+incdir = $(prefix)/include
 template_dir = $(prefix)/share/git-core/templates/
 GIT_PYTHON_DIR = $(prefix)/share/git-core/python
 # DESTDIR=
@@ -142,7 +144,18 @@ LIB_OBJS = \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o $(DIFF_OBJS)
 
-LIBS = $(LIB_FILE)
+ifdef SHARED_LIBOBJ
+
+LIB_FILE=libgit.so
+GITLIB = -L. -lgit
+
+else
+
+LIB_FILE=libgit.a
+GITLIB = $(LIB_FILE)
+
+endif
+
 LIBS += -lz
 
 ifeq ($(shell uname -s),Darwin)
@@ -167,6 +180,7 @@ endif
 ifndef NO_OPENSSL
 	LIB_OBJS += epoch.o
 	OPENSSL_LIBSSL = -lssl
+	LIBS += -lssl
 else
 	DEFINES += '-DNO_OPENSSL'
 	MOZILLA_SHA1 = 1
@@ -242,7 +256,7 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % 
 	$(CC) -o $*.o -c $(ALL_CFLAGS) $<
 
 git-%: %.o $(LIB_FILE)
-	$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
+	$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(GITLIB) $(LIBS)
 
 git-mailinfo : SIMPLE_LIB += $(LIB_4_ICONV)
 $(SIMPLE_PROGRAMS) : $(LIB_FILE)
@@ -267,9 +281,33 @@ $(LIB_OBJS): $(LIB_H)
 $(patsubst git-%,%.o,$(PROGRAMS)): $(LIB_H)
 $(DIFF_OBJS): diffcore.h
 
+# Use -fPIC for the library files so they may be linked into a shared
+# library if necessary
+#
+ifdef SHARED_LIBOBJ
+
+PIC=-fpic
+
+$(LIB_FILE): $(LIB_OBJS) libgit.vers
+	$(CC) -shared -Wl,-soname,$(SHARED_LIBOBJ) -Wl,--version-script=libgit.vers -o $@ $(LIB_OBJS) $(LIBS)
+	rm -f $(SHARED_LIBOBJ) && ln -s $(LIB_FILE) $(SHARED_LIBOBJ)
+
+else # "normal" library
+
+PIC=
+
 $(LIB_FILE): $(LIB_OBJS)
 	$(AR) rcs $@ $(LIB_OBJS)
 
+endif
+
+# Declare rules for building library files.
+define lib_rule
+$1.o: $1.c
+	$(CC) $(ALL_CFLAGS) $(PIC) -c -o $1.o $1.c
+endef
+$(foreach obj,$(basename $(LIB_OBJS)),$(eval $(call lib_rule, $(obj))))
+
 doc:
 	$(MAKE) -C Documentation all
 
@@ -300,6 +338,14 @@ install: $(PROGRAMS) $(SCRIPTS)
 	$(MAKE) -C templates install
 	$(INSTALL) -d -m755 $(DESTDIR)$(GIT_PYTHON_DIR)
 	$(INSTALL) $(PYMODULES) $(DESTDIR)$(GIT_PYTHON_DIR)
+ifdef SHARED_LIBOBJ
+	$(INSTALL) -m755 -d $(DESTDIR)$(libdir)
+	$(INSTALL) -m755 $(LIB_FILE) $(DESTDIR)$(libdir)/$(SHARED_LIBOBJ)
+	cd $(DESTDIR)$(libdir) && ln -sf $(SHARED_LIBOBJ) $(LIB_FILE)
+	$(INSTALL) -m755 -d $(DESTDIR)$(incdir)
+	$(INSTALL) -m755 -d $(DESTDIR)$(incdir)/git
+	$(INSTALL) -m644 $(LIB_H) $(DESTDIR)$(incdir)/git
+endif
 
 install-doc:
 	$(MAKE) -C Documentation install
@@ -333,7 +379,7 @@ deb: dist
 ### Cleaning rules
 
 clean:
-	rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROGRAMS) $(LIB_FILE)
+	rm -f *.o mozilla-sha1/*.o ppc/*.o $(PROGRAMS) *.a *.so *.so.*
 	rm -f $(filter-out gitk,$(SCRIPTS))
 	rm -f git-core.spec
 	rm -rf $(GIT_TARNAME)
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -228,6 +228,9 @@ extern int get_sha1_hex(const char *hex,
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 
 /* General helper functions */
+#define usage git_usage
+#define error git_error
+#define die git_die
 extern void usage(const char *err) NORETURN;
 extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
 extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+git-core (0.99.6-2) unstable; urgency=low
+
+  * Install a shared libgit.so
+  * Install development files (git-dev package)
+
+ -- Matthias Urlichs <smurf@debian.org>  Wed, 14 Sep 2005 09:04:57 +0200
+
 git-core (0.99.6-0) unstable; urgency=low
 
   * GIT 0.99.6
diff --git a/debian/control b/debian/control
--- a/debian/control
+++ b/debian/control
@@ -18,9 +18,22 @@ Description: The git content addressable
  enables human beings to work with the database in a manner to a degree
  similar to other SCM tools.
 
+Package: libgit1
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: The git content addressable filesystem, shared library
+ This package contains the shared library for git.
+
 Package: git-tk
 Architecture: all
 Depends: ${shlibs:Depends}, ${misc:Depends}, git-core, tk8.4
 Description: The git content addressable filesystem, GUI add-on
  This package contains 'gitk', the git revision tree visualizer.
 
+Package: git-dev
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, git-core, tk8.4
+Description: The git content addressable filesystem, development files
+ This package contains the files needed to build programs which access
+ the git library.
+
diff --git a/debian/git-core.files b/debian/git-core.files
--- a/debian/git-core.files
+++ b/debian/git-core.files
@@ -1 +1,3 @@
-/usr
+/usr/bin
+/usr/share
+/usr/lib/*.so.*
diff --git a/debian/git-dev.files b/debian/git-dev.files
new file mode 100644
--- /dev/null
+++ b/debian/git-dev.files
@@ -0,0 +1,2 @@
+/usr/include/git
+/usr/lib/*.so
diff --git a/debian/libgit1.files b/debian/libgit1.files
new file mode 100644
--- /dev/null
+++ b/debian/libgit1.files
@@ -0,0 +1 @@
+/usr/lib/libgit.so.1
diff --git a/debian/rules b/debian/rules
--- a/debian/rules
+++ b/debian/rules
@@ -25,6 +25,9 @@ else
 	export MOZILLA_SHA1=YesPlease
 endif
 
+# build libgit.a with shared objects
+export SHARED_LIBOBJ=libgit.so.1
+
 # We do have the requisite perl modules in the mainline, and
 # have no reason to shy away from this script.
 export WITH_SEND_EMAIL=YesPlease
@@ -60,11 +63,13 @@ install: build
 	dh_installdirs 
 
 	make DESTDIR=$(DESTDIR) prefix=$(PREFIX) mandir=$(MANDIR) \
-		install install-doc
+		install # install-doc
 
 	mkdir -p $(DOC_DESTDIR)
 	find $(DOC) '(' -name '*.txt' -o -name '*.html' ')' -exec install {} $(DOC_DESTDIR) ';'
 
+	dh_movefiles -p libgit1
+	dh_movefiles -p git-dev
 	dh_movefiles -p git-tk
 	dh_movefiles -p git-core
 	find debian/tmp -type d -o -print | sed -e 's/^/? /'
diff --git a/libgit.vers b/libgit.vers
new file mode 100644
--- /dev/null
+++ b/libgit.vers
@@ -0,0 +1,195 @@
+GIT_1 {
+	global:
+		add_cache_entry ;
+		add_packed_git ;
+		add_ref ;
+		alloc_filespec ;
+		base_name_compare ;
+		blob_type ;
+		cache_name_compare ;
+		cache_name_pos ;
+		ce_match_stat ;
+		ce_path_match ;
+		ce_same_name ;
+		checkout_entry ;
+		check_ref_format ;
+		check_sha1_signature ;
+		commit_index_file ;
+		commit_list_insert ;
+		commit_type ;
+		count_delta ;
+		count_parents ;
+		created_object ;
+		deref_tag ;
+		diff_addremove ;
+		diff_change ;
+		diffcore_break ;
+		diffcore_merge_broken ;
+		diffcore_order ;
+		diffcore_pathspec ;
+		diffcore_pickaxe ;
+		diffcore_rename ;
+		diffcore_std ;
+		diffcore_std_no_resolve ;
+		diff_delta ;
+		diff_flush ;
+		diff_free_filepair ;
+		diff_free_filespec ;
+		diff_helper_input ;
+		diff_populate_filespec ;
+		diff_q ;
+		diff_queue ;
+		diff_queue_is_empty ;
+		diff_scoreopt_parse ;
+		diff_setup ;
+		diff_unmerge ;
+		diff_unmodified_pair ;
+		fill_filespec ;
+		fill_stat_cache_info ;
+		find_pack_entry_one ;
+		find_rev_cache ;
+		find_sha1_pack ;
+		finish_connect ;
+		for_each_ref ;
+		free_commit_list ;
+		get_ack ;
+		get_commit_format ;
+		get_graft_file ;
+		get_ident ;
+		get_index_file ;
+		get_object_directory ;
+		get_pathspec ;
+		get_refs_directory ;
+		get_ref_sha1 ;
+		get_remote_heads ;
+		get_sha1 ;
+		get_sha1_hex ;
+		git_author_info ;
+		git_committer_info ;
+		git_connect ;
+		git_mkstemp ;
+		git_path ;
+		has_pack_file ;
+		has_pack_index ;
+		has_sha1_file ;
+		has_sha1_pack ;
+		head_ref ;
+		hold_index_file_for_update ;
+		index_fd ;
+		insert_by_date ;
+		install_packed_git ;
+		lock_ref_sha1 ;
+		lookup_blob ;
+		lookup_commit ;
+		lookup_commit_reference ;
+		lookup_commit_reference_gently ;
+		lookup_object ;
+		lookup_object_type ;
+		lookup_tag ;
+		lookup_tree ;
+		lookup_unknown_object ;
+		mark_reachable ;
+		match_refs ;
+		mkpath ;
+		nth_packed_object_sha1 ;
+		num_packed_objects ;
+		object_list_append ;
+		object_list_contains ;
+		object_list_insert ;
+		object_list_length ;
+		packed_object_info_detail ;
+		packet_flush ;
+		packet_read_line ;
+		packet_write ;
+		parse_blob ;
+		parse_blob_buffer ;
+		parse_commit ;
+		parse_commit_buffer ;
+		parse_date ;
+		parse_object ;
+		parse_pack_index ;
+		parse_pack_index_file ;
+		parse_sha1_header ;
+		parse_tag ;
+		parse_tag_buffer ;
+		parse_tree ;
+		parse_tree_buffer ;
+		parse_tree_indirect ;
+		patch_delta ;
+		path_match ;
+		pop_commit ;
+		pop_most_recent_commit ;
+		prefix_path ;
+		prepare_alt_odb ;
+		prepare_packed_git ;
+		pretty_print_commit ;
+		read_cache ;
+		read_line ;
+		read_object_with_reference ;
+		read_rev_cache ;
+		read_sha1_file ;
+		read_tree ;
+		record_rev_cache ;
+		remove_cache_entry_at ;
+		remove_file_from_cache ;
+		rollback_index_file ;
+		run_command ;
+		run_command_v ;
+		safe_create_leading_directories ;
+		safe_strncpy ;
+		setup_git_directory ;
+		setup_ident ;
+		sha1close ;
+		sha1create ;
+		sha1fd ;
+		sha1_file_name ;
+		SHA1_Final ;
+		SHA1_Init ;
+		sha1_object_info ;
+		sha1_pack_index_name ;
+		sha1_pack_name ;
+		sha1_to_hex ;
+		SHA1_Update ;
+		sha1write ;
+		sha1write_compressed ;
+		show_date ;
+		sort_by_date ;
+		sort_in_topological_order ;
+		sort_list_in_merge_order ;
+		sq_quote ;
+		strbuf_init ;
+		tag_type ;
+		tree_type ;
+		unpack_entry_gently ;
+		unpack_sha1_file ;
+		unpack_sha1_header ;
+		unuse_packed_git ;
+		update_server_info ;
+		use_packed_git ;
+		verify_pack ;
+		write_cache ;
+		write_ref_sha1 ;
+		write_ref_sha1_unlocked ;
+		write_rev_cache ;
+		write_sha1_file ;
+		write_sha1_file_prepare ;
+		write_sha1_from_fd ;
+		write_sha1_to_fd ;
+		active_alloc ;
+		active_cache ;
+		active_cache_changed ;
+		active_nr ;
+		nr_objs ;
+		objs ;
+		alloc_revs ;
+		nr_revs ;
+		rev_cache ;
+		alt_odb_list ;
+		packed_git ;
+		diff_queued_diff ;
+		git_die ;
+		git_usage ;
+		git_error ;
+	local:
+		*;
+};
diff --git a/t/Makefile b/t/Makefile
--- a/t/Makefile
+++ b/t/Makefile
@@ -8,7 +8,9 @@
 T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
 
 all:
-	@$(foreach t,$T,echo "*** $t ***"; sh $t $(GIT_TEST_OPTS) || exit; )
+	@$(foreach t,$T,echo "*** $t ***"; \
+	env LD_LIBRARY_PATH=$$(pwd)/..:$$LD_LIBRARY_PATH \
+	sh $t $(GIT_TEST_OPTS) || exit; )
 	@rm -fr trash
 
 clean:
-- 
Matthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
 - -
Don't send my boy to Harvard, the dying mother said. Don't send my boy to
Harvard, I'd rather see him dead.

^ permalink raw reply	[relevance 9%]

* Return proper error valud from "parse_date()"
@ 2005-09-19 22:53 16% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-09-19 22:53 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


Right now we don't return any error value at all from parse_date(), and if 
we can't parse it, we just silently leave the result buffer unchanged. 

That's fine for the current user, which will always default to the current 
date, but it's a crappy interface, and we might well be better off with an 
error message rather than just the default date.

So let's change the thing to return a negative value if an error occurs, 
and the length of the result otherwise (snprintf behaviour: if the buffer 
is too small, it returns how big it _would_ have been).

[ I started looking at this in case we could support date-based revision 
  names. Looks ugly. Would have to parse relative dates.. ]

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -241,7 +241,7 @@ extern void *read_object_with_reference(
 					unsigned char *sha1_ret);
 
 const char *show_date(unsigned long time, int timezone);
-void parse_date(const char *date, char *buf, int bufsize);
+int parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
 
 extern int setup_ident(void);
diff --git a/date.c b/date.c
--- a/date.c
+++ b/date.c
@@ -388,7 +388,7 @@ static int match_tz(const char *date, in
 
 /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
    (i.e. English) day/month names, and it doesn't work correctly with %z. */
-void parse_date(const char *date, char *result, int maxlen)
+int parse_date(const char *date, char *result, int maxlen)
 {
 	struct tm tm;
 	int offset, sign, tm_gmt;
@@ -431,7 +431,7 @@ void parse_date(const char *date, char *
 		offset = (then - mktime(&tm)) / 60;
 
 	if (then == -1)
-		return;
+		return -1;
 
 	if (!tm_gmt)
 		then -= offset * 60;
@@ -442,7 +442,7 @@ void parse_date(const char *date, char *
 		sign = '-';
 	}
 
-	snprintf(result, maxlen, "%lu %c%02d%02d", then, sign, offset/60, offset % 60);
+	return snprintf(result, maxlen, "%lu %c%02d%02d", then, sign, offset/60, offset % 60);
 }
 
 void datestamp(char *buf, int bufsize)

^ permalink raw reply	[relevance 16%]

* Re: git 0.99.7b doesn't build on Cygwin
  @ 2005-09-25 16:59 11%                       ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-09-25 16:59 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List; +Cc: Davide Libenzi



On Sat, 24 Sep 2005, Linus Torvalds wrote:
>
> Anyway, regardless, we could certainly make HEAD be a regular file 
> containing the name of the head instead.
> 
> It probably wouldn't even require a whole lot of changes. HEAD already 
> ends up getting some special attention, since most of the things that look 
> for refs only look inside the .git/refs directory.

This patch does some of it. I decided not to special-case HEAD, but to 
just improve "read_ref()" a bit.

Changing "read_ref()" was the trivial part - the bigger part that we had 
three different implementations of it, and this patch is thus bigger just 
because it collapses them all into "read_ref()" and makes the calling 
conventions acceptable to all.

NOTE! This makes "symbolic refs" usable in general, ie you can do

	echo "ref: refs/tags/v0.99.7" > .git/refs/tags/LATEST

and that essentially makes "LATEST" a symbolic ref that points to the 
v0.99.7 tag without using a filesystem symlink. But it does NOT mean that 
you can replace the HEAD symlink with a file containing "refs/tags/master" 
yet: there are _other_ parts of git that depend on it being a symlink. 

(For the most core example, the "write new head" logic depends on just
writing to HEAD, and that symlink will automatically change that write to 
the thing the HEAD _points_ to. That's the biggest one).

I'll change those too to accept a regular file, if people agree this is 
worthwhile. In theory there are even UNIXes out there that don't support 
symlinks, so maybe it's worth it. But maybe people dislike this.

In the meantime, you can test this out with

	echo "ref: HEAD" > .git/TEST_HEAD
	git-rev-parse HEAD TEST_HEAD master

which - if your HEAD points to master - should print out the same SHA1
three times ;)

		Linus

---
Subject: Allow reading "symbolic refs" that point to other refs

This extends the ref reading to understand a "symbolic ref": a ref file 
that starts with "ref: " and points to another ref file, and thus 
introduces the notion of ref aliases.

This is in preparation of allowing HEAD to eventually not be a symlink, 
but one of these symbolic refs instead.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -227,6 +227,7 @@ extern int has_pack_index(const unsigned
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
+extern int read_ref(const char *filename, unsigned char *sha1);
 
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
diff --git a/refs.c b/refs.c
--- a/refs.c
+++ b/refs.c
@@ -2,17 +2,38 @@
 #include "cache.h"
 
 #include <errno.h>
+#include <ctype.h>
 
-static int read_ref(const char *refname, unsigned char *sha1)
+/* We allow "recursive" symbolic refs. Only within reason, though */
+#define MAXDEPTH 5
+
+int read_ref(const char *filename, unsigned char *sha1)
 {
-	int ret = -1;
-	int fd = open(git_path("%s", refname), O_RDONLY);
+	int depth = 0;
+	int ret = -1, fd;
+
+	while ((fd = open(filename, O_RDONLY)) >= 0) {
+		char buffer[256];
+		int len = read(fd, buffer, sizeof(buffer)-1);
 
-	if (fd >= 0) {
-		char buffer[60];
-		if (read(fd, buffer, sizeof(buffer)) >= 40)
-			ret = get_sha1_hex(buffer, sha1);
 		close(fd);
+		if (len < 0)
+			break;
+
+		buffer[len] = 0;
+		while (len && isspace(buffer[len-1]))
+			buffer[--len] = 0;
+
+		if (!strncmp(buffer, "ref: ", 5)) {
+			if (depth > MAXDEPTH)
+				break;
+			depth++;
+			filename = git_path("%s", buffer+5);
+			continue;
+		}
+		if (len >= 40)
+			ret = get_sha1_hex(buffer, sha1);
+		break;
 	}
 	return ret;
 }
@@ -54,7 +75,7 @@ static int do_for_each_ref(const char *b
 					break;
 				continue;
 			}
-			if (read_ref(path, sha1) < 0)
+			if (read_ref(git_path("%s", path), sha1) < 0)
 				continue;
 			if (!has_sha1_file(sha1))
 				continue;
@@ -71,7 +92,7 @@ static int do_for_each_ref(const char *b
 int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
 {
 	unsigned char sha1[20];
-	if (!read_ref("HEAD", sha1))
+	if (!read_ref(git_path("HEAD"), sha1))
 		return fn("HEAD", sha1);
 	return 0;
 }
@@ -101,33 +122,14 @@ static char *ref_lock_file_name(const ch
 	return ret;
 }
 
-static int read_ref_file(const 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_ref_sha1(const char *ref, unsigned char *sha1)
 {
-	char *filename;
-	int retval;
+	const char *filename;
+
 	if (check_ref_format(ref))
 		return -1;
-	filename = ref_file_name(ref);
-	retval = read_ref_file(filename, sha1);
-	free(filename);
-	return retval;
+	filename = git_path("refs/%s", ref);
+	return read_ref(filename, sha1);
 }
 
 static int lock_ref_file(const char *filename, const char *lock_filename,
@@ -140,7 +142,7 @@ static int lock_ref_file(const char *fil
 		return error("Couldn't open lock file for %s: %s",
 			     filename, strerror(errno));
 	}
-	retval = read_ref_file(filename, current_sha1);
+	retval = read_ref(filename, current_sha1);
 	if (old_sha1) {
 		if (retval) {
 			close(fd);
diff --git a/sha1_name.c b/sha1_name.c
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -119,21 +119,6 @@ static int get_short_sha1(const char *na
 	return -1;
 }
 
-static int get_sha1_file(const char *path, unsigned char *result)
-{
-	char buffer[60];
-	int fd = open(path, O_RDONLY);
-	int len;
-
-	if (fd < 0)
-		return -1;
-	len = read(fd, buffer, sizeof(buffer));
-	close(fd);
-	if (len < 40)
-		return -1;
-	return get_sha1_hex(buffer, result);
-}
-
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 {
 	static const char *prefix[] = {
@@ -150,7 +135,7 @@ static int get_sha1_basic(const char *st
 
 	for (p = prefix; *p; p++) {
 		char *pathname = git_path("%s/%.*s", *p, len, str);
-		if (!get_sha1_file(pathname, sha1))
+		if (!read_ref(pathname, sha1))
 			return 0;
 	}
 

^ permalink raw reply	[relevance 11%]

* [PATCH] Add git-symbolic-ref
@ 2005-09-29  4:24  7% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-09-29  4:24 UTC (permalink / raw)
  To: git

This adds the counterpart of git-update-ref that lets you read
and create "symbolic refs".  By default it uses a symbolic link
to represent ".git/HEAD -> refs/heads/master", but it can be
compiled to use the textfile symbolic ref.  In that case, the
.git/HEAD file would typically read "ref: refs/heads/master".

The places that did 'readlink .git/HEAD' and 'ln -s
refs/heads/blah .git/HEAD' have been converted to use new
git-symbolic-ref command, so that they can deal with either
implementation.

I suspect that I ended up wasting my git day of this week
working on this, given that Cygwin seems to be capable of
emulating symlinks using .lnk files.  On the other hand, even
Linux folks may be on vfat or similar fs that does not have
symlinks so who knows.  On yet another hand, a project can have
symlinks stored in the repository, and in order to check things
out the filesystem needs to have symlinks anyway, so maybe this
is a big wasted effort.  Mumble mumble mumble...

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Makefile             |    2 +-
 cache.h              |    1 +
 fsck-objects.c       |   28 ++++++++++------------------
 git-bisect.sh        |    7 ++++---
 git-branch.sh        |    6 ++++--
 git-checkout.sh      |    3 ++-
 git-commit.sh        |   17 ++++++++---------
 git-sh-setup.sh      |    4 ++--
 git-status.sh        |    4 ++--
 init-db.c            |   10 +++++-----
 refs.c               |   46 ++++++++++++++++++++++++++++++++++++++++++++--
 setup.c              |   16 ++++++++++------
 show-branch.c        |   13 +++++++++----
 symbolic-ref.c       |   34 ++++++++++++++++++++++++++++++++++
 t/t5400-send-pack.sh |    6 +++---
 15 files changed, 139 insertions(+), 58 deletions(-)
 create mode 100644 symbolic-ref.c

15de68abcb00ede12ac4b67c3f0ecac7cfffd0b4
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,7 @@ PROGRAMS = \
 	git-ssh-upload git-tar-tree git-unpack-file \
 	git-unpack-objects git-update-index git-update-server-info \
 	git-upload-pack git-verify-pack git-write-tree \
-	git-update-ref \
+	git-update-ref git-symbolic-ref \
 	$(SIMPLE_PROGRAMS)
 
 # Backward compatibility -- to be removed in 0.99.8
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -231,6 +231,7 @@ extern int get_sha1_hex(const char *hex,
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
 extern const char *resolve_ref(const char *path, unsigned char *sha1);
+extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
 
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
diff --git a/fsck-objects.c b/fsck-objects.c
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -402,25 +402,17 @@ static void fsck_object_dir(const char *
 
 static int fsck_head_link(void)
 {
-	int fd, count;
-	char hex[40];
 	unsigned char sha1[20];
-	static char path[PATH_MAX], link[PATH_MAX];
-	const char *git_dir = get_git_dir();
-
-	snprintf(path, sizeof(path), "%s/HEAD", git_dir);
-	if (readlink(path, link, sizeof(link)) < 0)
-		return error("HEAD is not a symlink");
-	if (strncmp("refs/heads/", link, 11))
-		return error("HEAD points to something strange (%s)", link);
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return error("HEAD: %s", strerror(errno));
-	count = read(fd, hex, sizeof(hex));
-	close(fd);
-	if (count < 0)
-		return error("HEAD: %s", strerror(errno));
-	if (count < 40 || get_sha1_hex(hex, sha1))
+	const char *git_HEAD = strdup(git_path("HEAD"));
+	const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1);
+	int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
+
+	if (!git_refs_heads_master)
+		return error("HEAD is not a symbolic ref");
+	if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
+		return error("HEAD points to something strange (%s)",
+			     git_refs_heads_master + pfxlen);
+	if (!memcmp(null_sha1, sha1, 20))
 		return error("HEAD: not a valid git pointer");
 	return 0;
 }
diff --git a/git-bisect.sh b/git-bisect.sh
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -38,7 +38,8 @@ bisect_start() {
 	# Verify HEAD. If we were bisecting before this, reset to the
 	# top-of-line master first!
 	#
-	head=$(readlink $GIT_DIR/HEAD) || die "Bad HEAD - I need a symlink"
+	head=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) ||
+	die "Bad HEAD - I need a symbolic ref"
 	case "$head" in
 	refs/heads/bisect*)
 		git checkout master || exit
@@ -46,7 +47,7 @@ bisect_start() {
 	refs/heads/*)
 		;;
 	*)
-		die "Bad HEAD - strange symlink"
+		die "Bad HEAD - strange symbolic ref"
 		;;
 	esac
 
@@ -135,7 +136,7 @@ bisect_next() {
 	echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
 	git checkout new-bisect || exit
 	mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
-	ln -sf refs/heads/bisect "$GIT_DIR/HEAD"
+	GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
 	git-show-branch "$rev"
 }
 
diff --git a/git-branch.sh b/git-branch.sh
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -14,7 +14,8 @@ If two arguments, create a new branch <b
 
 delete_branch () {
     option="$1" branch_name="$2"
-    headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
+    headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
+    	       sed -e 's|^refs/heads/||')
     case ",$headref," in
     ",$branch_name,")
 	die "Cannot delete the branch you are on." ;;
@@ -67,7 +68,8 @@ done
 
 case "$#" in
 0)
-	headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
+	headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
+		  sed -e 's|^refs/heads/||')
 	git-rev-parse --symbolic --all |
 	sed -ne 's|^refs/heads/||p' |
 	sort |
diff --git a/git-checkout.sh b/git-checkout.sh
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -71,7 +71,8 @@ if [ "$?" -eq 0 ]; then
 		echo $new > "$GIT_DIR/refs/heads/$newbranch"
 		branch="$newbranch"
 	fi
-	[ "$branch" ] && ln -sf "refs/heads/$branch" "$GIT_DIR/HEAD"
+	[ "$branch" ] &&
+	GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
 	rm -f "$GIT_DIR/MERGE_HEAD"
 else
 	exit 1
diff --git a/git-commit.sh b/git-commit.sh
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -153,15 +153,8 @@ if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 fi >>.editmsg
 
 PARENTS="-p HEAD"
-if [ ! -r "$GIT_DIR/HEAD" ]; then
-	if [ -z "$(git-ls-files)" ]; then
-		echo Nothing to commit 1>&2
-		exit 1
-	fi
-	PARENTS=""
-	current=
-else
-	current=$(git-rev-parse --verify HEAD)
+if GIT_DIR="$GIT_DIR" git-rev-parse --verify HEAD >/dev/null 2>&1
+then
 	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
 	fi
@@ -194,6 +187,12 @@ else
 		export GIT_AUTHOR_EMAIL
 		export GIT_AUTHOR_DATE
 	fi
+else
+	if [ -z "$(git-ls-files)" ]; then
+		echo Nothing to commit 1>&2
+		exit 1
+	fi
+	PARENTS=""
 fi
 git-status >>.editmsg
 if [ "$?" != "0" -a ! -f $GIT_DIR/MERGE_HEAD ]
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -13,10 +13,10 @@
 unset CDPATH
 
 die() {
-	echo "$@" >&2
+	echo >&2 "$@"
 	exit 1
 }
 
-[ -h "$GIT_DIR/HEAD" ] &&
+GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD >/dev/null 2>&1 &&
 [ -d "$GIT_DIR/refs" ] &&
 [ -d "$GIT_OBJECT_DIRECTORY/00" ]
diff --git a/git-status.sh b/git-status.sh
--- a/git-status.sh
+++ b/git-status.sh
@@ -31,7 +31,7 @@ report () {
   [ "$header" ]
 }
 
-branch=`readlink "$GIT_DIR/HEAD"`
+branch=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD)
 case "$branch" in
 refs/heads/master) ;;
 *)	echo "# On branch $branch" ;;
@@ -39,7 +39,7 @@ esac
 
 git-update-index --refresh >/dev/null 2>&1
 
-if test -f "$GIT_DIR/HEAD"
+if GIT_DIR="$GIT_DIR" git-rev-parse --verify HEAD >/dev/null 2>&1
 then
 	git-diff-index -M --cached HEAD |
 	sed 's/^://' |
diff --git a/init-db.c b/init-db.c
--- a/init-db.c
+++ b/init-db.c
@@ -166,6 +166,7 @@ static void create_default_files(const c
 {
 	unsigned len = strlen(git_dir);
 	static char path[PATH_MAX];
+	unsigned char sha1[20];
 
 	if (len > sizeof(path)-50)
 		die("insane git directory %s", git_dir);
@@ -186,15 +187,14 @@ static void create_default_files(const c
 
 	/*
 	 * Create the default symlink from ".git/HEAD" to the "master"
-	 * branch
+	 * branch, if it does not exist yet.
 	 */
 	strcpy(path + len, "HEAD");
-	if (symlink("refs/heads/master", path) < 0) {
-		if (errno != EEXIST) {
-			perror(path);
+	if (read_ref(path, sha1) < 0) {
+		if (create_symref(path, "refs/heads/master") < 0)
 			exit(1);
-		}
 	}
+	path[len] = 0;
 	copy_templates(path, len, template_path);
 }
 
diff --git a/refs.c b/refs.c
--- a/refs.c
+++ b/refs.c
@@ -9,6 +9,10 @@ const unsigned char null_sha1[20] = { 0,
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
 
+#ifndef USE_SYMLINK_HEAD
+#define USE_SYMLINK_HEAD 1
+#endif
+
 const char *resolve_ref(const char *path, unsigned char *sha1)
 {
 	int depth = MAXDEPTH, len;
@@ -22,9 +26,14 @@ const char *resolve_ref(const char *path
 		if (--depth < 0)
 			return NULL;
 
-		/* Special case: non-existing file */
+		/* Special case: non-existing file.
+		 * But if this is the first round, i.e. the user
+		 * gave us ".git/NO_SUCH_SYMLINK" which does not even
+		 * exist, we should barf.  ".git/HEAD" symlink which
+		 * points at "refs/heads/master" not yet born is OK.
+		 */
 		if (lstat(path, &st) < 0) {
-			if (errno != ENOENT)
+			if (errno != ENOENT || depth == MAXDEPTH - 1)
 				return NULL;
 			memset(sha1, 0, 20);
 			return path;
@@ -67,6 +76,39 @@ const char *resolve_ref(const char *path
 	return path;
 }
 
+int create_symref(const char *git_HEAD, const char *refs_heads_master)
+{
+#if USE_SYMLINK_HEAD
+	unlink(git_HEAD);
+	return symlink(refs_heads_master, git_HEAD);
+#else
+	const char *lockpath;
+	char ref[1000];
+	int fd, len, written;
+
+	len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
+	if (sizeof(ref) <= len) {
+		error("refname too long: %s", refs_heads_master);
+		return -1;
+	}
+	lockpath = mkpath("%s.lock", git_HEAD);
+	fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);	
+	written = write(fd, ref, len);
+	close(fd);
+	if (written != len) {
+		unlink(lockpath);
+		error("Unable to write to %s", lockpath);
+		return -2;
+	}
+	if (rename(lockpath, git_HEAD) < 0) {
+		unlink(lockpath);
+		error("Unable to create %s", git_HEAD);
+		return -3;
+	}
+	return 0;
+#endif
+}
+
 int read_ref(const char *filename, unsigned char *sha1)
 {
 	if (resolve_ref(filename, sha1) && memcmp(sha1, null_sha1, 20))
diff --git a/setup.c b/setup.c
--- a/setup.c
+++ b/setup.c
@@ -76,18 +76,22 @@ const char **get_pathspec(const char *pr
  * Test it it looks like we're at the top
  * level git directory. We want to see a
  *
- *  - a HEAD symlink and a refs/ directory under ".git"
  *  - either a .git/objects/ directory _or_ the proper
  *    GIT_OBJECT_DIRECTORY environment variable
+ *  - a refs/ directory under ".git"
+ *  - either a HEAD symlink or a HEAD file that is formatted as
+ *    a proper "ref:".
  */
 static int is_toplevel_directory(void)
 {
-	struct stat st;
+	unsigned char sha1[20];
 
-	return	!lstat(".git/HEAD", &st) &&
-		S_ISLNK(st.st_mode) &&
-		!access(".git/refs/", X_OK) &&
-		(getenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK));
+	if (access(".git/refs/", X_OK) ||
+	    access(getenv(DB_ENVIRONMENT) ?
+		   getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
+	    (resolve_ref(".git/HEAD", sha1) == NULL))
+		return 0;
+	return 1;
 }
 
 const char *setup_git_directory(void)
diff --git a/show-branch.c b/show-branch.c
--- a/show-branch.c
+++ b/show-branch.c
@@ -349,6 +349,7 @@ int main(int ac, char **av)
 	int all_heads = 0, all_tags = 0;
 	int all_mask, all_revs, shown_merge_point;
 	char head_path[128];
+	const char *head_path_p;
 	int head_path_len;
 	unsigned char head_sha1[20];
 	int merge_base = 0;
@@ -430,11 +431,15 @@ int main(int ac, char **av)
 	if (0 <= extra)
 		join_revs(&list, &seen, num_rev, extra);
 
-	head_path_len = readlink(".git/HEAD", head_path, sizeof(head_path)-1);
-	if ((head_path_len < 0) || get_sha1("HEAD", head_sha1))
+	head_path_p = resolve_ref(git_path("HEAD"), head_sha1);
+	if (head_path_p) {
+		head_path_len = strlen(head_path_p);
+		memcpy(head_path, head_path_p, head_path_len + 1);
+	}
+	else {
+		head_path_len = 0;
 		head_path[0] = 0;
-	else
-		head_path[head_path_len] = 0;
+	}
 
 	if (merge_base)
 		return show_merge_base(seen, num_rev);
diff --git a/symbolic-ref.c b/symbolic-ref.c
new file mode 100644
--- /dev/null
+++ b/symbolic-ref.c
@@ -0,0 +1,34 @@
+#include "cache.h"
+
+static const char git_symbolic_ref_usage[] =
+"git-symbolic-ref name [ref]";
+
+static void check_symref(const char *HEAD)
+{
+	unsigned char sha1[20];
+	const char *git_HEAD = strdup(git_path("%s", HEAD));
+	const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1);
+	if (git_refs_heads_master) {
+		/* we want to strip the .git/ part */
+		int pfxlen = strlen(git_HEAD) - strlen(HEAD);
+		puts(git_refs_heads_master + pfxlen);
+	}
+	else
+		die("No such ref: %s", HEAD);
+}
+
+int main(int argc, const char **argv)
+{
+	setup_git_directory();
+	switch (argc) {
+	case 2:
+		check_symref(argv[1]);
+		break;
+	case 3:
+		create_symref(strdup(git_path("%s", argv[1])), argv[2]);
+		break;
+	default:
+		usage(git_symbolic_ref_usage);
+	}
+	return 0;
+}
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -20,12 +20,12 @@ test_expect_success setup '
 	    commit=$(echo "Commit #$i" | git-commit-tree $tree -p $parent) &&
 	    parent=$commit || return 1
 	done &&
-	echo "$commit" >.git/HEAD &&
+	git-update-ref HEAD "$commit" &&
 	git-clone -l ./. victim &&
 	cd victim &&
 	git-log &&
 	cd .. &&
-	echo $zero >.git/HEAD &&
+	git-update-ref HEAD "$zero" &&
 	parent=$zero &&
 	for i in $cnt
 	do
@@ -33,7 +33,7 @@ test_expect_success setup '
 	    commit=$(echo "Rebase #$i" | git-commit-tree $tree -p $parent) &&
 	    parent=$commit || return 1
 	done &&
-	echo "$commit" >.git/HEAD &&
+	git-update-ref HEAD "$commit" &&
 	echo Rebase &&
 	git-log'
 

^ permalink raw reply	[relevance 7%]

* [PATCH] Fix git+ssh's indefinite halts during long fetches
@ 2005-10-01 18:39 11% Dan Aloni
  0 siblings, 0 replies; 200+ results
From: Dan Aloni @ 2005-10-01 18:39 UTC (permalink / raw)
  To: git, Junio C Hamano

The problem with the old implementation is that the socket input buffers
get full and then both ends halt waiting for each other. This take cares
of it, by buffering at the fetching side while still trying to send. It's
quite hackish but does the work (I managed to locally fetch the kernel with
its ~85000 objects that sum up to 250MB).

Signed-off-by: Dan Aloni <da-x@monatomic.org>

---
commit 958b0c00525fb63276430783dccb18316cec73c9
tree 4003cf1069e9ac4bbb8aade512047dd41a466ae2
parent 60fb5b2c4d9e26204f480f8a18ae1ff0051a6440
author Dan Aloni <da-x@monatomic.org> Sat, 01 Oct 2005 21:38:25 +0300
committer Dan Aloni <da-x@monatomic.org> Sat, 01 Oct 2005 21:38:25 +0300

 cache.h     |   18 +++++++-
 sha1_file.c |  129 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 ssh-fetch.c |   76 ++++++++++++++++++++++++-----------
 3 files changed, 174 insertions(+), 49 deletions(-)

diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -214,8 +214,22 @@ extern int check_sha1_signature(const un
 /* Read a tree into the cache */
 extern int read_tree(void *buffer, unsigned long size, int stage, const char **paths);
 
-extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
-			      size_t bufsize, size_t *bufposn);
+struct input_segment {
+	unsigned char *buffer;
+	size_t size;
+
+	struct input_segment *next;
+	struct input_segment *prev;
+};
+
+struct input_buffer {
+	struct input_segment *first;
+	struct input_segment *last;
+};
+
+extern int read_input_buffers(int block, int fd_in, struct input_buffer *inputbuffer);
+extern int write_sha1_from_fd(const unsigned char *sha1, int fd, struct input_buffer *inputbuffer);
+
 extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
 
 extern int has_sha1_pack(const unsigned char *sha1);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1413,11 +1413,88 @@ int write_sha1_to_fd(int fd, const unsig
 	return 0;
 }
 
-int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
-		       size_t bufsize, size_t *bufposn)
+int cut_last_input_segment(struct input_buffer *inputbuffer, struct input_segment *segment, size_t size_left)
 {
-	char *filename = sha1_file_name(sha1);
+	if (size_left) {
+		memmove(segment->buffer, segment->buffer + segment->size - size_left, size_left);
+		segment->size = size_left;
+		return 1;
+	}
+	
+	if (segment == inputbuffer->first) 
+		inputbuffer->first = NULL;
+
+	free(segment->buffer);
+	segment = segment->prev;
+	free(inputbuffer->last);
+	inputbuffer->last = segment;
+	return 0;
+}
+
+int read_input_buffers(int block, int fd_in, struct input_buffer *inputbuffer)
+{
+	unsigned long old_flags = 0;
+	size_t bufsize;
+	int readsize;
+	struct input_segment *segment;
+	int ret = 0;
+	unsigned char *buf;
+
+	if (!block) {
+		old_flags = fcntl(fd_in, F_GETFL);
+		fcntl(fd_in, F_SETFL, old_flags | O_NONBLOCK);
+	}
+
+	do {
+		bufsize = 0x10000;
+		buf = malloc(bufsize);
+		if (!buf) {
+			ret = -1;
+			break;
+		}
+		
+		readsize = read(fd_in, buf, bufsize);
+		if (readsize <= 0) {
+			free(buf);
+			if (readsize == 0) {
+				ret = -1;
+			}
+			break;
+		}
+			
+		buf = realloc(buf, readsize);
+		segment = (typeof(segment))(malloc(sizeof(*segment)));
+		if (!segment) {
+			free(buf);
+			ret = -1;
+			break;
+		}
+
+		segment->size = readsize;
+		segment->buffer = buf;
+		segment->next = inputbuffer->first;
+		segment->prev = NULL;
+
+		if (inputbuffer->first == NULL) {
+			inputbuffer->last = segment;
+		} else {
+			inputbuffer->first->prev = segment;
+		}
+		inputbuffer->first = segment;
+	} while (!block);
+
+	if (!block) {
+		fcntl(fd_in, F_SETFL, old_flags);
+	}
+
+	return ret;
+}
 
+extern int write_sha1_from_fd(const unsigned char *sha1, int fd, struct input_buffer *inputbuffer)
+{
+	char *filename = sha1_file_name(sha1);
+	int read_result_byte = 0;
+	signed char result_byte;
 	int local;
 	z_stream stream;
 	unsigned char real_sha1[20];
@@ -1437,10 +1514,20 @@ int write_sha1_from_fd(const unsigned ch
 	SHA1_Init(&c);
 
 	do {
-		ssize_t size;
-		if (*bufposn) {
-			stream.avail_in = *bufposn;
-			stream.next_in = (unsigned char *) buffer;
+		struct input_segment *segment = inputbuffer->last;
+		if (segment) {
+			if (!read_result_byte) {
+				int more_to_read;
+				result_byte = segment->buffer[0];
+				read_result_byte = 1;
+
+				more_to_read = cut_last_input_segment(inputbuffer, segment, segment->size - 1);
+				if (!more_to_read)
+					continue;
+			}
+
+			stream.avail_in = segment->size;
+			stream.next_in = segment->buffer;
 			do {
 				stream.next_out = discard;
 				stream.avail_out = sizeof(discard);
@@ -1448,23 +1535,19 @@ int write_sha1_from_fd(const unsigned ch
 				SHA1_Update(&c, discard, sizeof(discard) -
 					    stream.avail_out);
 			} while (stream.avail_in && ret == Z_OK);
-			write(local, buffer, *bufposn - stream.avail_in);
-			memmove(buffer, buffer + *bufposn - stream.avail_in,
-				stream.avail_in);
-			*bufposn = stream.avail_in;
-			if (ret != Z_OK)
-				break;
-		}
-		size = read(fd, buffer + *bufposn, bufsize - *bufposn);
-		if (size <= 0) {
-			close(local);
-			unlink(filename);
-			if (!size)
+
+			write(local, segment->buffer, segment->size - stream.avail_in);
+			cut_last_input_segment(inputbuffer, segment, stream.avail_in);
+ 			if (ret != Z_OK)
+ 				break;
+		} else {
+			ret = read_input_buffers(1, fd, inputbuffer);
+			if (ret) {
+				close(local);
+				unlink(filename);
 				return error("Connection closed?");
-			perror("Reading from connection");
-			return -1;
-		}
-		*bufposn += size;
+			}
+ 		}
 	} while (1);
 	inflateEnd(&stream);
 
diff --git a/ssh-fetch.c b/ssh-fetch.c
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -14,57 +14,85 @@
 #include "fetch.h"
 #include "refs.h"
 
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 static int fd_in;
 static int fd_out;
 
 static unsigned char remote_version = 0;
 static unsigned char local_version = 1;
+static struct input_buffer inputbuffer = {NULL, };
 
-static ssize_t force_write(int fd, void *buffer, size_t length)
+static ssize_t force_write(void *buffer, size_t length)
 {
+	fd_set rfds, wfds;
 	ssize_t ret = 0;
+	int retval;
+	struct timeval tv;
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&wfds);
+	FD_SET(fd_in, &rfds);
+	FD_SET(fd_out, &wfds);
+
 	while (ret < length) {
-		ssize_t size = write(fd, buffer + ret, length - ret);
-		if (size < 0) {
-			return size;
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+		
+		retval = select(FD_SETSIZE, &rfds, &wfds, NULL, &tv);
+		if (!retval)
+			continue;
+
+		if (FD_ISSET(fd_in, &rfds)) {
+			read_input_buffers(0, fd_in, &inputbuffer);
+			continue;
 		}
-		if (size == 0) {
-			return ret;
+
+		if (FD_ISSET(fd_out, &wfds)) {
+			ssize_t size;
+			unsigned long old_flags = 0;
+
+			old_flags = fcntl(fd_out, F_GETFL);
+			fcntl(fd_out, F_SETFL, old_flags | O_NONBLOCK);
+			size = write(fd_out, buffer + ret, length - ret);
+			fcntl(fd_out, F_SETFL, old_flags);
+			
+			if (size < 0) {
+				return size;
+			}
+			if (size == 0) {
+				return ret;
+			}		
+	
+			ret += size;
 		}
-		ret += size;
 	}
+
 	return ret;
 }
 
 void prefetch(unsigned char *sha1)
 {
 	char type = 'o';
-	force_write(fd_out, &type, 1);
-	force_write(fd_out, sha1, 20);
+	read_input_buffers(0, fd_in, &inputbuffer);
+	force_write(&type, 1);
+	force_write(sha1, 20);
 	//memcpy(requested + 20 * prefetches++, sha1, 20);
 }
 
-static char conn_buf[4096];
-static size_t conn_buf_posn = 0;
-
 int fetch(unsigned char *sha1)
 {
 	int ret;
-	signed char remote;
 
-	if (conn_buf_posn) {
-		remote = conn_buf[0];
-		memmove(conn_buf, conn_buf + 1, --conn_buf_posn);
-	} else {
-		if (read(fd_in, &remote, 1) < 1)
-			return -1;
-	}
-	//fprintf(stderr, "Got %d\n", remote);
-	if (remote < 0)
-		return remote;
-	ret = write_sha1_from_fd(sha1, fd_in, conn_buf, 4096, &conn_buf_posn);
+	read_input_buffers(0, fd_in, &inputbuffer);
+	ret = write_sha1_from_fd(sha1, fd_in, &inputbuffer);
 	if (!ret)
 		pull_say("got %s\n", sha1_to_hex(sha1));
+
 	return ret;
 }
 

-- 
Dan Aloni
da-x@monatomic.org, da-x@colinux.org, da-x@gmx.net

^ permalink raw reply	[relevance 11%]

* [PATCH] Show original and resulting blob object info in diff output.
  @ 2005-10-07  2:33  7%                     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-07  2:33 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Eric W. Biederman, git

This adds more cruft to diff --git header to record the blob SHA1 and
the mode the patch/diff is intended to be applied against, to help the
receiving end fall back on a three-way merge.  The new header looks
like this:

    diff --git a/apply.c b/apply.c
    old index 7be50413538868412a87c847f8fa184cadd0fa2a 100644
    new index 83660822fcbb9edac523634999e30d65c2790cae 100644
    --- a/apply.c
    +++ b/apply.c
    @@ -14,6 +14,7 @@
     //    files that are being modified, but doesn't apply the patch
     //  --stat does just a diffstat, and doesn't actually apply
    +//  --show-index-info shows the old and new index info for...
    ...

There is a counterpart option --show-index-info to git-apply command
to summarize this:

    - 7be5041... 100644	apply.c
    + 8366082... 100644	apply.c
    - ec2a161... 100644	cache.h
    + 514adb8... 100644	cache.h
    - ...

Upon receiving such a patch, if the patch did not apply cleanly to the
target tree, the recipient can try to find the matching old objects in
her object database and create a temporary tree, apply the patch to
that temporary tree, and attempt a 3-way merge between the patched
temporary tree and the target tree using the original temporary tree
as the common ancestor.

The patch lifts the code to compute the hash for an on-filesystem
object from update-index.c and makes it available to the diff output
routine.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

    Linus Torvalds <torvalds@osdl.org> writes:

    > On Thu, 6 Oct 2005, Eric W. Biederman wrote:
    >> 
    >> After thinking about it I don't think you need to look through the
    >> history to use it for a merge3 operation.   As I recall merge3 only
    >> looks at the base and the two derived versions of the file.  If we
    >> have the sha1 of the original in the git repository I think all we
    >> need to compute is the diff between that sha1 the current version
    >> file.  And then apply the merge3 algorithm to combine the two sets of
    >> changes.
    >
    > Ahh, that I can definitely agree with. In fact, it makes perfect sense.

    And this is a sample implementation to do so.  Will not
    graduate "pu" until the receiving end gets ready and unless
    people agree that the additional cruft is not too
    distracting.

 apply.c                        |   64 +++++++++++++++++++++++++++++++++-
 cache.h                        |    1 +
 diff.c                         |   76 +++++++++++++++++++++++++++++-----------
 sha1_file.c                    |   39 +++++++++++++++++++++
 t/diff-lib.sh                  |   10 ++++-
 t/t4000-diff-format.sh         |    6 +++
 t/t4001-diff-rename.sh         |    3 +-
 t/t4004-diff-rename-symlink.sh |    3 +-
 update-index.c                 |   33 ++---------------
 9 files changed, 179 insertions(+), 56 deletions(-)

applies-to: 8cf0bb652ffde36e57bca5d6f33287305a61bb74
2c48a811a36ee6e12aeb044b3d1ff459b8d958c2
diff --git a/apply.c b/apply.c
old index 7be50413538868412a87c847f8fa184cadd0fa2a 100644
new index ed2eac2c67dd003c8a0eaa7325e1543d1472777d 100644
--- a/apply.c
+++ b/apply.c
@@ -14,6 +14,7 @@
 //    files that are being modified, but doesn't apply the patch
 //  --stat does just a diffstat, and doesn't actually apply
 //  --show-files shows the directory changes
+//  --show-index-info shows the old and new index info for paths if available.
 //
 static int check_index = 0;
 static int write_index = 0;
@@ -22,8 +23,9 @@ static int summary = 0;
 static int check = 0;
 static int apply = 1;
 static int show_files = 0;
+static int show_index_info = 0;
 static const char apply_usage[] =
-"git-apply [--stat] [--summary] [--check] [--index] [--apply] [--show-files] <patch>...";
+"git-apply [--stat] [--summary] [--check] [--index] [--apply] [--show-files] [--show-index-info] <patch>...";
 
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
@@ -56,6 +58,8 @@ struct patch {
 	struct fragment *fragments;
 	char *result;
 	unsigned long resultsize;
+	unsigned char old_sha1[20];
+	unsigned char new_sha1[20];
 	struct patch *next;
 };
 
@@ -334,6 +338,24 @@ static int gitdiff_dissimilarity(const c
 	return 0;
 }
 
+static int gitdiff_old_index(const char *line, struct patch *patch)
+{
+	if (get_sha1_hex(line, patch->old_sha1))
+		memcpy(patch->old_sha1, null_sha1, 20);
+	else
+		gitdiff_oldmode(line + 41, patch);
+	return 0;
+}
+
+static int gitdiff_new_index(const char *line, struct patch *patch)
+{
+	if (get_sha1_hex(line, patch->new_sha1))
+		memcpy(patch->new_sha1, null_sha1, 20);
+	else
+		gitdiff_newmode(line + 41, patch);
+	return 0;
+}
+
 /*
  * This is normal for a diff that doesn't change anything: we'll fall through
  * into the next diff. Tell the parser to break out.
@@ -438,6 +460,8 @@ static int parse_git_header(char *line, 
 			{ "rename to ", gitdiff_renamedst },
 			{ "similarity index ", gitdiff_similarity },
 			{ "dissimilarity index ", gitdiff_dissimilarity },
+			{ "old index ", gitdiff_old_index },
+			{ "new index ", gitdiff_new_index },
 			{ "", gitdiff_unrecognized },
 		};
 		int i;
@@ -1136,6 +1160,36 @@ static void show_file_list(struct patch 
 	}
 }
 
+static inline int is_null_sha1(const unsigned char *sha1)
+{
+	return !memcmp(sha1, null_sha1, 20);
+}
+
+static void show_index_list(struct patch *list)
+{
+	struct patch *patch;
+
+	for (patch = list; patch; patch = patch->next) {
+		if ( (!patch->is_delete && is_null_sha1(patch->new_sha1)) ||
+		     (!patch->is_new && is_null_sha1(patch->old_sha1)) )
+			die("patch does not record sha1 information");
+	}
+
+	for (patch = list; patch; patch = patch->next) {
+		if (!is_null_sha1(patch->old_sha1))
+			printf("- %s %06o	%s\n",
+			       sha1_to_hex(patch->old_sha1),
+			       patch->old_mode,
+			       patch->old_name);
+
+		if (!is_null_sha1(patch->new_sha1))
+			printf("+ %s %06o	%s\n",
+			       sha1_to_hex(patch->new_sha1),
+			       patch->new_mode,
+			       patch->new_name);
+	}
+}
+
 static void stat_patch_list(struct patch *patch)
 {
 	int files, adds, dels;
@@ -1476,6 +1530,9 @@ static int apply_patch(int fd)
 	if (show_files)
 		show_file_list(list);
 
+	if (show_index_info)
+		show_index_list(list);
+
 	if (diffstat)
 		stat_patch_list(list);
 
@@ -1534,6 +1591,11 @@ int main(int argc, char **argv)
 			show_files = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--show-index-info")) {
+			apply = 0;
+			show_index_info = 1;
+			continue;
+		}
 		fd = open(arg, O_RDONLY);
 		if (fd < 0)
 			usage(apply_usage);
diff --git a/cache.h b/cache.h
old index ec2a1610b2fd6edec6c95847d4377f9c0241b738 100644
new index 514adb8f8ed621d98175bea0d701576de13eb620 100644
--- a/cache.h
+++ b/cache.h
@@ -165,6 +165,7 @@ extern int ce_match_stat(struct cache_en
 extern int ce_modified(struct cache_entry *ce, struct stat *st);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
+extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
 struct cache_file {
diff --git a/diff.c b/diff.c
old index 7d06b035ae8b6a53f10a7f94251a24d911baa509 100644
new index b602e25ccb2b4cf56dbfb5f2797651b1e44d4585 100644
--- a/diff.c
+++ b/diff.c
@@ -596,15 +596,31 @@ static void run_external_diff(const char
 	remove_tempfile();
 }
 
+static void diff_fill_sha1_info(struct diff_filespec *one)
+{
+	if (DIFF_FILE_VALID(one)) {
+		if (!one->sha1_valid) {
+			struct stat st;
+			if (stat(one->path, &st) < 0)
+				die("stat %s", one->path);
+			if (index_path(one->sha1, one->path, &st, 0))
+				die("cannot hash %s\n", one->path);
+		}
+	}
+	else
+		memset(one->sha1, 0, 20);
+}
+
 static void run_diff(struct diff_filepair *p)
 {
 	const char *pgm = external_diff();
-	char msg_[PATH_MAX*2+200], *xfrm_msg;
+	char msg[PATH_MAX*2+300], *xfrm_msg;
 	struct diff_filespec *one;
 	struct diff_filespec *two;
 	const char *name;
 	const char *other;
 	int complete_rewrite = 0;
+	int len;
 
 	if (DIFF_PAIR_UNMERGED(p)) {
 		/* unmerged */
@@ -616,38 +632,58 @@ static void run_diff(struct diff_filepai
 	name = p->one->path;
 	other = (strcmp(name, p->two->path) ? p->two->path : NULL);
 	one = p->one; two = p->two;
+
+	diff_fill_sha1_info(one);
+	diff_fill_sha1_info(two);
+
+	len = 0;
+	if (memcmp(one->sha1, two->sha1, 20)) {
+		if (memcmp(one->sha1, null_sha1, 20))
+			len += snprintf(msg + len, sizeof(msg) - len,
+					"old index %s %06o\n",
+					sha1_to_hex(one->sha1),
+					one->mode);
+		if (memcmp(two->sha1, null_sha1, 20))
+			len += snprintf(msg + len, sizeof(msg) - len,
+					"new index %s %06o\n",
+					sha1_to_hex(two->sha1),
+					two->mode);
+	}
+
 	switch (p->status) {
 	case DIFF_STATUS_COPIED:
-		sprintf(msg_,
-			"similarity index %d%%\n"
-			"copy from %s\n"
-			"copy to %s",
-			(int)(0.5 + p->score * 100.0/MAX_SCORE),
-			name, other);
-		xfrm_msg = msg_;
+		len += snprintf(msg + len, sizeof(msg) - len,
+				"similarity index %d%%\n"
+				"copy from %s\n"
+				"copy to %s\n",
+				(int)(0.5 + p->score * 100.0/MAX_SCORE),
+				name, other);
 		break;
 	case DIFF_STATUS_RENAMED:
-		sprintf(msg_,
-			"similarity index %d%%\n"
-			"rename from %s\n"
-			"rename to %s",
-			(int)(0.5 + p->score * 100.0/MAX_SCORE),
-			name, other);
-		xfrm_msg = msg_;
+		len += snprintf(msg + len, sizeof(msg) - len,
+				"similarity index %d%%\n"
+				"rename from %s\n"
+				"rename to %s\n",
+				(int)(0.5 + p->score * 100.0/MAX_SCORE),
+				name, other);
 		break;
 	case DIFF_STATUS_MODIFIED:
 		if (p->score) {
-			sprintf(msg_,
-				"dissimilarity index %d%%",
-				(int)(0.5 + p->score * 100.0/MAX_SCORE));
-			xfrm_msg = msg_;
+			len += snprintf(msg + len, sizeof(msg) - len,
+					"dissimilarity index %d%%\n",
+					(int)(0.5 + p->score *
+					      100.0/MAX_SCORE));
 			complete_rewrite = 1;
 			break;
 		}
 		/* fallthru */
 	default:
-		xfrm_msg = NULL;
+		/* nothing */
+		;
 	}
+	if (len)
+		msg[--len] = 0;
+	xfrm_msg = len ? msg : NULL;
 
 	if (!pgm &&
 	    DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
diff --git a/sha1_file.c b/sha1_file.c
old index 895c1fab6fc00b8131e44851f33b79b1d2310b12 100644
new index 287f618827d9b2fd472c06add42ead65de291822 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1545,3 +1545,42 @@ int index_fd(unsigned char *sha1, int fd
 		munmap(buf, size);
 	return ret;
 }
+
+int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)
+{
+	int fd;
+	char *target;
+
+	switch (st->st_mode & S_IFMT) {
+	case S_IFREG:
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			return error("open(\"%s\"): %s", path,
+				     strerror(errno));
+		if (index_fd(sha1, fd, st, write_object, NULL) < 0)
+			return error("%s: failed to insert into database",
+				     path);
+		break;
+	case S_IFLNK:
+		target = xmalloc(st->st_size+1);
+		if (readlink(path, target, st->st_size+1) != st->st_size) {
+			char *errstr = strerror(errno);
+			free(target);
+			return error("readlink(\"%s\"): %s", path,
+			             errstr);
+		}
+		if (!write_object) {
+			unsigned char hdr[50];
+			int hdrlen;
+			write_sha1_file_prepare(target, st->st_size, "blob",
+						sha1, hdr, &hdrlen);
+		} else if (write_sha1_file(target, st->st_size, "blob", sha1))
+			return error("%s: failed to insert into database",
+				     path);
+		free(target);
+		break;
+	default:
+		return error("%s: unsupported file type", path);
+	}
+	return 0;
+}
diff --git a/t/diff-lib.sh b/t/diff-lib.sh
old index a912f435aa67d7b2cde09f0b8c9855442c6c2377 100755
new index a4095db2ed3b57d5e042c5ca49dd912c1c534cf8 100755
--- a/t/diff-lib.sh
+++ b/t/diff-lib.sh
@@ -29,7 +29,13 @@ compare_diff_raw_z () {
 compare_diff_patch () {
     # When heuristics are improved, the score numbers would change.
     # Ignore them while comparing.
-    sed -e '/^[dis]*imilarity index [0-9]*%$/d' <"$1" >.tmp-1
-    sed -e '/^[dis]*imilarity index [0-9]*%$/d' <"$2" >.tmp-2
+    sed -e '
+	/^[dis]*imilarity index [0-9]*%$/d
+	/^[no][el][dw] index [0-9a-f]* [0-7]*$/d
+    ' <"$1" >.tmp-1
+    sed -e '
+	/^[dis]*imilarity index [0-9]*%$/d
+	/^[no][el][dw] index [0-9a-f]* [0-7]*$/d
+    ' <"$2" >.tmp-2
     diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh
old index f3b6330a9b4af0e68d9e402ab7d82e600c939ccc 100755
new index fa387cc24b8e5e6c92df9d1d504b805c92b94e36 100755
--- a/t/t4000-diff-format.sh
+++ b/t/t4000-diff-format.sh
@@ -7,6 +7,7 @@ test_description='Test built-in diff out
 
 '
 . ./test-lib.sh
+. ../diff-lib.sh
 
 echo >path0 'Line 1
 Line 2
@@ -29,6 +30,8 @@ cat >expected <<\EOF
 diff --git a/path0 b/path0
 old mode 100644
 new mode 100755
+old index 85d7fd2fbbe9564fe6ecc5e72416adb36e62d658 100644
+new index 6ad36e52f0002937ed2de6a1c15d8a0ae5df056a 100755
 --- a/path0
 +++ b/path0
 @@ -1,3 +1,3 @@
@@ -38,6 +41,7 @@ new mode 100755
 +Line 3
 diff --git a/path1 b/path1
 deleted file mode 100755
+old index 85d7fd2fbbe9564fe6ecc5e72416adb36e62d658 100755
 --- a/path1
 +++ /dev/null
 @@ -1,3 +0,0 @@
@@ -48,6 +52,6 @@ EOF
 
 test_expect_success \
     'validate git-diff-files -p output.' \
-    'cmp -s current expected'
+    'compare_diff_patch current expected'
 
 test_done
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
old index be474856824f8e6659151590ed5acff38187e97d 100755
new index 2e3c20d6b9468bf413e97d422e7dbe13ac4238cd 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -7,6 +7,7 @@ test_description='Test rename detection 
 
 '
 . ./test-lib.sh
+. ../diff-lib.sh
 
 echo >path0 'Line 1
 Line 2
@@ -61,6 +62,6 @@ EOF
 
 test_expect_success \
     'validate the output.' \
-    'diff -I "similarity.*" >/dev/null current expected'
+    'compare_diff_patch current expected'
 
 test_done
diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh
old index f59614ae255b33f450a784200716c9fd63b0a054 100755
new index a23aaa0a9471c68b233480cf34c7115d1f40e154 100755
--- a/t/t4004-diff-rename-symlink.sh
+++ b/t/t4004-diff-rename-symlink.sh
@@ -10,6 +10,7 @@ copy of symbolic links, but should not p
 by an edit for them.
 '
 . ./test-lib.sh
+. ../diff-lib.sh
 
 test_expect_success \
     'prepare reference tree' \
@@ -61,6 +62,6 @@ EOF
 
 test_expect_success \
     'validate diff output' \
-    'diff -u current expected'
+    'compare_diff_patch current expected'
 
 test_done
diff --git a/update-index.c b/update-index.c
old index b825a11d2f6d8a53f5e42e4f157ba036a13edb59 100644
new index 9dc518877b67bedced29ac91ecd8fafbb2a60135 100644
--- a/update-index.c
+++ b/update-index.c
@@ -37,8 +37,6 @@ static int add_file_to_cache(const char 
 	int size, namelen, option, status;
 	struct cache_entry *ce;
 	struct stat st;
-	int fd;
-	char *target;
 
 	status = lstat(path, &st);
 	if (status < 0 || S_ISDIR(st.st_mode)) {
@@ -77,34 +75,9 @@ static int add_file_to_cache(const char 
 	fill_stat_cache_info(ce, &st);
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	ce->ce_flags = htons(namelen);
-	switch (st.st_mode & S_IFMT) {
-	case S_IFREG:
-		fd = open(path, O_RDONLY);
-		if (fd < 0)
-			return error("open(\"%s\"): %s", path, strerror(errno));
-		if (index_fd(ce->sha1, fd, &st, !info_only, NULL) < 0)
-			return error("%s: failed to insert into database", path);
-		break;
-	case S_IFLNK:
-		target = xmalloc(st.st_size+1);
-		if (readlink(path, target, st.st_size+1) != st.st_size) {
-			char *errstr = strerror(errno);
-			free(target);
-			return error("readlink(\"%s\"): %s", path,
-			             errstr);
-		}
-		if (info_only) {
-			unsigned char hdr[50];
-			int hdrlen;
-			write_sha1_file_prepare(target, st.st_size, "blob",
-						ce->sha1, hdr, &hdrlen);
-		} else if (write_sha1_file(target, st.st_size, "blob", ce->sha1))
-			return error("%s: failed to insert into database", path);
-		free(target);
-		break;
-	default:
-		return error("%s: unsupported file type", path);
-	}
+
+	if (index_path(ce->sha1, path, &st, !info_only))
+		return -1;
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
 	if (add_cache_entry(ce, option))
---
0.99.8.GIT

^ permalink raw reply	[relevance 7%]

* [PATCH] If NO_MMAP is defined, fake mmap() and munmap()
@ 2005-10-07 22:55 14% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-10-07 22:55 UTC (permalink / raw)
  To: git; +Cc: junkio


Since some platforms do not support mmap() at all, and others do only just 
so, this patch introduces the option to fake mmap() and munmap() by 
malloc()ing and read()ing explicitely.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

Only lightly tested, but it seems to work correctly (after all, this 
commit was created after compiling with NO_MMAP=1).

 Makefile      |    6 +++
 cache.h       |   16 ++++++++
 compat/mmap.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mailsplit.c   |    1 -
 4 files changed, 135 insertions(+), 1 deletions(-)
 create mode 100644 compat/mmap.c

applies-to: 2c165e1b55bf857247c0f074e9bea680bf411586
3d4f1e103b35c28c8190f9a59ffa95221277fdb4
diff --git a/Makefile b/Makefile
index 2f7cdd4..fb4c410 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,8 @@
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
 # Patrick Mauritz).
 #
+# Define NO_MMAP if you want to avoid mmap.
+#
 # Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
 #
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
@@ -259,6 +261,10 @@ ifdef NO_STRCASESTR
 	DEFINES += -Dstrcasestr=gitstrcasestr
 	LIB_OBJS += compat/strcasestr.o
 endif
+ifdef NO_MMAP
+	DEFINES += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
+	LIB_OBJS += compat/mmap.o
+endif
 ifdef NO_IPV6
 	DEFINES += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
 endif
diff --git a/cache.h b/cache.h
index 514adb8..5987d4c 100644
--- a/cache.h
+++ b/cache.h
@@ -11,7 +11,9 @@
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
+#ifndef NO_MMAP
 #include <sys/mman.h>
+#endif
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <sys/types.h>
@@ -356,4 +358,18 @@ extern void packed_object_info_detail(st
 /* Dumb servers support */
 extern int update_server_info(int);
 
+#ifdef NO_MMAP
+
+#ifndef PROT_READ
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define MAP_PRIVATE 1
+#define MAP_FAILED ((void*)-1)
+#endif
+
+extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
+extern int gitfakemunmap(void *start, size_t length);
+
+#endif
+
 #endif /* CACHE_H */
diff --git a/compat/mmap.c b/compat/mmap.c
new file mode 100644
index 0000000..fca6321
--- /dev/null
+++ b/compat/mmap.c
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "../cache.h"
+
+typedef struct fakemmapwritable {
+	void *start;
+	size_t length;
+	int fd;
+	off_t offset;
+	struct fakemmapwritable *next;
+} fakemmapwritable;
+
+static fakemmapwritable *writablelist = NULL;
+
+void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
+{
+	int n = 0;
+
+	if(start != NULL)
+		die("Invalid usage of gitfakemmap.");
+
+	if(lseek(fd, offset, SEEK_SET)<0) {
+		errno = EINVAL;
+		return MAP_FAILED;
+	}
+
+	start = xmalloc(length);
+	if(start == NULL) {
+		errno = ENOMEM;
+		return MAP_FAILED;
+	}
+
+	while(n < length) {
+		int count = read(fd, start+n, length-n);
+
+		if(count == 0) {
+			memset(start+n, 0, length-n);
+			break;
+		}
+
+		if(count < 0) {
+			free(start);
+			errno = EACCES;
+			return MAP_FAILED;
+		}
+
+		n += count;
+	}
+
+	if(prot & PROT_WRITE) {
+		fakemmapwritable *next = xmalloc(sizeof(fakemmapwritable));
+		next->start = start;
+		next->length = length;
+		next->fd = dup(fd);
+		next->offset = offset;
+		next->next = writablelist;
+		writablelist = next;
+	}
+
+	return start;
+}
+
+int gitfakemunmap(void *start, size_t length)
+{
+	fakemmapwritable *writable = writablelist, *before = NULL;
+
+	while(writable && (writable->start > start + length
+			|| writable->start + writable->length < start)) {
+		before = writable;
+		writable = writable->next;
+	}
+
+	if(writable) {
+		/* need to write back the contents */
+		int n = 0;
+
+		if(writable->start != start || writable->length != length)
+			die("fakemmap does not support partial write back.");
+
+		if(lseek(writable->fd, writable->offset, SEEK_SET) < 0) {
+			free(start);
+			errno = EBADF;
+			return -1;
+		}
+
+		while(n < length) {
+			int count = write(writable->fd, start + n, length - n);
+
+			if(count < 0) {
+				errno = EINVAL;
+				return -1;
+			}
+
+			n += count;
+		}
+
+		close(writable->fd);
+
+		if(before)
+			before->next = writable->next;
+		else
+			writablelist = writable->next;
+
+		free(writable);
+	}
+
+	free(start);
+
+	return 0;
+}
+
diff --git a/mailsplit.c b/mailsplit.c
index 7981f87..0f8100d 100644
--- a/mailsplit.c
+++ b/mailsplit.c
@@ -9,7 +9,6 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/mman.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
---
0.99.8.GIT

^ permalink raw reply related	[relevance 14%]

* Re: First cut at git port to Cygwin
  @ 2005-10-08 22:06 15%                               ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-10-08 22:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Linus Torvalds

Hi,

On Sat, 8 Oct 2005, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > Sure. Something like this?
> 
> Not, really.  What I meant was to rip out the writing out
> altogether, and perhaps making sure that the caller never calls
> us without MAP_PRIVATE.

How about this, then?

[PATCH] If NO_MMAP is defined, fake mmap() and munmap()

Since some platforms do not support mmap() at all, and others do only just so,
this patch introduces the option to fake mmap() and munmap() by malloc()ing the
region explicitely.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 Makefile      |    6 ++++++
 cache.h       |   16 ++++++++++++++++
 compat/mmap.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 mailsplit.c   |    1 -
 4 files changed, 73 insertions(+), 1 deletions(-)
 create mode 100644 compat/mmap.c

applies-to: 274542bcbc891cca353c2728ac4075df3d1d2c0d
ed334e3e2276fe9d41ed78917544ef6a3fa87eb7
diff --git a/Makefile b/Makefile
index 1bdf4de..7ca77cf 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,8 @@
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
 # Patrick Mauritz).
 #
+# Define NO_MMAP if you want to avoid mmap.
+#
 # Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
 #
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
@@ -258,6 +260,10 @@ ifdef NO_STRCASESTR
 	DEFINES += -Dstrcasestr=gitstrcasestr
 	LIB_OBJS += compat/strcasestr.o
 endif
+ifdef NO_MMAP
+	DEFINES += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
+	LIB_OBJS += compat/mmap.o
+endif
 ifdef NO_IPV6
 	DEFINES += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
 endif
diff --git a/cache.h b/cache.h
index 514adb8..5987d4c 100644
--- a/cache.h
+++ b/cache.h
@@ -11,7 +11,9 @@
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
+#ifndef NO_MMAP
 #include <sys/mman.h>
+#endif
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <sys/types.h>
@@ -356,4 +358,18 @@ extern void packed_object_info_detail(st
 /* Dumb servers support */
 extern int update_server_info(int);
 
+#ifdef NO_MMAP
+
+#ifndef PROT_READ
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define MAP_PRIVATE 1
+#define MAP_FAILED ((void*)-1)
+#endif
+
+extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
+extern int gitfakemunmap(void *start, size_t length);
+
+#endif
+
 #endif /* CACHE_H */
diff --git a/compat/mmap.c b/compat/mmap.c
new file mode 100644
index 0000000..3f035a0
--- /dev/null
+++ b/compat/mmap.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "../cache.h"
+
+void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
+{
+	int n = 0;
+
+	if(start != NULL || !(flags & MAP_PRIVATE))
+		die("Invalid usage of gitfakemmap.");
+
+	if(lseek(fd, offset, SEEK_SET)<0) {
+		errno = EINVAL;
+		return MAP_FAILED;
+	}
+
+	start = xmalloc(length);
+	if(start == NULL) {
+		errno = ENOMEM;
+		return MAP_FAILED;
+	}
+
+	while(n < length) {
+		int count = read(fd, start+n, length-n);
+
+		if(count == 0) {
+			memset(start+n, 0, length-n);
+			break;
+		}
+
+		if(count < 0) {
+			free(start);
+			errno = EACCES;
+			return MAP_FAILED;
+		}
+
+		n += count;
+	}
+
+	return start;
+}
+
+int gitfakemunmap(void *start, size_t length)
+{
+	free(start);
+
+	return 0;
+}
+
diff --git a/mailsplit.c b/mailsplit.c
index 7981f87..0f8100d 100644
--- a/mailsplit.c
+++ b/mailsplit.c
@@ -9,7 +9,6 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/mman.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
---
0.99.8.GIT

^ permalink raw reply related	[relevance 15%]

* Use the same move_temp_to_file in git-http-fetch.
  @ 2005-10-09 10:42 14%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-09 10:42 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Linus Torvalds, Git Mailing List

The http commit walker cannot use the same temporary file
creation code because it needs to use predictable temporary
filename for partial fetch continuation purposes, but the code
to move the temporary file to the final location should be
usable from the ordinary object creation case.

Export move_temp_to_file from sha1_file.c and use it, while
losing the custom relink_or_rename function from http-fetch.c.

Also the temporary object file creation part needs to make sure
the leading path exists, in preparation of the really lazy
fan-out directory creation.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

    Daniel Barkalow <barkalow@iabervon.org> writes:

    > This looks right to me, but it would be nice to also split out and 
    > share the temp file creation. Also, http-fetch.c writes object files and 
    > needs at least move_temp_to_file() if it's going to do special stuff.

    I agree.  The proposed updates branch has this patch.

 cache.h      |    1 +
 http-fetch.c |   47 ++++++++++++++++++-----------------------------
 sha1_file.c  |    2 +-
 3 files changed, 20 insertions(+), 30 deletions(-)

applies-to: f3741b89b850db8d343d3cde58416e076964c952
07d374bffd6fcd0c67c671902dde9402335776f5
diff --git a/cache.h b/cache.h
index 5987d4c..28077fc 100644
--- a/cache.h
+++ b/cache.h
@@ -221,6 +221,7 @@ extern int read_tree(void *buffer, unsig
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
 			      size_t bufsize, size_t *bufposn);
 extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
+extern int move_temp_to_file(const char *tmpfile, char *filename);
 
 extern int has_sha1_pack(const unsigned char *sha1);
 extern int has_sha1_file(const unsigned char *sha1);
diff --git a/http-fetch.c b/http-fetch.c
index 5d0e3e3..c617583 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -138,25 +138,6 @@ static size_t fwrite_sha1_file(void *ptr
 	return size;
 }
 
-int relink_or_rename(char *old, char *new) {
-	int ret;
-
-	ret = link(old, new);
-	if (ret < 0) {
-		/* Same Coda hack as in write_sha1_file(sha1_file.c) */
-		ret = errno;
-		if (ret == EXDEV && !rename(old, new))
-			return 0;
-	}
-	unlink(old);
-	if (ret) {
-		if (ret != EEXIST)
-			return ret;
-	}
-
-	return 0;
-}
-
 #ifdef USE_CURL_MULTI
 void process_curl_messages();
 void process_request_queue();
@@ -295,6 +276,20 @@ void start_request(struct transfer_reque
 
 	request->local = open(request->tmpfile,
 			      O_WRONLY | O_CREAT | O_EXCL, 0666);
+	/* This could have failed due to the "lazy directory creation";
+	 * try to mkdir the last path component.
+	 */
+	if (request->local < 0 && errno == ENOENT) {
+		char *dir = strrchr(request->tmpfile, '/');
+		if (dir) {
+			*dir = 0;
+			mkdir(request->tmpfile, 0777);
+			*dir = '/';
+		}
+		request->local = open(request->tmpfile,
+				      O_WRONLY | O_CREAT | O_EXCL, 0666);
+	}
+
 	if (request->local < 0) {
 		request->state = ABORTED;
 		error("Couldn't create temporary file %s for %s: %s\n",
@@ -408,7 +403,7 @@ void finish_request(struct transfer_requ
 		return;
 	}
 	request->rename =
-		relink_or_rename(request->tmpfile, request->filename);
+		move_temp_to_file(request->tmpfile, request->filename);
 
 	if (request->rename == 0)
 		pull_say("got %s\n", sha1_to_hex(request->sha1));
@@ -599,12 +594,7 @@ static int fetch_index(struct alt_base *
 
 	fclose(indexfile);
 
-	ret = relink_or_rename(tmpfile, filename);
-	if (ret)
-		return error("unable to write index filename %s: %s",
-			     filename, strerror(ret));
-
-	return 0;
+	return move_temp_to_file(tmpfile, filename);
 }
 
 static int setup_index(struct alt_base *repo, unsigned char *sha1)
@@ -869,10 +859,9 @@ static int fetch_pack(struct alt_base *r
 
 	fclose(packfile);
 
-	ret = relink_or_rename(tmpfile, filename);
+	ret = move_temp_to_file(tmpfile, filename);
 	if (ret)
-		return error("unable to write pack filename %s: %s",
-			     filename, strerror(ret));
+		return ret;
 
 	lst = &repo->packs;
 	while (*lst != target)
diff --git a/sha1_file.c b/sha1_file.c
index baaa4c0..6e3ea23 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1287,7 +1287,7 @@ static int link_temp_to_file(const char 
 /*
  * Move the just written object into its final resting place
  */
-static int move_temp_to_file(const char *tmpfile, char *filename)
+int move_temp_to_file(const char *tmpfile, char *filename)
 {
 	int ret = link_temp_to_file(tmpfile, filename);
 	if (ret) {
---
0.99.8.GIT

^ permalink raw reply related	[relevance 14%]

* Add ".git/config" file parser
  @ 2005-10-10 21:35 13%                 ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-10-10 21:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List


This is a first cut at a very simple parser for a git config file.

The format of the file is a simple ini-file like thing, with simple 
variable/value pairs. You can (and should) make the variables have a 
simple single-level scope, ie a valid file looks something like this:

	#
	# This is the config file, and
	# a '#' or ';' character indicates
	# a comment
	#

	; core variables
	[core]
		; Don't trust file modes
		filemode = false

	; Our diff algorithm 
	[diff]
		external = "/usr/local/bin/gnu-diff -u"
		renames = true

which parses into two variables: "core.filemode" is associated with the 
string "false", and "diff.external" gets the appropriate quoted value.

Right now we only react to one variable: "core.filemode" is a boolean that 
decides if we should care about the 0100 (user-execute) bit of the stat 
information. Even that is just a parsing demonstration - this doesn't 
actually implement that st_mode compare logic itself.

Different programs can react to different config options, although they 
should always fall back to calling "git_default_config()" on any config 
option name that they don't recognize.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
----

Ok, so it's stupid. But quite frankly, I think the Windows ini-file format 
is a hell of a lot more readable than something over-engineered like XML 
files or other crap.

The interface is really easy to use, imho. You can do things like

	static int enable_renames = 0;

	static int my_options(const char *var, const char *value)
	{
		if (!strcmp("diff.renames", var)) {
			enable_renames = git_config_bool(var, value);
			return 0;
		}

		/*
		 * Put other local option parsing for this program
		 * here .. 
		 */

		/* Fall back on the default ones */
		return git_default_config(var, value);
	}

and then in the "main()" routine you just do

		git_config(my_options);

at the top (or, more precisely, just after the "git_setup_directory()" if 
you have one).

And as usual, it's not like this has gotten a whole lot of testing.

Flames, comments, whatever? The code is actually written so that the 
config file parsing should really be pretty neutral. It doesn't even have 
any git-specific in it, except for the naming and the actual initial 
"fopen()" pathname used, I think.

---
diff --git a/Makefile b/Makefile
index a201187..e8b46f1 100644
--- a/Makefile
+++ b/Makefile
@@ -158,7 +158,7 @@ LIB_OBJS = \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
-	tag.o tree.o usage.o $(DIFF_OBJS)
+	tag.o tree.o usage.o config.o $(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
 LIBS += -lz
diff --git a/cache.h b/cache.h
index 5987d4c..0571282 100644
--- a/cache.h
+++ b/cache.h
@@ -178,6 +178,8 @@ extern int hold_index_file_for_update(st
 extern int commit_index_file(struct cache_file *);
 extern void rollback_index_file(struct cache_file *);
 
+extern int trust_executable_bit;
+
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
 #define OWNER_CHANGED	0x0004
@@ -372,4 +374,10 @@ extern int gitfakemunmap(void *start, si
 
 #endif
 
+typedef int (*config_fn_t)(const char *, const char *);
+extern int git_default_config(const char *, const char *);
+extern int git_config(config_fn_t fn);
+extern int git_config_int(const char *, const char *);
+extern int git_config_bool(const char *, const char *);
+
 #endif /* CACHE_H */
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..f3c4fa4
--- /dev/null
+++ b/config.c
@@ -0,0 +1,222 @@
+#include <ctype.h>
+
+#include "cache.h"
+
+#define MAXNAME (256)
+
+static FILE *config_file;
+static int config_linenr;
+static int get_next_char(void)
+{
+	int c;
+	FILE *f;
+
+	c = '\n';
+	if ((f = config_file) != NULL) {
+		c = fgetc(f);
+		if (c == '\n')
+			config_linenr++;
+		if (c == EOF) {
+			config_file = NULL;
+			c = '\n';
+		}
+	}
+	return c;
+}
+
+static char *parse_value(void)
+{
+	static char value[1024];
+	int quote = 0, comment = 0, len = 0, space = 0;
+
+	for (;;) {
+		int c = get_next_char();
+		if (len >= sizeof(value))
+			return NULL;
+		if (c == '\n') {
+			if (quote)
+				return NULL;
+			value[len] = 0;
+			return value;
+		}
+		if (comment)
+			continue;
+		if (isspace(c) && !quote) {
+			space = 1;
+			continue;
+		}
+		if (space) {
+			if (len)
+				value[len++] = ' ';
+			space = 0;
+		}
+		if (c == '\\') {
+			c = get_next_char();
+			switch (c) {
+			case '\n':
+				continue;
+			case 't':
+				c = '\t';
+				break;
+			case 'b':
+				c = '\b';
+				break;
+			case 'n':
+				c = '\n';
+				break;
+			return NULL;
+			}
+			value[len++] = c;
+			continue;
+		}
+		if (c == '"') {
+			quote = 1-quote;
+			continue;
+		}
+		if (!quote) {
+			if (c == ';' || c == '#') {
+				comment = 1;
+				continue;
+			}
+		}
+		value[len++] = c;
+	}
+}
+
+static int get_value(config_fn_t fn, char *name, unsigned int len)
+{
+	int c;
+	char *value;
+
+	/* Get the full name */
+	for (;;) {
+		c = get_next_char();
+		if (c == EOF)
+			break;
+		if (!isalnum(c))
+			break;
+		name[len++] = tolower(c);
+		if (len >= MAXNAME)
+			return -1;
+	}
+	name[len] = 0;
+	while (c == ' ' || c == '\t')
+		c = get_next_char();
+
+	value = NULL;
+	if (c != '\n') {
+		if (c != '=')
+			return -1;
+		value = parse_value();
+		if (!value)
+			return -1;
+	}
+	return fn(name, value);
+}
+
+static int get_base_var(char *name)
+{
+	int baselen = 0;
+
+	for (;;) {
+		int c = get_next_char();
+		if (c == EOF)
+			return -1;
+		if (c == ']')
+			return baselen;
+		if (!isalnum(c))
+			return -1;
+		if (baselen > MAXNAME / 2)
+			return -1;
+		name[baselen++] = tolower(c);
+	}
+}
+
+static int git_parse_file(config_fn_t fn)
+{
+	int comment = 0;
+	int baselen = 0;
+	static char var[MAXNAME];
+
+	for (;;) {
+		int c = get_next_char();
+		if (c == '\n') {
+			/* EOF? */
+			if (!config_file)
+				return 0;
+			comment = 0;
+			continue;
+		}
+		if (comment || isspace(c))
+			continue;
+		if (c == '#' || c == ';') {
+			comment = 1;
+			continue;
+		}
+		if (c == '[') {
+			baselen = get_base_var(var);
+			if (baselen <= 0)
+				break;
+			var[baselen++] = '.';
+			var[baselen] = 0;
+			continue;
+		}
+		if (!isalpha(c))
+			break;
+		var[baselen] = c;
+		if (get_value(fn, var, baselen+1) < 0)
+			break;
+	}
+	die("bad config file line %d", config_linenr);
+}
+
+int git_config_int(const char *name, const char *value)
+{
+	if (value && *value) {
+		char *end;
+		int val = strtol(value, &end, 0);
+		if (!*end)
+			return val;
+	}
+	die("bad config value for '%s'", name);
+}
+
+int git_config_bool(const char *name, const char *value)
+{
+	if (!value)
+		return 1;
+	if (!*value)
+		return 0;
+	if (!strcasecmp(value, "true"))
+		return 1;
+	if (!strcasecmp(value, "false"))
+		return 0;
+	return git_config_int(name, value) != 0;
+}
+
+int git_default_config(const char *var, const char *value)
+{
+	/* This needs a better name */
+	if (!strcmp(var, "core.filemode")) {
+		trust_executable_bit = git_config_bool(var, value);
+		return 0;
+	}
+
+	/* Add other config variables here.. */
+	return 0;
+}
+
+int git_config(config_fn_t fn)
+{
+	int ret;
+	FILE *f = fopen(git_path("config"), "r");
+
+	ret = -1;
+	if (f) {
+		config_file = f;
+		config_linenr = 1;
+		ret = git_parse_file(fn);
+		fclose(f);
+	}
+	return ret;
+}
diff --git a/diff-files.c b/diff-files.c
index 5e59832..96d2c7f 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -38,6 +38,7 @@ int main(int argc, const char **argv)
 	const char *prefix = setup_git_directory();
 	int entries, i;
 
+	git_config(git_default_config);
 	diff_setup(&diff_options);
 	while (1 < argc && argv[1][0] == '-') {
 		if (!strcmp(argv[1], "-q"))
diff --git a/diff-tree.c b/diff-tree.c
index b2d74eb..2203fa5 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -408,6 +408,7 @@ int main(int argc, const char **argv)
 	unsigned char sha1[2][20];
 	const char *prefix = setup_git_directory();
 
+	git_config(git_default_config);
 	nr_sha1 = 0;
 	diff_setup(&diff_options);
 
diff --git a/read-cache.c b/read-cache.c
index d2aebdd..c7f3b26 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -5,6 +5,7 @@
  */
 #include "cache.h"
 
+int trust_executable_bit = 1;
 struct cache_entry **active_cache = NULL;
 unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 

^ permalink raw reply related	[relevance 13%]

* Use git config file for committer name and email info
@ 2005-10-12  0:54 12% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-10-12  0:54 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This starts using the "user.name" and "user.email" config variables if
they exist as the default name and email when committing.  This means
that you don't have to use the GIT_COMMITTER_EMAIL environment variable
to override your email - you can just edit the config file instead.

The patch looks bigger than it is because it makes the default name and
email information non-static and renames it appropriately.  And it moves
the common git environment variables into a new library file, so that
you can link against libgit.a and get the git environment without having
to link in zlib and libcrypt.

In short, most of it is renaming and moving, the real change core is
just a few new lines in "git_default_config()" that copies the user
config values to the new base.

It also changes "git-var -l" to list the config variables.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

With this, you can now have a .git/config file that has something like 
this in it:

	[user]
	   name = Linus Torvalds
	   email = torvalds@osdl.org

	[core]
	   filemode = false

and it will do the obvious thing. The "user.name" and "user.email" 
variables will be used by default for the name information, overriding any 
system information from /etc/passwd etc.

NOTE! The GIT_{COMMITTER|AUTHOR}_NAME and GIT_{COMMITTER|AUTHOR}_EMAIL 
environment variables continue to override any config file information. 

Also, we should probably verify that the name/email is valid (ie doesn't 
contain any of the characters "<>\n" that could cause invalid commit 
objects).

The fact that "git-var -l" now also shows all config info can be useful. 

For example, scripts can use it to pick up stuff from the config file, ie 
we could make "git tag" get the default key from there by adding something 
like

	key=$(git-var -l | sed -n '/^user\.key=/ { s/user.key=//;p;q}')

to the script, which again allows us to have a convenient default value in 
the config file without littering us up with more environment variables.

Hmm?

This hasn't gotten a ton of testing, but I did do a test-commit with this, 
and it all seems to work.

---
 Makefile      |    2 +-
 cache.h       |    4 +++
 commit-tree.c |    4 ++-
 config.c      |   10 ++++++++
 environment.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ident.c       |   30 +++++++++++------------
 read-cache.c  |    1 -
 sha1_file.c   |   59 ---------------------------------------------
 var.c         |   11 ++++++++
 9 files changed, 118 insertions(+), 78 deletions(-)

diff --git a/Makefile b/Makefile
index 8697d52..ee3a752 100644
--- a/Makefile
+++ b/Makefile
@@ -158,7 +158,7 @@ LIB_OBJS = \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
-	tag.o tree.o usage.o config.o $(DIFF_OBJS)
+	tag.o tree.o usage.o config.o environment.o $(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
 LIBS += -lz
diff --git a/cache.h b/cache.h
index 41cc22c..1a7e047 100644
--- a/cache.h
+++ b/cache.h
@@ -382,4 +382,8 @@ extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
 
+#define MAX_GITNAME (1000)
+extern char git_default_email[MAX_GITNAME];
+extern char git_default_name[MAX_GITNAME];
+
 #endif /* CACHE_H */
diff --git a/commit-tree.c b/commit-tree.c
index b1ef0b5..030fb70 100644
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -89,6 +89,9 @@ int main(int argc, char **argv)
 	char *buffer;
 	unsigned int size;
 
+	setup_ident();
+	git_config(git_default_config);
+
 	if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
 		usage(commit_tree_usage);
 
@@ -104,7 +107,6 @@ int main(int argc, char **argv)
 	}
 	if (!parents)
 		fprintf(stderr, "Committing initial tree %s\n", argv[1]);
-	setup_ident();
 
 	init_buffer(&buffer, &size);
 	add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
diff --git a/config.c b/config.c
index 510456c..cf80358 100644
--- a/config.c
+++ b/config.c
@@ -207,6 +207,16 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "user.name")) {
+		strncpy(git_default_name, value, sizeof(git_default_name));
+		return 0;
+	}
+
+	if (!strcmp(var, "user.email")) {
+		strncpy(git_default_email, value, sizeof(git_default_email));
+		return 0;
+	}
+
 	/* Add other config variables here.. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
new file mode 100644
index 0000000..1dc7af5
--- /dev/null
+++ b/environment.c
@@ -0,0 +1,75 @@
+/*
+ * We put all the git config variables in this same object
+ * file, so that programs can link against the config parser
+ * without having to link against all the rest of git.
+ *
+ * In particular, no need to bring in libz etc unless needed,
+ * even if you might want to know where the git directory etc
+ * are.
+ */
+#include "cache.h"
+
+char git_default_email[MAX_GITNAME];
+char git_default_name[MAX_GITNAME];
+int trust_executable_bit = 1;
+
+static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
+	*git_graft_file;
+static void setup_git_env(void)
+{
+	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	if (!git_dir)
+		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+	git_object_dir = getenv(DB_ENVIRONMENT);
+	if (!git_object_dir) {
+		git_object_dir = xmalloc(strlen(git_dir) + 9);
+		sprintf(git_object_dir, "%s/objects", git_dir);
+	}
+	git_refs_dir = xmalloc(strlen(git_dir) + 6);
+	sprintf(git_refs_dir, "%s/refs", git_dir);
+	git_index_file = getenv(INDEX_ENVIRONMENT);
+	if (!git_index_file) {
+		git_index_file = xmalloc(strlen(git_dir) + 7);
+		sprintf(git_index_file, "%s/index", git_dir);
+	}
+	git_graft_file = getenv(GRAFT_ENVIRONMENT);
+	if (!git_graft_file)
+		git_graft_file = strdup(git_path("info/grafts"));
+}
+
+char *get_git_dir(void)
+{
+	if (!git_dir)
+		setup_git_env();
+	return git_dir;
+}
+
+char *get_object_directory(void)
+{
+	if (!git_object_dir)
+		setup_git_env();
+	return git_object_dir;
+}
+
+char *get_refs_directory(void)
+{
+	if (!git_refs_dir)
+		setup_git_env();
+	return git_refs_dir;
+}
+
+char *get_index_file(void)
+{
+	if (!git_index_file)
+		setup_git_env();
+	return git_index_file;
+}
+
+char *get_graft_file(void)
+{
+	if (!git_graft_file)
+		setup_git_env();
+	return git_graft_file;
+}
+
+
diff --git a/ident.c b/ident.c
index 562f5f1..7a9f567 100644
--- a/ident.c
+++ b/ident.c
@@ -11,9 +11,7 @@
 #include <time.h>
 #include <ctype.h>
 
-static char real_email[1000];
-static char real_name[1000];
-static char real_date[50];
+static char git_default_date[50];
 
 static void copy_gecos(struct passwd *w, char *name, int sz)
 {
@@ -58,22 +56,22 @@ int setup_ident(void)
 		die("You don't exist. Go away!");
 
 	/* Get the name ("gecos") */
-	copy_gecos(pw, real_name, sizeof(real_name));
+	copy_gecos(pw, git_default_name, sizeof(git_default_name));
 
 	/* Make up a fake email address (name + '@' + hostname [+ '.' + domainname]) */
 	len = strlen(pw->pw_name);
-	if (len > sizeof(real_email)/2)
+	if (len > sizeof(git_default_email)/2)
 		die("Your sysadmin must hate you!");
-	memcpy(real_email, pw->pw_name, len);
-	real_email[len++] = '@';
-	gethostname(real_email + len, sizeof(real_email) - len);
-	if (!strchr(real_email+len, '.')) {
-		len = strlen(real_email);
-		real_email[len++] = '.';
-		getdomainname(real_email+len, sizeof(real_email)-len);
+	memcpy(git_default_email, pw->pw_name, len);
+	git_default_email[len++] = '@';
+	gethostname(git_default_email + len, sizeof(git_default_email) - len);
+	if (!strchr(git_default_email+len, '.')) {
+		len = strlen(git_default_email);
+		git_default_email[len++] = '.';
+		getdomainname(git_default_email+len, sizeof(git_default_email)-len);
 	}
 	/* And set the default date */
-	datestamp(real_date, sizeof(real_date));
+	datestamp(git_default_date, sizeof(git_default_date));
 	return 0;
 }
 
@@ -159,10 +157,10 @@ char *get_ident(const char *name, const 
 	int i;
 
 	if (!name)
-		name = real_name;
+		name = git_default_name;
 	if (!email)
-		email = real_email;
-	strcpy(date, real_date);
+		email = git_default_email;
+	strcpy(date, git_default_date);
 	if (date_str)
 		parse_date(date_str, date, sizeof(date));
 
diff --git a/read-cache.c b/read-cache.c
index c7f3b26..d2aebdd 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -5,7 +5,6 @@
  */
 #include "cache.h"
 
-int trust_executable_bit = 1;
 struct cache_entry **active_cache = NULL;
 unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 
diff --git a/sha1_file.c b/sha1_file.c
index 6e3ea23..f059004 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -48,65 +48,6 @@ int get_sha1_hex(const char *hex, unsign
 	return 0;
 }
 
-static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
-	*git_graft_file;
-static void setup_git_env(void)
-{
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
-	if (!git_dir)
-		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
-	git_object_dir = getenv(DB_ENVIRONMENT);
-	if (!git_object_dir) {
-		git_object_dir = xmalloc(strlen(git_dir) + 9);
-		sprintf(git_object_dir, "%s/objects", git_dir);
-	}
-	git_refs_dir = xmalloc(strlen(git_dir) + 6);
-	sprintf(git_refs_dir, "%s/refs", git_dir);
-	git_index_file = getenv(INDEX_ENVIRONMENT);
-	if (!git_index_file) {
-		git_index_file = xmalloc(strlen(git_dir) + 7);
-		sprintf(git_index_file, "%s/index", git_dir);
-	}
-	git_graft_file = getenv(GRAFT_ENVIRONMENT);
-	if (!git_graft_file)
-		git_graft_file = strdup(git_path("info/grafts"));
-}
-
-char *get_git_dir(void)
-{
-	if (!git_dir)
-		setup_git_env();
-	return git_dir;
-}
-
-char *get_object_directory(void)
-{
-	if (!git_object_dir)
-		setup_git_env();
-	return git_object_dir;
-}
-
-char *get_refs_directory(void)
-{
-	if (!git_refs_dir)
-		setup_git_env();
-	return git_refs_dir;
-}
-
-char *get_index_file(void)
-{
-	if (!git_index_file)
-		setup_git_env();
-	return git_index_file;
-}
-
-char *get_graft_file(void)
-{
-	if (!git_graft_file)
-		setup_git_env();
-	return git_graft_file;
-}
-
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path;
diff --git a/var.c b/var.c
index 3f13126..51cf86a 100644
--- a/var.c
+++ b/var.c
@@ -42,6 +42,15 @@ static const char *read_var(const char *
 	return val;
 }
 
+static int show_config(const char *var, const char *value)
+{
+	if (value)
+		printf("%s=%s\n", var, value);
+	else
+		printf("%s\n", var);
+	return git_default_config(var, value);
+}
+
 int main(int argc, char **argv)
 {
 	const char *val;
@@ -52,9 +61,11 @@ int main(int argc, char **argv)
 	val = NULL;
 
 	if (strcmp(argv[1], "-l") == 0) {
+		git_config(show_config);
 		list_vars();
 		return 0;
 	}
+	git_config(git_default_config);
 	val = read_var(argv[1]);
 	if (!val)
 		usage(var_usage);

^ permalink raw reply related	[relevance 12%]

* Re: Usage of isspace and friends
  @ 2005-10-13 15:46 12%     ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-10-13 15:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Morten Welinder, Git Mailing List



On Thu, 13 Oct 2005, Linus Torvalds wrote:
> 
> I'm almost goign to suggest that we do our own ctype.h, just to get the 
> sane semantics: we want locale-independence, _and_ we want the right 
> signed behaviour. Plus we only use a very small subset of ctype.h anyway 
> (isspace, isalpha, isdigit and isalnum).

Maybe something like this.

No, I'm not 100% sure we need it. But hey, it's probably less complicated 
than trying to de-localize various different targets.

Is there anything else that is locale-dependent that we use in the C 
toolchain?

		Linus

---
diff-tree f6fea67a590196d81bc4c6a6be1a16dd8bf2815d (from d06b689a933f6d2130f8afdf1ac0ddb83eeb59ab)
Author: Linus Torvalds <torvalds@osdl.org>
Date:   Thu Oct 13 08:36:35 2005 -0700

    Add locale-independent (and stupid) ctype.
    
    It's also safe for signed chars.

diff --git a/Makefile b/Makefile
index 5e7d055..31e62d4 100644
--- a/Makefile
+++ b/Makefile
@@ -158,7 +158,8 @@ LIB_OBJS = \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
-	tag.o tree.o usage.o config.o environment.o $(DIFF_OBJS)
+	tag.o tree.o usage.o config.o environment.o ctype.o \
+	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
 LIBS += -lz
diff --git a/apply.c b/apply.c
index 155fbe8..f4d00f2 100644
--- a/apply.c
+++ b/apply.c
@@ -6,7 +6,6 @@
  * This applies patches on top of some (arbitrary) version of the SCM.
  *
  */
-#include <ctype.h>
 #include <fnmatch.h>
 #include "cache.h"
 
diff --git a/cache.h b/cache.h
index 1a7e047..a465952 100644
--- a/cache.h
+++ b/cache.h
@@ -386,4 +386,30 @@ extern int git_config_bool(const char *,
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
 
+/* Sane ctype - no locale, and works with signed chars */
+#undef isspace
+#undef isdigit
+#undef isalpha
+#undef isalnum
+#undef tolower
+#undef toupper
+extern unsigned char sane_ctype[256];
+#define GIT_SPACE 0x01
+#define GIT_DIGIT 0x02
+#define GIT_ALPHA 0x04
+#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
+#define isspace(x) sane_istest(x,GIT_SPACE)
+#define isdigit(x) sane_istest(x,GIT_DIGIT)
+#define isalpha(x) sane_istest(x,GIT_ALPHA)
+#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define tolower(x) sane_case((unsigned char)(x), 0x20)
+#define toupper(x) sane_case((unsigned char)(x), 0)
+
+static inline int sane_case(int x, int high)
+{
+	if (sane_istest(x, GIT_ALPHA))
+		x = (x & ~0x20) | high;
+	return x;
+}
+
 #endif /* CACHE_H */
diff --git a/commit-tree.c b/commit-tree.c
index 030fb70..ea0fdd4 100644
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -7,7 +7,6 @@
 
 #include <pwd.h>
 #include <time.h>
-#include <ctype.h>
 
 #define BLOCKING (1ul << 14)
 
diff --git a/commit.c b/commit.c
index f735f98..8f40318 100644
--- a/commit.c
+++ b/commit.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include "tag.h"
 #include "commit.h"
 #include "cache.h"
diff --git a/config.c b/config.c
index 9b7c6f2..519fecf 100644
--- a/config.c
+++ b/config.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 
 #include "cache.h"
 
diff --git a/convert-objects.c b/convert-objects.c
index 9ad0c77..a892013 100644
--- a/convert-objects.c
+++ b/convert-objects.c
@@ -1,6 +1,5 @@
 #define _XOPEN_SOURCE /* glibc2 needs this */
 #include <time.h>
-#include <ctype.h>
 #include "cache.h"
 
 struct entry {
diff --git a/ctype.c b/ctype.c
new file mode 100644
index 0000000..56bdffa
--- /dev/null
+++ b/ctype.c
@@ -0,0 +1,23 @@
+/*
+ * Sane locale-independent, ASCII ctype.
+ *
+ * No surprises, and works with signed and unsigned chars.
+ */
+#include "cache.h"
+
+#define SS GIT_SPACE
+#define AA GIT_ALPHA
+#define DD GIT_DIGIT
+
+unsigned char sane_ctype[256] = {
+	 0,  0,  0,  0,  0,  0,  0,  0,  0, SS, SS,  0,  0, SS,  0,  0,		/* 0-15 */
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 16-15 */
+	SS,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 32-15 */
+	DD, DD, DD, DD, DD, DD, DD, DD, DD, DD,  0,  0,  0,  0,  0,  0,		/* 48-15 */
+	 0, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA,		/* 64-15 */
+	AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA,  0,  0,  0,  0,  0,		/* 80-15 */
+	 0, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA,		/* 96-15 */
+	AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA,  0,  0,  0,  0,  0,		/* 112-15 */
+	/* Nothing in the 128.. range */
+};
+
diff --git a/date.c b/date.c
index b21cadc..63f5a09 100644
--- a/date.c
+++ b/date.c
@@ -4,7 +4,6 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 
-#include <ctype.h>
 #include <time.h>
 
 #include "cache.h"
diff --git a/diff-tree.c b/diff-tree.c
index 2203fa5..8517220 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include "cache.h"
 #include "diff.h"
 #include "commit.h"
diff --git a/ident.c b/ident.c
index 7a9f567..1bfbc6f 100644
--- a/ident.c
+++ b/ident.c
@@ -9,7 +9,6 @@
 
 #include <pwd.h>
 #include <time.h>
-#include <ctype.h>
 
 static char git_default_date[50];
 
diff --git a/mailsplit.c b/mailsplit.c
index 0f8100d..189f4ed 100644
--- a/mailsplit.c
+++ b/mailsplit.c
@@ -11,7 +11,6 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <stdio.h>
-#include <ctype.h>
 #include <assert.h>
 #include "cache.h"
 
diff --git a/pack-objects.c b/pack-objects.c
index 3d62278..83ac22b 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include "cache.h"
 #include "object.h"
 #include "delta.h"
diff --git a/patch-id.c b/patch-id.c
index 960e7ce..edbc4aa 100644
--- a/patch-id.c
+++ b/patch-id.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
 #include "cache.h"
 
 static void flush_current_id(int patchlen, unsigned char *id, SHA_CTX *c)
diff --git a/refs.c b/refs.c
index 5a8cbd4..42240d2 100644
--- a/refs.c
+++ b/refs.c
@@ -2,7 +2,6 @@
 #include "cache.h"
 
 #include <errno.h>
-#include <ctype.h>
 
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
diff --git a/update-ref.c b/update-ref.c
index 4a1704c..65dc3d6 100644
--- a/update-ref.c
+++ b/update-ref.c
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "refs.h"
-#include <ctype.h>
 
 static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]";
 

^ permalink raw reply related	[relevance 12%]

* [PATCH 1/3] Keep track of whether a pack is local or not
@ 2005-10-13 21:26 16% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-10-13 21:26 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


If we want to re-pack just local packfiles, we need to know whether a
particular object is local or not.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
diff --git a/cache.h b/cache.h
index 1a7e047..3286582 100644
--- a/cache.h
+++ b/cache.h
@@ -313,6 +313,7 @@ extern struct packed_git {
 	void *pack_base;
 	unsigned int pack_last_used;
 	unsigned int pack_use_cnt;
+	int pack_local;
 	unsigned char sha1[20];
 	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
 } *packed_git;
@@ -352,7 +353,7 @@ extern struct packed_git *find_sha1_pack
 
 extern int use_packed_git(struct packed_git *);
 extern void unuse_packed_git(struct packed_git *);
-extern struct packed_git *add_packed_git(char *, int);
+extern struct packed_git *add_packed_git(char *, int, int);
 extern int num_packed_objects(const struct packed_git *p);
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
 extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
diff --git a/sha1_file.c b/sha1_file.c
index f059004..e456799 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -416,7 +416,7 @@ int use_packed_git(struct packed_git *p)
 	return 0;
 }
 
-struct packed_git *add_packed_git(char *path, int path_len)
+struct packed_git *add_packed_git(char *path, int path_len, int local)
 {
 	struct stat st;
 	struct packed_git *p;
@@ -444,6 +444,7 @@ struct packed_git *add_packed_git(char *
 	p->pack_base = NULL;
 	p->pack_last_used = 0;
 	p->pack_use_cnt = 0;
+	p->pack_local = local;
 	return p;
 }
 
@@ -484,7 +485,7 @@ void install_packed_git(struct packed_gi
 	packed_git = pack;
 }
 
-static void prepare_packed_git_one(char *objdir)
+static void prepare_packed_git_one(char *objdir, int local)
 {
 	char path[PATH_MAX];
 	int len;
@@ -506,7 +507,7 @@ static void prepare_packed_git_one(char 
 
 		/* we have .idx.  Is it a file we can map? */
 		strcpy(path + len, de->d_name);
-		p = add_packed_git(path, len + namelen);
+		p = add_packed_git(path, len + namelen, local);
 		if (!p)
 			continue;
 		p->next = packed_git;
@@ -522,11 +523,11 @@ void prepare_packed_git(void)
 
 	if (run_once)
 		return;
-	prepare_packed_git_one(get_object_directory());
+	prepare_packed_git_one(get_object_directory(), 1);
 	prepare_alt_odb();
 	for (alt = alt_odb_list; alt; alt = alt->next) {
 		alt->name[0] = 0;
-		prepare_packed_git_one(alt->base);
+		prepare_packed_git_one(alt->base, 0);
 	}
 	run_once = 1;
 }
diff --git a/verify-pack.c b/verify-pack.c
index 80b60a6..c99db9d 100644
--- a/verify-pack.c
+++ b/verify-pack.c
@@ -15,12 +15,12 @@ static int verify_one_pack(char *arg, in
 			len--;
 		}
 		/* Should name foo.idx now */
-		if ((g = add_packed_git(arg, len)))
+		if ((g = add_packed_git(arg, len, 1)))
 			break;
 		/* No?  did you name just foo? */
 		strcpy(arg + len, ".idx");
 		len += 4;
-		if ((g = add_packed_git(arg, len)))
+		if ((g = add_packed_git(arg, len, 1)))
 			break;
 		return error("packfile %s not found.", arg);
 	}

^ permalink raw reply related	[relevance 16%]

* [PATCH] Ignore funny refname sent from remote
@ 2005-10-14  6:03 15% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-14  6:03 UTC (permalink / raw)
  To: git

This allows the remote side (most notably, upload-pack) to show
additional information without affecting the downloader.  Peek-remote
does not ignore them -- this is to make it useful for Pasky's
automatic tag following.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * This is a preparation for the next one, which starts sending
   out extra "refs" from upload-pack.  Normal client side should
   not get affected by those extra info.

 cache.h       |    2 +-
 clone-pack.c  |    2 +-
 connect.c     |    8 +++++++-
 fetch-pack.c  |    2 +-
 peek-remote.c |    2 +-
 send-pack.c   |    2 +-
 6 files changed, 12 insertions(+), 6 deletions(-)

applies-to: c0f2aa6e25a9291830ddd86acfc569fd33077ec6
60b2e010ba8dd4c24fe6ef7bfc1ee3185ac2cf52
diff --git a/cache.h b/cache.h
index 3286582..8aa63cc 100644
--- a/cache.h
+++ b/cache.h
@@ -339,7 +339,7 @@ extern int path_match(const char *path, 
 extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
 		      int nr_refspec, char **refspec, int all);
 extern int get_ack(int fd, unsigned char *result_sha1);
-extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);
+extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
 extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
diff --git a/clone-pack.c b/clone-pack.c
index 0ea7e7f..f9b263a 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -287,7 +287,7 @@ static int clone_pack(int fd[2], int nr_
 	struct ref *refs;
 	int status;
 
-	get_remote_heads(fd[0], &refs, nr_match, match);
+	get_remote_heads(fd[0], &refs, nr_match, match, 1);
 	if (!refs) {
 		packet_flush(fd[1]);
 		die("no matching remote head");
diff --git a/connect.c b/connect.c
index b157cf1..b6732f6 100644
--- a/connect.c
+++ b/connect.c
@@ -10,7 +10,8 @@
 /*
  * Read all the refs from the other end
  */
-struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match)
+struct ref **get_remote_heads(int in, struct ref **list,
+			      int nr_match, char **match, int ignore_funny)
 {
 	*list = NULL;
 	for (;;) {
@@ -29,6 +30,11 @@ struct ref **get_remote_heads(int in, st
 		if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
 			die("protocol error: expected sha/ref, got '%s'", buffer);
 		name = buffer + 41;
+
+		if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
+		    check_ref_format(name + 5))
+			continue;
+
 		if (nr_match && !path_match(name, nr_match, match))
 			continue;
 		ref = xcalloc(1, sizeof(*ref) + len - 40);
diff --git a/fetch-pack.c b/fetch-pack.c
index 582f967..953c0cf 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -81,7 +81,7 @@ static int fetch_pack(int fd[2], int nr_
 	int status;
 	pid_t pid;
 
-	get_remote_heads(fd[0], &ref, nr_match, match);
+	get_remote_heads(fd[0], &ref, nr_match, match, 1);
 	if (!ref) {
 		packet_flush(fd[1]);
 		die("no matching remote head");
diff --git a/peek-remote.c b/peek-remote.c
index 4b1d0d5..ee49bf3 100644
--- a/peek-remote.c
+++ b/peek-remote.c
@@ -11,7 +11,7 @@ static int peek_remote(int fd[2])
 {
 	struct ref *ref;
 
-	get_remote_heads(fd[0], &ref, 0, NULL);
+	get_remote_heads(fd[0], &ref, 0, NULL, 0);
 	packet_flush(fd[1]);
 
 	while (ref) {
diff --git a/send-pack.c b/send-pack.c
index 55d8ff7..9f9a6e7 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -181,7 +181,7 @@ static int send_pack(int in, int out, in
 	int new_refs;
 
 	/* No funny business with the matcher */
-	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL);
+	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1);
 	get_local_heads();
 
 	/* match them up */
---
@@GIT_VERSION@@

^ permalink raw reply related	[relevance 15%]

* [PATCH] Allow caching of generated pack for full cloning.
@ 2005-10-22  9:00 10% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-22  9:00 UTC (permalink / raw)
  To: git; +Cc: H Peter Anvin

git-pack-objects can reuse pack files stored in $GIT_DIR/pack-cache
directory, when a necessary pack is found.  This is hopefully useful
when upload-pack (called from git-daemon) is expected to receive
requests for the same set of objects many times (e.g full cloning
request of any project, or updates from the set of heads previous day
to the latest for a slow moving project).

Currently git-pack-objects does *not* keep pack files it creates for
reusing.  It might be useful to implement its --update-cache option,
which would let it store pack files it created in the pack-cache
directory, and prune rarely used ones from it.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

  Right now, this is not very useful except perhaps preparing
  for many clone requests by statically creating and storing a
  full pack in pack-cache directory.  I am expecting that
  enabling the unimplemented --update-cache option of
  git-pack-objects would let the server keep recently generated
  packs, hoping that fetch requests close together would be for
  the same "master" head, relative to the same previous heads
  (multiple people making a habit of pulling every day, or every
  week, or whatever).  These cached packs need to be purged from
  the pack-cache directory quite often.  They would become
  useless once you update a popular ref in the repository.

  Even if this caching would help git-daemon by reusing
  generated packs, I see one potential problem; --update-cache
  option would require the process to be able to write into the
  pack-cache directory, but I expect git-daemon would run as a
  user that does not have any write privilege to the filesystem.

 Makefile       |    2 +
 cache.h        |    1 +
 copy.c         |   37 +++++++++++++++++++++++
 pack-objects.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 upload-pack.c  |   12 ++++++-
 5 files changed, 126 insertions(+), 16 deletions(-)
 create mode 100644 copy.c

applies-to: a0d57ba5b9245eb3a4cc15fb029af51a40eb8136
dd42e422104f43b369929c4f900362d401d2e962
diff --git a/Makefile b/Makefile
index 903c57c..3d8503d 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@ LIB_OBJS = \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
-	tag.o tree.o usage.o config.o environment.o ctype.o \
+	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/cache.h b/cache.h
index d776016..2e36cc5 100644
--- a/cache.h
+++ b/cache.h
@@ -413,4 +413,5 @@ static inline int sane_case(int x, int h
 	return x;
 }
 
+extern int copy_fd(int ifd, int ofd);
 #endif /* CACHE_H */
diff --git a/copy.c b/copy.c
new file mode 100644
index 0000000..2009275
--- /dev/null
+++ b/copy.c
@@ -0,0 +1,37 @@
+#include "cache.h"
+
+int copy_fd(int ifd, int ofd)
+{
+	while (1) {
+		int len;
+		char buffer[8192];
+		char *buf = buffer;
+		len = read(ifd, buffer, sizeof(buffer));
+		if (!len)
+			break;
+		if (len < 0) {
+			if (errno == EAGAIN)
+				continue;
+			return error("copy-fd: read returned %s",
+				     strerror(errno));
+		}
+		while (1) {
+			int written = write(ofd, buf, len);
+			if (written > 0) {
+				buf += written;
+				len -= written;
+				if (!len)
+					break;
+			}
+			if (!written)
+				return error("copy-fd: write returned 0");
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			return error("copy-fd: write returned %s",
+				     strerror(errno));
+		}
+	}
+	close(ifd);
+	return 0;
+}
+
diff --git a/pack-objects.c b/pack-objects.c
index b3e6152..915469e 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -4,7 +4,7 @@
 #include "pack.h"
 #include "csum-file.h"
 
-static const char pack_usage[] = "git-pack-objects [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
+static const char pack_usage[] = "git-pack-objects [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} [--update-cache] < object-list";
 
 struct object_entry {
 	unsigned char sha1[20];
@@ -400,6 +400,71 @@ static void find_deltas(struct object_en
 	free(array);
 }
 
+static void prepare_pack(int window, int depth)
+{
+	get_object_details();
+
+	fprintf(stderr, "Packing %d objects\n", nr_objects);
+
+	sorted_by_type = create_sorted_list(type_size_sort);
+	if (window && depth)
+		find_deltas(sorted_by_type, window+1, depth);
+	write_pack_file();
+}
+
+static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
+{
+	static const char cache[] = "pack-cache/pack-%s.%s";
+	char *cached_pack, *cached_idx;
+	int ifd, ofd, ifd_ix = -1;
+
+	cached_pack = git_path(cache, sha1_to_hex(sha1), "pack");
+	ifd = open(cached_pack, O_RDONLY);
+	if (ifd < 0)
+		return 0;
+
+	if (!pack_to_stdout) {
+		cached_idx = git_path(cache, sha1_to_hex(sha1), "idx");
+		ifd_ix = open(cached_idx, O_RDONLY);
+		if (ifd_ix < 0) {
+			close(ifd);
+			return 0;
+		}
+	}
+
+	fprintf(stderr, "Reusing %d objects pack %s\n", nr_objects,
+		sha1_to_hex(sha1));
+
+	if (pack_to_stdout) {
+		if (copy_fd(ifd, 1))
+			exit(1);
+		close(ifd);
+	}
+	else {
+		char name[PATH_MAX];
+		snprintf(name, sizeof(name),
+			 "%s-%s.%s", base_name, sha1_to_hex(sha1), "pack");
+		ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (ofd < 0)
+			die("unable to open %s (%s)", name, strerror(errno));
+		if (copy_fd(ifd, ofd))
+			exit(1);
+		close(ifd);
+
+		snprintf(name, sizeof(name),
+			 "%s-%s.%s", base_name, sha1_to_hex(sha1), "idx");
+		ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (ofd < 0)
+			die("unable to open %s (%s)", name, strerror(errno));
+		if (copy_fd(ifd_ix, ofd))
+			exit(1);
+		close(ifd_ix);
+		puts(sha1_to_hex(sha1));
+	}
+
+	return 1;
+}
+
 int main(int argc, char **argv)
 {
 	SHA_CTX ctx;
@@ -424,6 +489,10 @@ int main(int argc, char **argv)
 				incremental = 1;
 				continue;
 			}
+			if (!strcmp("--update-cache", arg)) {
+				/* Not implemented */
+				continue;
+			}
 			if (!strncmp("--window=", arg, 9)) {
 				char *end;
 				window = strtoul(arg+9, &end, 0);
@@ -472,9 +541,6 @@ int main(int argc, char **argv)
 	}
 	if (non_empty && !nr_objects)
 		return 0;
-	get_object_details();
-
-	fprintf(stderr, "Packing %d objects\n", nr_objects);
 
 	sorted_by_sha = create_sorted_list(sha1_sort);
 	SHA1_Init(&ctx);
@@ -485,14 +551,14 @@ int main(int argc, char **argv)
 	}
 	SHA1_Final(object_list_sha1, &ctx);
 
-	sorted_by_type = create_sorted_list(type_size_sort);
-	if (window && depth)
-		find_deltas(sorted_by_type, window+1, depth);
-
-	write_pack_file();
-	if (!pack_to_stdout) {
-		write_index_file();
-		puts(sha1_to_hex(object_list_sha1));
+	if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
+		;
+	else {
+		prepare_pack(window, depth);
+		if (!pack_to_stdout) {
+			write_index_file();
+			puts(sha1_to_hex(object_list_sha1));
+		}
 	}
 	return 0;
 }
diff --git a/upload-pack.c b/upload-pack.c
index 8a41caf..6fb8eb7 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -29,6 +29,7 @@ static void create_pack_file(void)
 {
 	int fd[2];
 	pid_t pid;
+	int create_full_pack = (MAX_NEEDS <= nr_needs);
 
 	if (pipe(fd) < 0)
 		die("git-upload-pack: unable to create pipe");
@@ -43,7 +44,7 @@ static void create_pack_file(void)
 		char *buf;
 		char **p;
 
-		if (MAX_NEEDS <= nr_needs)
+		if (create_full_pack)
 			args = nr_has + 10;
 		else
 			args = nr_has + nr_needs + 5;
@@ -57,7 +58,7 @@ static void create_pack_file(void)
 		close(fd[1]);
 		*p++ = "git-rev-list";
 		*p++ = "--objects";
-		if (MAX_NEEDS <= nr_needs)
+		if (create_full_pack)
 			*p++ = "--all";
 		else {
 			for (i = 0; i < nr_needs; i++) {
@@ -79,7 +80,12 @@ static void create_pack_file(void)
 	dup2(fd[0], 0);
 	close(fd[0]);
 	close(fd[1]);
-	execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL);
+	if (create_full_pack)
+		execlp("git-pack-objects", "git-pack-objects",
+		       "--stdout", NULL);
+	else
+		execlp("git-pack-objects", "git-pack-objects",
+		       "--stdout", "--update-cache", NULL);
 	die("git-upload-pack: unable to exec git-pack-objects");
 }
 
---
0.99.8.GIT

^ permalink raw reply related	[relevance 10%]

* Re: daemon.c broken on OpenBSD
  @ 2005-10-24  5:20  7% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-24  5:20 UTC (permalink / raw)
  To: Randal L. Schwartz; +Cc: git

merlyn@stonehenge.com (Randal L. Schwartz) writes:

> Wow.
>...
> If that rings a bell, help me out here.  I'm guessing "isalnum" is getting
> defined (wrongly).  Yeah, looks like in cache.h.  Why is this getting
> defined?

Wow indeed.  It comes from this thread:

	http://marc.theaimsgroup.com/?l=git&m=112917422812418&w=2


Maybe something like this would help?

 ------------
[PATCH] do not override standard ctype macros, but use our own.

...since it can cause breakage in system supplied header files...

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

   It would be easier for *you* to grok if I say this patch is
   essentially this ;-):

	$ git-ls-files |
	xargs perl -i -p -e '
		s/\bis(space|digit|alpha|alnum)\b/is_$1/g;
		s/\bto(lower|upper)\b/to_$1/g;
	'

   except that I did not touch gitk.

diff --git a/apply.c b/apply.c
index e5c0b7d..9608f92 100644
--- a/apply.c
+++ b/apply.c
@@ -113,7 +113,7 @@ static unsigned long linelen(const char 
 
 static int is_dev_null(const char *str)
 {
-	return !memcmp("/dev/null", str, 9) && isspace(str[9]);
+	return !memcmp("/dev/null", str, 9) && is_space(str[9]);
 }
 
 #define TERM_SPACE	1
@@ -167,7 +167,7 @@ static char * find_name(const char *line
 	for (;;) {
 		char c = *line;
 
-		if (isspace(c)) {
+		if (is_space(c)) {
 			if (c == '\n')
 				break;
 			if (name_terminate(start, line-start, c, terminate))
@@ -447,7 +447,7 @@ static char *git_header_name(char *line,
 		/* second points at one past closing dq of name.
 		 * find the second name.
 		 */
-		while ((second < line + llen) && isspace(*second))
+		while ((second < line + llen) && is_space(*second))
 			second++;
 
 		if (line + llen <= second)
@@ -508,7 +508,7 @@ static char *git_header_name(char *line,
 			len = strlen(np);
 			if (len < cp - name &&
 			    !strncmp(np, name, len) &&
-			    isspace(name[len])) {
+			    is_space(name[len])) {
 				/* Good */
 				memmove(sp, np, len + 1);
 				return sp;
@@ -615,7 +615,7 @@ static int parse_num(const char *line, u
 {
 	char *ptr;
 
-	if (!isdigit(*line))
+	if (!is_digit(*line))
 		return 0;
 	*p = strtoul(line, &ptr, 10);
 	return ptr - line;
diff --git a/cache.h b/cache.h
index d776016..3f6ff0d 100644
--- a/cache.h
+++ b/cache.h
@@ -388,23 +388,17 @@ extern char git_default_email[MAX_GITNAM
 extern char git_default_name[MAX_GITNAME];
 
 /* Sane ctype - no locale, and works with signed chars */
-#undef isspace
-#undef isdigit
-#undef isalpha
-#undef isalnum
-#undef tolower
-#undef toupper
 extern unsigned char sane_ctype[256];
 #define GIT_SPACE 0x01
 #define GIT_DIGIT 0x02
 #define GIT_ALPHA 0x04
 #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
-#define isspace(x) sane_istest(x,GIT_SPACE)
-#define isdigit(x) sane_istest(x,GIT_DIGIT)
-#define isalpha(x) sane_istest(x,GIT_ALPHA)
-#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
-#define tolower(x) sane_case((unsigned char)(x), 0x20)
-#define toupper(x) sane_case((unsigned char)(x), 0)
+#define is_space(x) sane_istest(x,GIT_SPACE)
+#define is_digit(x) sane_istest(x,GIT_DIGIT)
+#define is_alpha(x) sane_istest(x,GIT_ALPHA)
+#define is_alnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define to_lower(x) sane_case((unsigned char)(x), 0x20)
+#define to_upper(x) sane_case((unsigned char)(x), 0)
 
 static inline int sane_case(int x, int high)
 {
diff --git a/commit.c b/commit.c
index 8f40318..4d094b5 100644
--- a/commit.c
+++ b/commit.c
@@ -379,7 +379,7 @@ static int add_user_info(const char *wha
 
 static int is_empty_line(const char *line, int len)
 {
-	while (len && isspace(line[len-1]))
+	while (len && is_space(line[len-1]))
 		len--;
 	return !len;
 }
diff --git a/compat/strcasestr.c b/compat/strcasestr.c
index b96414d..d1a4253 100644
--- a/compat/strcasestr.c
+++ b/compat/strcasestr.c
@@ -12,7 +12,7 @@ char *gitstrcasestr(const char *haystack
 		for (j = 0; j < nlen; j++) {
 			unsigned char c1 = haystack[i+j];
 			unsigned char c2 = needle[j];
-			if (toupper(c1) != toupper(c2))
+			if (to_upper(c1) != to_upper(c2))
 				goto next;
 		}
 		return (char *) haystack + i;
diff --git a/config.c b/config.c
index 519fecf..24b017f 100644
--- a/config.c
+++ b/config.c
@@ -40,7 +40,7 @@ static char *parse_value(void)
 		}
 		if (comment)
 			continue;
-		if (isspace(c) && !quote) {
+		if (is_space(c) && !quote) {
 			space = 1;
 			continue;
 		}
@@ -97,9 +97,9 @@ static int get_value(config_fn_t fn, cha
 		c = get_next_char();
 		if (c == EOF)
 			break;
-		if (!isalnum(c))
+		if (!is_alnum(c))
 			break;
-		name[len++] = tolower(c);
+		name[len++] = to_lower(c);
 		if (len >= MAXNAME)
 			return -1;
 	}
@@ -128,11 +128,11 @@ static int get_base_var(char *name)
 			return -1;
 		if (c == ']')
 			return baselen;
-		if (!isalnum(c))
+		if (!is_alnum(c))
 			return -1;
 		if (baselen > MAXNAME / 2)
 			return -1;
-		name[baselen++] = tolower(c);
+		name[baselen++] = to_lower(c);
 	}
 }
 
@@ -151,7 +151,7 @@ static int git_parse_file(config_fn_t fn
 			comment = 0;
 			continue;
 		}
-		if (comment || isspace(c))
+		if (comment || is_space(c))
 			continue;
 		if (c == '#' || c == ';') {
 			comment = 1;
@@ -165,9 +165,9 @@ static int git_parse_file(config_fn_t fn
 			var[baselen] = 0;
 			continue;
 		}
-		if (!isalpha(c))
+		if (!is_alpha(c))
 			break;
-		var[baselen] = tolower(c);
+		var[baselen] = to_lower(c);
 		if (get_value(fn, var, baselen+1) < 0)
 			break;
 	}
diff --git a/convert-objects.c b/convert-objects.c
index a892013..621c1bb 100644
--- a/convert-objects.c
+++ b/convert-objects.c
@@ -166,7 +166,7 @@ static unsigned long parse_oldstyle_date
 	const char **fmt = formats;
 
 	p = buffer;
-	while (isspace(c = *buf))
+	while (is_space(c = *buf))
 		buf++;
 	while ((c = *buf++) != '\n')
 		*p++ = c;
@@ -181,7 +181,7 @@ static unsigned long parse_oldstyle_date
 			buf = next;
 		} else {
 			const char **p = timezones;
-			while (isspace(*buf))
+			while (is_space(*buf))
 				buf++;
 			while (*p) {
 				if (!memcmp(buf, *p, strlen(*p))) {
@@ -217,7 +217,7 @@ static int convert_date_line(char *dst, 
 	dst += len;
 
 	/* Is it already in new format? */
-	if (isdigit(*date)) {
+	if (is_digit(*date)) {
 		int datelen = next - date;
 		memcpy(dst, date, datelen);
 		return len + datelen;
diff --git a/date.c b/date.c
index 63f5a09..340052d 100644
--- a/date.c
+++ b/date.c
@@ -131,9 +131,9 @@ static int match_string(const char *date
 	for (i = 0; *date; date++, str++, i++) {
 		if (*date == *str)
 			continue;
-		if (toupper(*date) == toupper(*str))
+		if (to_upper(*date) == to_upper(*str))
 			continue;
-		if (!isalnum(*date))
+		if (!is_alnum(*date))
 			break;
 		return 0;
 	}
@@ -145,7 +145,7 @@ static int skip_alpha(const char *date)
 	int i = 0;
 	do {
 		i++;
-	} while (isalpha(date[i]));
+	} while (is_alpha(date[i]));
 	return i;
 }
 
@@ -229,7 +229,7 @@ static int match_multi_number(unsigned l
 
 	num2 = strtol(end+1, &end, 10);
 	num3 = -1;
-	if (*end == c && isdigit(end[1]))
+	if (*end == c && is_digit(end[1]))
 		num3 = strtol(end+1, &end, 10);
 
 	/* Time? Date? */
@@ -295,7 +295,7 @@ static int match_digit(const char *date,
 	case ':':
 	case '/':
 	case '-':
-		if (isdigit(end[1])) {
+		if (is_digit(end[1])) {
 			int match = match_multi_number(num, *end, date, end, tm);
 			if (match)
 				return match;
@@ -310,7 +310,7 @@ static int match_digit(const char *date,
 	n = 0;
 	do {
 		n++;
-	} while (isdigit(date[n]));
+	} while (is_digit(date[n]));
 
 	/* Four-digit year or a timezone? */
 	if (n == 4) {
@@ -420,11 +420,11 @@ int parse_date(const char *date, char *r
 		if (!c || c == '\n')
 			break;
 
-		if (isalpha(c))
+		if (is_alpha(c))
 			match = match_alpha(date, &tm, &offset);
-		else if (isdigit(c))
+		else if (is_digit(c))
 			match = match_digit(date, &tm, &offset, &tm_gmt);
-		else if ((c == '-' || c == '+') && isdigit(date[1]))
+		else if ((c == '-' || c == '+') && is_digit(date[1]))
 			match = match_tz(date, &offset);
 
 		if (!match) {
diff --git a/diff-tree.c b/diff-tree.c
index 382011a..f7b16eb 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -137,7 +137,7 @@ static int diff_tree_stdin(char *line)
 	line[len-1] = 0;
 	if (get_sha1_hex(line, commit))
 		return -1;
-	if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
+	if (is_space(line[40]) && !get_sha1_hex(line+41, parent)) {
 		line[40] = 0;
 		line[81] = 0;
 		sprintf(this_header, "%s (from %s)\n", line, line+41);
diff --git a/ident.c b/ident.c
index bc89e1d..0a3d735 100644
--- a/ident.c
+++ b/ident.c
@@ -34,7 +34,7 @@ static void copy_gecos(struct passwd *w,
 		}
 		if (len + nlen < sz) {
 			/* Sorry, Mr. McDonald... */
-			*dst++ = toupper(*w->pw_name);
+			*dst++ = to_upper(*w->pw_name);
 			memcpy(dst, w->pw_name + 1, nlen - 1);
 			dst += nlen - 1;
 		}
diff --git a/mailinfo.c b/mailinfo.c
index cb853df..3a06240 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -6,9 +6,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <iconv.h>
 
+#include "cache.h"
+
 #ifdef NO_STRCASESTR
 extern char *gitstrcasestr(const char *haystack, const char *needle);
 #endif
@@ -61,7 +62,7 @@ static int handle_from(char *line)
 	 */
 	while (at > line) {
 		char c = at[-1];
-		if (isspace(c))
+		if (is_space(c))
 			break;
 		if (c == '<') {
 			at[-1] = ' ';
@@ -72,7 +73,7 @@ static int handle_from(char *line)
 	dst = email;
 	for (;;) {
 		unsigned char c = *at;
-		if (!c || c == '>' || isspace(c)) {
+		if (!c || c == '>' || is_space(c)) {
 			if (c == '>')
 				*at = ' ';
 			break;
@@ -90,7 +91,7 @@ static int handle_from(char *line)
 	at = line + strlen(line);
 	while (at > line) {
 		unsigned char c = *--at;
-		if (!isspace(c)) {
+		if (!is_space(c)) {
 			at[(c == ')') ? 0 : 1] = 0;
 			break;
 		}
@@ -99,7 +100,7 @@ static int handle_from(char *line)
 	at = line;
 	for (;;) {
 		unsigned char c = *at;
-		if (!c || !isspace(c)) {
+		if (!c || !is_space(c)) {
 			if (c == '(')
 				at++;
 			break;
@@ -164,7 +165,7 @@ static int handle_subcontent_type(char *
 	if (*charset) {
 		int i, c;
 		for (i = 0; (c = charset[i]) != 0; i++)
-			charset[i] = tolower(c);
+			charset[i] = to_lower(c);
 	}
 	return 0;
 }
@@ -199,7 +200,7 @@ static int is_multipart_boundary(const c
 static int eatspace(char *line)
 {
 	int len = strlen(line);
-	while (len > 0 && isspace(line[len-1]))
+	while (len > 0 && is_space(line[len-1]))
 		line[--len] = 0;
 	return len;
 }
@@ -211,27 +212,27 @@ static int eatspace(char *line)
 /* First lines of body can have From:, Date:, and Subject: */
 static int handle_inbody_header(int *seen, char *line)
 {
-	if (!memcmp("From:", line, 5) && isspace(line[5])) {
+	if (!memcmp("From:", line, 5) && is_space(line[5])) {
 		if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
 			*seen |= SEEN_FROM;
 			return 1;
 		}
 	}
-	if (!memcmp("Date:", line, 5) && isspace(line[5])) {
+	if (!memcmp("Date:", line, 5) && is_space(line[5])) {
 		if (!(*seen & SEEN_DATE)) {
 			handle_date(line+6);
 			*seen |= SEEN_DATE;
 			return 1;
 		}
 	}
-	if (!memcmp("Subject:", line, 8) && isspace(line[8])) {
+	if (!memcmp("Subject:", line, 8) && is_space(line[8])) {
 		if (!(*seen & SEEN_SUBJECT)) {
 			handle_subject(line+9);
 			*seen |= SEEN_SUBJECT;
 			return 1;
 		}
 	}
-	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+	if (!memcmp("[PATCH]", line, 7) && is_space(line[7])) {
 		if (!(*seen & SEEN_SUBJECT)) {
 			handle_subject(line);
 			*seen |= SEEN_SUBJECT;
@@ -282,10 +283,10 @@ static void cleanup_space(char *buf)
 	unsigned char c;
 	while ((c = *buf) != 0) {
 		buf++;
-		if (isspace(c)) {
+		if (is_space(c)) {
 			buf[-1] = ' ';
 			c = *buf;
-			while (isspace(c)) {
+			while (is_space(c)) {
 				int len = strlen(buf);
 				memmove(buf, buf+1, len);
 				c = *buf;
@@ -312,7 +313,7 @@ static void check_header(char *line, int
 	for (i = 0; header[i].name; i++) {
 		int len = header[i].namelen;
 		if (!strncasecmp(line, header[i].name, len) &&
-		    line[len] == ':' && isspace(line[len + 1])) {
+		    line[len] == ':' && is_space(line[len + 1])) {
 			header[i].func(line + len + 2);
 			break;
 		}
@@ -491,7 +492,7 @@ static void decode_header_bq(char *it)
 		if (!cp)
 			return; /* no munging */
 		for (sp = ep; sp < cp; sp++)
-			charset_q[sp - ep] = tolower(*sp);
+			charset_q[sp - ep] = to_lower(*sp);
 		charset_q[cp - ep] = 0;
 		encoding = cp[1];
 		if (!encoding || cp[2] != '?')
@@ -499,7 +500,7 @@ static void decode_header_bq(char *it)
 		ep = strstr(cp + 3, "?=");
 		if (!ep)
 			return; /* no munging */
-		switch (tolower(encoding)) {
+		switch (to_lower(encoding)) {
 		default:
 			return; /* no munging */
 		case 'b':
@@ -709,11 +710,6 @@ static void handle_body(void)
 static const char mailinfo_usage[] =
 	"git-mailinfo [-k] [-u] msg patch <mail >info";
 
-static void usage(void) {
-	fprintf(stderr, "%s\n", mailinfo_usage);
-	exit(1);
-}
-
 int main(int argc, char **argv)
 {
 	while (1 < argc && argv[1][0] == '-') {
@@ -722,12 +718,12 @@ int main(int argc, char **argv)
 		else if (!strcmp(argv[1], "-u"))
 			metainfo_utf8 = 1;
 		else
-			usage();
+			usage(mailinfo_usage);
 		argc--; argv++;
 	}
 
 	if (argc != 3)
-		usage();
+		usage(mailinfo_usage);
 	cmitmsg = fopen(argv[1], "w");
 	if (!cmitmsg) {
 		perror(argv[1]);
diff --git a/mailsplit.c b/mailsplit.c
index 189f4ed..de9fb2b 100644
--- a/mailsplit.c
+++ b/mailsplit.c
@@ -33,11 +33,11 @@ static int is_from_line(const char *line
 			break;
 	}
 
-	if (!isdigit(colon[-4]) ||
-	    !isdigit(colon[-2]) ||
-	    !isdigit(colon[-1]) ||
-	    !isdigit(colon[ 1]) ||
-	    !isdigit(colon[ 2]))
+	if (!is_digit(colon[-4]) ||
+	    !is_digit(colon[-2]) ||
+	    !is_digit(colon[-1]) ||
+	    !is_digit(colon[ 1]) ||
+	    !is_digit(colon[ 2]))
 		return 0;
 
 	/* year */
diff --git a/pack-objects.c b/pack-objects.c
index b3e6152..314616d 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -464,7 +464,7 @@ int main(int argc, char **argv)
 		p = line+40;
 		while (*p) {
 			unsigned char c = *p++;
-			if (isspace(c))
+			if (is_space(c))
 				continue;
 			hash = hash * 11 + c;
 		}
diff --git a/patch-id.c b/patch-id.c
index edbc4aa..ba09d2a 100644
--- a/patch-id.c
+++ b/patch-id.c
@@ -21,7 +21,7 @@ static int remove_space(char *line)
 	unsigned char c;
 
 	while ((c = *src++) != '\0') {
-		if (!isspace(c))
+		if (!is_space(c))
 			*dst++ = c;
 	}
 	return dst - line;
diff --git a/refs.c b/refs.c
index 97506a4..4d202ee 100644
--- a/refs.c
+++ b/refs.c
@@ -43,7 +43,7 @@ int validate_symref(const char *path)
 		return -1;
 	buf = buffer + 4;
 	len -= 4;
-	while (len && isspace(*buf))
+	while (len && is_space(*buf))
 		buf++, len--;
 	if (len >= 5 && !memcmp("refs/", buf, 5))
 		return 0;
@@ -103,9 +103,9 @@ const char *resolve_ref(const char *path
 			break;
 		buf = buffer + 4;
 		len -= 4;
-		while (len && isspace(*buf))
+		while (len && is_space(*buf))
 			buf++, len--;
-		while (len && isspace(buf[len-1]))
+		while (len && is_space(buf[len-1]))
 			buf[--len] = 0;
 		path = git_path("%.*s", len, buf);
 	}
diff --git a/stripspace.c b/stripspace.c
index 96cd0a8..a6204b6 100644
--- a/stripspace.c
+++ b/stripspace.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <string.h>
-#include <ctype.h>
+#include "cache.h"
 
 /*
  * Remove empty lines from the beginning and end.
@@ -15,7 +15,7 @@ static void cleanup(char *line)
 	if (len > 1 && line[len-1] == '\n') {
 		do {
 			unsigned char c = line[len-2];
-			if (!isspace(c))
+			if (!is_space(c))
 				break;
 			line[len-2] = '\n';
 			len--;

^ permalink raw reply related	[relevance 7%]

* [PATCH] git_progname (was: Re: User-relative paths)
  @ 2005-10-25  9:11 18%       ` Andreas Ericsson
  0 siblings, 0 replies; 200+ results
From: Andreas Ericsson @ 2005-10-25  9:11 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 3137 bytes --]

Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
> 
> 
>>Junio C Hamano wrote:
>>
>>>Andreas Ericsson <ae@op5.se> writes:
>>>...
>>>At one point, Linus posted an outline of "restricted login shell
>>>for use with git over ssh".  I think you could start from there,
>>>perhaps extend it so that it checks the binaries *and* pathnames
>>>the user can specify (e.g. only under your own $HOME is allowed,
>>>and no /../ in them, or something silly like that).
>>>
>>
>>I found this in the archives:
>>http://article.gmane.org/gmane.comp.version-control.git/5784/match=restricted+login
>>
>>Is that what you're referring to?
> 
> 
> No, it is this one:
> 
>     http://marc.theaimsgroup.com/?l=git&m=112681457828137&w=2
> 
> But it is orthogonal to what you are doing in this patch.
> 
> 
>>Let me know if you want things done differently.
> 
> 
> I think srvside_chdir() should not do the userdir expansion
> under --strict (otherwise you would need a matching change in
> daemon.c as well, but I would rather not).
> 

True. I'll rework it.

> The --strict flag in upload-pack is to make sure git-daemon can
> see what is being accessed and make its policy decision even
> before it calls upload-pack.  In a pathological case, somebody
> can create a directory "/~foo/bar/.git", where the "/~foo"
> directory is different from "/home/foo", and have git-daemon
> check that the former is OK and call your upload-pack.  Your
> upload-pack uses srvside_chdir() and exposes /home/foo/bar/.git;


It shouldn't, because srvside_chdir() will only user-expand paths that 
start with a tilde.


> this circumvents git-daemon's policy decision, doesn't it?
> 
> I also agree with everything Pasky already said.
> 
>  * In a URL, a colon after hostname means "port number
>    follows".  So it was a good intention to make these
>    consistent:
> 
>         git fetch ssh://kernel.org:git
>         git fetch kernel.org:git
> 
>    it should not be done.  IOW, if I wanted to use the former
>    form (which I do not think I'd use myself), I should say either one
>    of:
> 
>         git fetch ssh://kernel.org:~/git
>         git fetch ssh://kernel.org:~junio/git
> 
>    Oh, I just noticed you do not handle the former, because you
>    did not have to, but now you need to.
> 
>  * Use of "extern const char *__progname" is questionable.  I
>    could be easily talked into:
> 
>     - have "extern const char *git_program_name" in cache.h or
>       somewhere;
> 
>     - convert programs (gradually) to set that at the beginning
>       of main();
> 

See the attached patch, which adds git_progname as a global variable to 
daemon.c with a minimum of fuzz. The one-liner below will add it to the 
rest of the programs. GNU sed >= 4.0.9 required.

grep -l "int main" *.c | xargs -- sed -i '/^#include/i#include "main.h"'

>     - update die() and error() to use that variable when
>       reporting (both callers and implementation) -- this is
>       optional.
> 
> 

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

[-- Attachment #2: git_progname.diff --]
[-- Type: text/plain, Size: 1666 bytes --]

diff --git a/Makefile b/Makefile
index 5b0306d..f8e4511 100644
--- a/Makefile
+++ b/Makefile
@@ -147,7 +147,7 @@ LIB_FILE=libgit.a
 LIB_H = \
 	blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
 	diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
-	run-command.h strbuf.h tag.h tree.h
+	run-command.h strbuf.h tag.h tree.h main.h
 
 DIFF_OBJS = \
 	diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
diff --git a/cache.h b/cache.h
index d776016..db5d667 100644
--- a/cache.h
+++ b/cache.h
@@ -45,6 +45,13 @@
 #endif
 #endif
 
+#if defined(__GLIBC__)
+extern const char *__progname;
+#define git_progname __progname
+#else
+extern const char *git_progname;
+#endif
+
 /*
  * Intensive research over the course of many years has shown that
  * port 9418 is totally unused by anything else. Or
diff --git a/daemon.c b/daemon.c
index 0c6182f..c197ee5 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,3 +1,4 @@
+#include "main.h"
 #include "cache.h"
 #include "pkt-line.h"
 #include <signal.h>
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..472f134
--- /dev/null
+++ b/main.h
@@ -0,0 +1,22 @@
+/* unistd.h must be available and the glibc version includes features.h
+ * from it which #defines __GLIBC__ and friends */
+#include <unistd.h>
+#ifndef __GLIBC__
+const char *git_progname;
+static int git_main(int, char **);
+
+int main(int argc, char **argv)
+{
+	char *p;
+	git_progname = p = *argv;
+
+	/* don't use any library functions. We won't have the headers */
+	while(*p)
+		if(*p++ == '/')
+			git_progname = p;
+
+	return git_main(argc, argv);
+}
+
+#define main(argc, argv) git_main(argc, argv)
+#endif /* __GLIBC__ */

^ permalink raw reply related	[relevance 18%]

* Re: [PATCH 1/4] git-init-db should error out with a message
  @ 2005-10-26 19:45 16% ` Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2005-10-26 19:45 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, junkio

Johannes Schindelin, Wed, Oct 26, 2005 01:39:24 +0200:
> When the HEAD symref could not be created, it is helpful for the user to 
> know that.
> 

Not just that. It would be interesting to give the user an option to
use the file references ("ref: refs/heads/master").
Something like that:

Add --no-symref (make init-db use file references)

---

 cache.h   |    1 +
 init-db.c |   11 +++++++++--
 refs.c    |    7 ++++++-
 3 files changed, 16 insertions(+), 3 deletions(-)

applies-to: dba443573167bb9b0023613428e6d1a69477fac6
097ca1bf9b21d19d425e8151986eb36f82cbeff3
diff --git a/cache.h b/cache.h
index d776016..e410ce2 100644
--- a/cache.h
+++ b/cache.h
@@ -239,6 +239,7 @@ extern char *sha1_to_hex(const unsigned 
 extern int read_ref(const char *filename, unsigned char *sha1);
 extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
 extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
+extern int create_file_symref(const char *git_HEAD, const char *refs_heads_master);
 extern int validate_symref(const char *git_HEAD);
 
 /* General helper functions */
diff --git a/init-db.c b/init-db.c
index aabc09f..2d2b705 100644
--- a/init-db.c
+++ b/init-db.c
@@ -161,6 +161,8 @@ static void copy_templates(const char *g
 	closedir(dir);
 }
 
+static int try_symref = 1;
+
 static void create_default_files(const char *git_dir,
 				 char *template_path)
 {
@@ -191,8 +193,11 @@ static void create_default_files(const c
 	 */
 	strcpy(path + len, "HEAD");
 	if (read_ref(path, sha1) < 0) {
-		if (create_symref(path, "refs/heads/master") < 0)
-			exit(1);
+		int err = 0;
+		if ( try_symref )
+			err = create_symref(path, "refs/heads/master");
+		if ( !err && create_file_symref(path, "refs/heads/master") < 0 )
+			die("cannot create %s", path);
 	}
 	path[len] = 0;
 	copy_templates(path, len, template_path);
@@ -220,6 +225,8 @@ int main(int argc, char **argv)
 			break;
 		else if (!strncmp(arg, "--template=", 11))
 			template_dir = arg+11;
+		else if (!strcmp(arg, "--no-symref"))
+			try_symref = 0;
 		else
 			die(init_db_usage);
 	}
diff --git a/refs.c b/refs.c
index 97506a4..8029667 100644
--- a/refs.c
+++ b/refs.c
@@ -120,6 +120,12 @@ int create_symref(const char *git_HEAD, 
 	unlink(git_HEAD);
 	return symlink(refs_heads_master, git_HEAD);
 #else
+	return create_file_symref(git_HEAD, refs_heads_master);
+#endif
+}
+
+int create_file_symref(const char *git_HEAD, const char *refs_heads_master)
+{
 	const char *lockpath;
 	char ref[1000];
 	int fd, len, written;
@@ -144,7 +150,6 @@ int create_symref(const char *git_HEAD, 
 		return -3;
 	}
 	return 0;
-#endif
 }
 
 int read_ref(const char *filename, unsigned char *sha1)
---
0.99.8.GIT

^ permalink raw reply related	[relevance 16%]

* Re: [RFC] multi_ack protocol v2
  @ 2005-10-27 17:45 12%       ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-27 17:45 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Sergey Vlasov, git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> On Thu, 27 Oct 2005, Sergey Vlasov wrote:
>
>> Actually, there is another way to pass some data from the server
>> which would be ignored by older clients - at the first stage,
>> when upload-pack sends the list of refs to the client:
>> 
>> 	packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, '\0',
>> 		     server_capabilities);
>
> That exploits that packet_write() uses vnsprintf() to find out the length,
> not strlen(). Sweet.

OK.

> get_remote_heads() would need to store the server_capabilities, maybe with 
> a function "server_supports(const char *extension_string)" 

Another thing that would probably be helpful is to redo
get_remote_heads() slightly differently, so that it can return
information on *all* refs the other end has.  We need to extend
"struct ref" to mark which one was actually matched/ignored by
path_match() and ignore_funny.  An completely untested patch is
attached, based on fetch-pack that still runs rev-list as an
external process, to outline the idea.

---
diff --git a/cache.h b/cache.h
index 2e36cc5..d39a006 100644
--- a/cache.h
+++ b/cache.h
@@ -329,6 +329,7 @@ struct ref {
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
 	unsigned char force;
+	unsigned char matched; /* when using REPORT_ALL */
 	struct ref *peer_ref; /* when renaming */
 	char name[0];
 };
@@ -339,7 +340,9 @@ extern int path_match(const char *path, 
 extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
 		      int nr_refspec, char **refspec, int all);
 extern int get_ack(int fd, unsigned char *result_sha1);
-extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny);
+#define GET_REMOTE_HEADS_IGNORE_FUNNY	1
+#define GET_REMOTE_HEADS_REPORT_ALL	2
+extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int match_options);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
 extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
diff --git a/clone-pack.c b/clone-pack.c
index 9609219..8b63183 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -250,7 +250,7 @@ static int clone_pack(int fd[2], int nr_
 	struct ref *refs;
 	int status;
 
-	get_remote_heads(fd[0], &refs, nr_match, match, 1);
+	get_remote_heads(fd[0], &refs, nr_match, match, GET_REMOTE_HEADS_IGNORE_FUNNY);
 	if (!refs) {
 		packet_flush(fd[1]);
 		die("no matching remote head");
diff --git a/connect.c b/connect.c
index b171c5d..f7a3550 100644
--- a/connect.c
+++ b/connect.c
@@ -12,8 +12,11 @@
  * Read all the refs from the other end
  */
 struct ref **get_remote_heads(int in, struct ref **list,
-			      int nr_match, char **match, int ignore_funny)
+			      int nr_match, char **match, int match_options)
 {
+	int ignore_funny = match_options & GET_REMOTE_HEADS_IGNORE_FUNNY;
+	int report_all = match_options & GET_REMOTE_HEADS_REPORT_ALL;
+
 	*list = NULL;
 	for (;;) {
 		struct ref *ref;
@@ -21,6 +24,7 @@ struct ref **get_remote_heads(int in, st
 		static char buffer[1000];
 		char *name;
 		int len;
+		int matched = 1;
 
 		len = packet_read_line(in, buffer, sizeof(buffer));
 		if (!len)
@@ -28,17 +32,22 @@ struct ref **get_remote_heads(int in, st
 		if (buffer[len-1] == '\n')
 			buffer[--len] = 0;
 
-		if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
-			die("protocol error: expected sha/ref, got '%s'", buffer);
+		if (len < 42 || get_sha1_hex(buffer, old_sha1) ||
+		    buffer[40] != ' ')
+			die("protocol error: expected sha/ref, got '%s'",
+			    buffer);
 		name = buffer + 41;
 
-		if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
-		    check_ref_format(name + 5))
-			continue;
+		if ((ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
+		     check_ref_format(name + 5)) ||
+		    (nr_match && !path_match(name, nr_match, match))) {
+			if (!report_all)
+				continue;
+			matched = 0;
+		}
 
-		if (nr_match && !path_match(name, nr_match, match))
-			continue;
 		ref = xcalloc(1, sizeof(*ref) + len - 40);
+		ref->matched = matched;
 		memcpy(ref->old_sha1, old_sha1, 20);
 		memcpy(ref->name, buffer + 41, len - 40);
 		*list = ref;
diff --git a/fetch-pack.c b/fetch-pack.c
index 8566ab1..11fb1c1 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -13,6 +13,7 @@ static const char fetch_pack_usage[] =
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE	(1U << 0)
+#define EXCLUDE		(1U << 1)
 
 static int find_common(int fd[2], unsigned char *result_sha1,
 		       struct ref *refs)
@@ -52,17 +53,24 @@ static int find_common(int fd[2], unsign
 			p = commit->parents;
 			while (p &&
 			       rev_command_len + 44 < sizeof(rev_command)) {
-				snprintf(rev_command + rev_command_len, 44,
-					 " ^%s",
-					 sha1_to_hex(p->item->object.sha1));
-				rev_command_len += 43;
+				struct object *pobj = &(p->item->object);
+				if (!pobj->flags & EXCLUDE) {
+					snprintf(rev_command +
+						 rev_command_len, 44,
+						 " ^%s",
+						 sha1_to_hex(pobj->sha1));
+					rev_command_len += 43;
+				}
+				pobj->flags |= EXCLUDE;
 				p = p->next;
 			}
 			continue;
 		}
 	repair:
-		packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
-		fetching++;
+		if (refs->matched) {
+			packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
+			fetching = 1;
+		}
 	}
 	packet_flush(fd[1]);
 	if (!fetching)
@@ -183,6 +191,8 @@ static int everything_local(struct ref *
 		unsigned char local[20];
 		struct object *o;
 
+		if (!refs->matched)
+			continue;
 		o = parse_object(remote);
 		if (!o || !(o->flags & COMPLETE)) {
 			retval = 0;
@@ -204,6 +214,16 @@ static int everything_local(struct ref *
 	return retval;
 }
 
+static int no_matching_remote(struct ref *ref)
+{
+	while (ref)
+		if (ref->matched)
+			return 0;
+		else
+			ref = ref->next;
+	return 1;
+}
+
 static int fetch_pack(int fd[2], int nr_match, char **match)
 {
 	struct ref *ref;
@@ -211,8 +231,10 @@ static int fetch_pack(int fd[2], int nr_
 	int status;
 	pid_t pid;
 
-	get_remote_heads(fd[0], &ref, nr_match, match, 1);
-	if (!ref) {
+	get_remote_heads(fd[0], &ref, nr_match, match,
+			 GET_REMOTE_HEADS_IGNORE_FUNNY |
+			 GET_REMOTE_HEADS_REPORT_ALL);
+	if (no_matching_remote(ref)) {
 		packet_flush(fd[1]);
 		die("no matching remote head");
 	}
@@ -245,8 +267,9 @@ static int fetch_pack(int fd[2], int nr_
 			die("git-unpack-objects died with error code %d", code);
 all_done:
 		while (ref) {
-			printf("%s %s\n",
-			       sha1_to_hex(ref->old_sha1), ref->name);
+			if (ref->matched)
+				printf("%s %s\n",
+				       sha1_to_hex(ref->old_sha1), ref->name);
 			ref = ref->next;
 		}
 		return 0;
diff --git a/send-pack.c b/send-pack.c
index 9f9a6e7..d7bb6c1 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -181,7 +181,8 @@ static int send_pack(int in, int out, in
 	int new_refs;
 
 	/* No funny business with the matcher */
-	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1);
+	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL,
+				       GET_REMOTE_HEADS_IGNORE_FUNNY);
 	get_local_heads();
 
 	/* match them up */

^ permalink raw reply related	[relevance 12%]

* [PATCH 6/8] Support receiving server capabilities
@ 2005-10-28  2:48 17% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-10-28  2:48 UTC (permalink / raw)
  To: git, junkio


On Thu, 27 Oct 2005, Sergey Vlasov wrote:

> Actually, there is another way to pass some data from the server
> which would be ignored by older clients - at the first stage,
> when upload-pack sends the list of refs to the client:
>
>       packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, '\0',
>                    server_capabilities);

This patch implements the client side of it. server_capabilities is supposed
to be a string containing space separated features of the server.

After get_remote_heads(), check if the server supports the feature like

	if (server_supports("multi_ack"))
		do_something();

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 cache.h   |    1 +
 connect.c |   16 +++++++++++++++-
 2 files changed, 16 insertions(+), 1 deletions(-)

applies-to: 755b5d7a6bb3861a284381a8adb26c2241217355
883ea2e2bf664c78a7bee5b29ad9584339085310
diff --git a/cache.h b/cache.h
index 2e36cc5..677c6ac 100644
--- a/cache.h
+++ b/cache.h
@@ -340,6 +340,7 @@ extern int match_refs(struct ref *src, s
 		      int nr_refspec, char **refspec, int all);
 extern int get_ack(int fd, unsigned char *result_sha1);
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny);
+extern int server_supports(const char *feature);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
 extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
diff --git a/connect.c b/connect.c
index b171c5d..5cc49f9 100644
--- a/connect.c
+++ b/connect.c
@@ -8,6 +8,8 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+static char *server_capabilities = "";
+
 /*
  * Read all the refs from the other end
  */
@@ -20,7 +22,7 @@ struct ref **get_remote_heads(int in, st
 		unsigned char old_sha1[20];
 		static char buffer[1000];
 		char *name;
-		int len;
+		int len, name_len;
 
 		len = packet_read_line(in, buffer, sizeof(buffer));
 		if (!len)
@@ -36,6 +38,13 @@ struct ref **get_remote_heads(int in, st
 		    check_ref_format(name + 5))
 			continue;
 
+		name_len = strlen(name);
+		if (len != name_len + 41) {
+			if (server_capabilities)
+				free(server_capabilities);
+			server_capabilities = strdup(name + name_len + 1);
+		}
+
 		if (nr_match && !path_match(name, nr_match, match))
 			continue;
 		ref = xcalloc(1, sizeof(*ref) + len - 40);
@@ -47,6 +56,11 @@ struct ref **get_remote_heads(int in, st
 	return list;
 }
 
+int server_supports(const char *feature)
+{
+	return strstr(feature, server_capabilities) != NULL;
+}
+
 int get_ack(int fd, unsigned char *result_sha1)
 {
 	static char line[1000];
---
0.99.8.GIT

^ permalink raw reply related	[relevance 17%]

* [PATCH 2/4] Library code for user-relative paths.
@ 2005-11-01 22:59 15% Andreas Ericsson
  0 siblings, 0 replies; 200+ results
From: Andreas Ericsson @ 2005-11-01 22:59 UTC (permalink / raw)


See this discussion, "[RFC] GIT paths", on the git-list:
http://www.gelato.unsw.edu.au/archives/git/0510/10924.html

This patch provides the work-horse of the user-relative paths, using Linus'
idea of a blind chdir() and getcwd(), which makes it remarkably simple.

Signed-off-by: Andreas Ericsson <ae@op5.se>

---

 cache.h |    1 +
 path.c  |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 0 deletions(-)

applies-to: bf640ae3d5bb5f5f283c62d4f5198a3c5e5086f0
1c4e7bb2383e2b67f0e877a46ea1eba4ec7e45e7
diff --git a/cache.h b/cache.h
index 677c6ac..aea2097 100644
--- a/cache.h
+++ b/cache.h
@@ -190,6 +190,7 @@ extern int trust_executable_bit;
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern const char *is_git_repo(const char *path, int strict);
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
 extern char *sha1_pack_name(const unsigned char *sha1);
diff --git a/path.c b/path.c
index 495d17c..4f4018d 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
  * which is what it's designed for.
  */
 #include "cache.h"
+#include <pwd.h>
 
 static char pathname[PATH_MAX];
 static char bad_path[] = "/bad-path/";
@@ -89,3 +90,74 @@ char *safe_strncpy(char *dest, const cha
 
 	return dest;
 }
+
+static const char *current_dir()
+{
+	return getcwd(pathname, sizeof(pathname));
+}
+
+/* Take a raw path from is_git_repo() and canonicalize it using Linus'
+ * idea of a blind chdir() and getcwd(). */
+static const char *canonical_path(const char *path, int strict)
+{
+	const char *dir = path;
+
+	if(strict && *dir != '/')
+		return NULL;
+
+	if(*dir == '~') {		/* user-relative path */
+		struct passwd *pw;
+		char *slash = NULL;
+
+		dir++;
+		/* '~/' and '~' (no slash) means users own home-dir */
+		if(!*dir || *dir == '/')
+			pw = getpwuid(getuid());
+		else {
+			if((slash = strchr(dir, '/'))) {
+				*slash = '\0';
+				pw = getpwnam(dir);
+				*slash = '/';
+			}
+			else
+				pw = getpwnam(dir);
+		}
+
+		/* make sure we got something back that we can chdir() to */
+		if(!pw || chdir(pw->pw_dir) < 0)
+			return NULL;
+
+		if(slash && *slash + 1)
+			dir = slash + 1;
+		else
+			dir = current_dir();
+	}
+
+	/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
+	if(chdir(dir) < 0)
+		return NULL;
+
+	return current_dir();
+}
+
+const char *is_git_repo(const char *path, int strict)
+{
+	if(!path)
+		return NULL;
+
+	if(!canonical_path(path, strict)) {
+		if(strict || !canonical_path(mkpath("%s.git", path), strict))
+			return NULL;
+	}
+
+	/* This is perfectly safe, and people tend to think of the directory
+	 * where they ran git-init-db as their repository, so humour them. */
+	(void)chdir(".git");
+
+	if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0) {
+		putenv("GIT_DIR=.");
+		return current_dir();
+	}
+
+	return NULL;
+}
---
0.99.9.GIT

^ permalink raw reply related	[relevance 15%]

* Re: git's rev-parse.c function show_datestring presumes gnu date
  @ 2005-11-15  3:29 10%   ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-11-15  3:29 UTC (permalink / raw)
  To: Randal L. Schwartz, Junio C Hamano; +Cc: git



On Mon, 14 Nov 2005, Linus Torvalds wrote:
> 
> It shouldn't be all that difficult to do some trivial cases (gnu date 
> handles totally insane things, we could easily do with just a simpler 
> thing). 

Ok. This is the insane patch to do this.

It really isn't very careful, and the reason I call it "approxidate()" 
will become obvious when you look at the code. It is very liberal in what 
it accepts, to the point where sometimes the results may not make a whole 
lot of sense.

It accepts "last week" as a date string, by virtue of "last" parsing as 
the number 1, and it totally ignoring superfluous fluff like "ago", so 
"last week" ends up being exactly the same thing as "1 week ago". Fine so 
far.

It has strange side effects: "last december" will actually parse as "Dec 
1", which actually _does_ turn out right, because it will then notice that 
it's not December yet, so it will decide that you must be talking about a 
date last year. So it actually gets it right, but it's kind of for the 
"wrong" reasons.

It also accepts the numbers 1..10 in string format ("one" .. "ten"), so 
you can do "ten weeks ago" or "ten hours ago" and it will do the right 
thing.

But it will do some really strange thigns too: the string "this will last 
forever", will not recognize anyting but "last", which is recognized as 
"1", which since it doesn't understand anything else it will think is the 
day of the month. So if you do

	gitk --since="this will last forever"

the date will actually parse as the first day of the current month.

And it will parse the string "now" as "now", but only because it doesn't 
understand it at all, and it makes everything relative to "now".

Similarly, it doesn't actually parse the "ago" or "from now", so "2 weeks 
ago" is exactly the same as "2 weeks from now". It's the current date 
minus 14 days.

But hey, it's probably better (and certainly faster) than depending on GNU 
date. So now you can portably do things like

	gitk --since="two weeks and three days ago"
	git log --since="July 5"
	git-whatchanged --since="10 hours ago"
	git log --since="last october"

and it will actually do exactly what you thought it would do (I think). It 
will count 17 days backwards, and it will do so even if you don't have GNU 
date installed.

(I don't do "last monday" or similar yet, but I can extend it to that too 
if people want).

It was kind of fun trying to write code that uses such totally relaxed 
"understanding" of dates yet tries to get it right for the trivial cases. 
The result should be mixed with a few strange preprocessor tricks, and be 
submitted for the IOCCC ;)

Feel free to try it out, and see how many strange dates it gets right. Or 
wrong.

And if you find some interesting (and valid - not "interesting" as in 
"strange", but "interesting" as in "I'd be interested in actually doing 
this) thing it gets wrong - usually by not understanding it and silently 
just doing some strange things - please holler.

Now, as usual this certainly hasn't been getting a lot of testing. But my 
code always works, no?

		Linus

----
diff --git a/cache.h b/cache.h
index 677c6ac..dcfee1e 100644
--- a/cache.h
+++ b/cache.h
@@ -257,6 +257,7 @@ extern void *read_object_with_reference(
 const char *show_date(unsigned long time, int timezone);
 int parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
+unsigned long approxidate(const char *);
 
 extern int setup_ident(void);
 extern char *get_ident(const char *name, const char *email, const char *date_str);
diff --git a/date.c b/date.c
index 63f5a09..73c063b 100644
--- a/date.c
+++ b/date.c
@@ -5,6 +5,7 @@
  */
 
 #include <time.h>
+#include <sys/time.h>
 
 #include "cache.h"
 
@@ -460,3 +461,126 @@ void datestamp(char *buf, int bufsize)
 
 	date_string(now, offset, buf, bufsize);
 }
+
+static void update_tm(struct tm *tm, unsigned long sec)
+{
+	time_t n = mktime(tm) - sec;
+	localtime_r(&n, tm);
+}
+
+static const char *number_name[] = {
+	"zero", "one", "two", "three", "four",
+	"five", "six", "seven", "eight", "nine", "ten",
+};
+
+static struct typelen {
+	const char *type;
+	int length;
+} typelen[] = {
+	{ "seconds", 1 },
+	{ "minutes", 60 },
+	{ "hours", 60*60 },
+	{ "days", 24*60*60 },
+	{ "weeks", 7*24*60*60 },
+	{ NULL }
+};	
+
+static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
+{
+	struct typelen *tl;
+	const char *end = date;
+	int n = 1, i;
+
+	while (isalpha(*++end))
+		n++;
+
+	for (i = 0; i < 12; i++) {
+		int match = match_string(date, month_names[i]);
+		if (match >= 3) {
+			tm->tm_mon = i;
+			return end;
+		}
+	}
+
+	if (match_string(date, "yesterday") > 8) {
+		update_tm(tm, 24*60*60);
+		return end;
+	}
+
+	if (!*num) {
+		for (i = 1; i < 11; i++) {
+			int len = strlen(number_name[i]);
+			if (match_string(date, number_name[i]) == len) {
+				*num = i;
+				return end;
+			}
+		}
+		if (match_string(date, "last") == 4)
+			*num = 1;
+		return end;
+	}
+
+	tl = typelen;
+	while (tl->type) {
+		int len = strlen(tl->type);
+		if (match_string(date, tl->type) >= len-1) {
+			update_tm(tm, tl->length * *num);
+			*num = 0;
+			return end;
+		}
+		tl++;
+	}
+
+	if (match_string(date, "months") >= 5) {
+		int n = tm->tm_mon - *num;
+		*num = 0;
+		while (n < 0) {
+			n += 12;
+			tm->tm_year--;
+		}
+		tm->tm_mon = n;
+		return end;
+	}
+
+	if (match_string(date, "years") >= 4) {
+		tm->tm_year -= *num;
+		*num = 0;
+		return end;
+	}
+
+	return end;
+}
+
+unsigned long approxidate(const char *date)
+{
+	int number = 0;
+	struct tm tm, now;
+	struct timeval tv;
+	char buffer[50];
+
+	if (parse_date(date, buffer, sizeof(buffer)) > 0)
+		return strtoul(buffer, NULL, 10);
+
+	gettimeofday(&tv, NULL);
+	localtime_r(&tv.tv_sec, &tm);
+	now = tm;
+	for (;;) {
+		unsigned char c = *date;
+		if (!c)
+			break;
+		date++;
+		if (isdigit(c)) {
+			char *end;
+			number = strtoul(date-1, &end, 10);
+			date = end;
+			continue;
+		}
+		if (isalpha(c))
+			date = approxidate_alpha(date-1, &tm, &number);
+	}
+	if (number > 0 && number < 32)
+		tm.tm_mday = number;
+	if (tm.tm_mon > now.tm_mon)
+		tm.tm_year--;
+	return mktime(&tm);
+}
diff --git a/rev-parse.c b/rev-parse.c
index 5a98982..bb4949a 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -131,25 +131,12 @@ static int show_reference(const char *re
 
 static void show_datestring(const char *flag, const char *datestr)
 {
-	FILE *date;
 	static char buffer[100];
-	static char cmd[1000];
-	int len;
 
 	/* date handling requires both flags and revs */
 	if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
 		return;
-	len = strlen(flag);
-	memcpy(buffer, flag, len);
-
-	snprintf(cmd, sizeof(cmd), "date --date=%s +%%s", sq_quote(datestr));
-	date = popen(cmd, "r");
-	if (!date || !fgets(buffer + len, sizeof(buffer) - len, date))
-		die("git-rev-list: bad date string");
-	pclose(date);
-	len = strlen(buffer);
-	if (buffer[len-1] == '\n')
-		buffer[--len] = 0;
+	snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
 	show(buffer);
 }
 

^ permalink raw reply related	[relevance 10%]

* [PATCH] Add config variable core.symrefsonly
@ 2005-11-15 18:24 22% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-11-15 18:24 UTC (permalink / raw)
  To: git, junkio

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2808 bytes --]


This allows you to force git to avoid symlinks for refs. Just add
something like

	[core]
		symrefsonly = true

to .git/config.

Don´t forget to "git checkout your_branch", or it does not do anything...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

---

	Linus, is there any reason you don´t allow spaces, underscores
	and dashes in the config variables?

	Petr, happy?

 cache.h        |    1 +
 config.c       |    5 +++++
 environment.c  |    1 +
 refs.c         |   10 ++++++----
 symbolic-ref.c |    1 +
 5 files changed, 14 insertions(+), 4 deletions(-)

applies-to: 4b6dbe856a3e63699b299c76f4f1fc5cb34cbe26
b12e60607e70f01de9dc65b88f15c9b17f7be4c5
diff --git a/cache.h b/cache.h
index 677c6ac..9a6bfb9 100644
--- a/cache.h
+++ b/cache.h
@@ -179,6 +179,7 @@ extern int commit_index_file(struct cach
 extern void rollback_index_file(struct cache_file *);
 
 extern int trust_executable_bit;
+extern int only_use_symrefs;
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
diff --git a/config.c b/config.c
index e89bab2..bd35138 100644
--- a/config.c
+++ b/config.c
@@ -214,6 +214,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "core.symrefsonly")) {
+		only_use_symrefs = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "user.name")) {
 		strncpy(git_default_name, value, sizeof(git_default_name));
 		return 0;
diff --git a/environment.c b/environment.c
index 1dc7af5..b5026f1 100644
--- a/environment.c
+++ b/environment.c
@@ -12,6 +12,7 @@
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
+int only_use_symrefs = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
diff --git a/refs.c b/refs.c
index a52b038..f324be5 100644
--- a/refs.c
+++ b/refs.c
@@ -121,10 +121,12 @@ int create_symref(const char *git_HEAD, 
 	int fd, len, written;
 
 #if USE_SYMLINK_HEAD
-	unlink(git_HEAD);
-	if (!symlink(refs_heads_master, git_HEAD))
-		return 0;
-	fprintf(stderr, "no symlink - falling back to symbolic ref\n");
+	if (!only_use_symrefs) {
+		unlink(git_HEAD);
+		if (!symlink(refs_heads_master, git_HEAD))
+			return 0;
+		fprintf(stderr, "no symlink - falling back to symbolic ref\n");
+	}
 #endif
 
 	len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
diff --git a/symbolic-ref.c b/symbolic-ref.c
index a72d7ac..193c87c 100644
--- a/symbolic-ref.c
+++ b/symbolic-ref.c
@@ -20,6 +20,7 @@ static void check_symref(const char *HEA
 int main(int argc, const char **argv)
 {
 	setup_git_directory();
+	git_config(git_default_config);
 	switch (argc) {
 	case 2:
 		check_symref(argv[1]);
---
0.99.9.GIT

^ permalink raw reply related	[relevance 22%]

* [PATCH 1/3] Add function git_config_set()
@ 2005-11-15 21:36 14% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-11-15 21:36 UTC (permalink / raw)
  To: git, junkio


This function does exactly what you think it does. Given a key and a value,
it sets the key (in the form "core.filemode") to the value.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

---

 cache.h  |    1 
 config.c |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+), 0 deletions(-)

applies-to: a54ecd1a81180a8d860a6554e6fc71dcab3327ef
c38f654a4387ed503a8ea445824e49b44a796c61
diff --git a/cache.h b/cache.h
index 9a6bfb9..91070ae 100644
--- a/cache.h
+++ b/cache.h
@@ -384,6 +384,7 @@ extern int git_default_config(const char
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
+extern int git_config_set(const char *, const char *);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
diff --git a/config.c b/config.c
index bd35138..1b39290 100644
--- a/config.c
+++ b/config.c
@@ -247,3 +247,148 @@ int git_config(config_fn_t fn)
 	}
 	return ret;
 }
+
+static struct {
+	int baselen;
+	const char* key;
+	const char* value;
+	off_t offset;
+	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
+} store;
+
+static int store_aux(const char* key, const char* value)
+{
+	switch (store.state) {
+		case KEY_SEEN:
+			if (!strcmp(key, store.key))
+				store.offset = ftell(config_file);
+			break;
+		case SECTION_SEEN:
+			if (strncmp(key, store.key, store.baselen+1)) {
+				store.offset = ftell(config_file);
+				store.state = SECTION_END_SEEN;
+				break;
+			}
+		case SECTION_END_SEEN:
+		case START:
+			if (!strcmp(key, store.key)) {
+				store.offset = ftell(config_file);
+				store.state = KEY_SEEN;
+			} else if(!strncmp(key, store.key, store.baselen))
+				store.state = SECTION_SEEN;
+	}
+	return 0;
+}
+
+static void store_write_section(int fd)
+{
+	write(fd, "[", 1);
+	write(fd, store.key, store.baselen);
+	write(fd, "]\n", 2);
+}
+
+static void store_write_pair(int fd)
+{
+	int i;
+
+	write(fd, "\t", 1);
+	write(fd, store.key+store.baselen+1,
+		strlen(store.key+store.baselen+1));
+	write(fd, " = ", 3);
+	for (i = 0; store.value[i]; i++)
+		switch (store.value[i]) {
+		case '\n': write(fd, "\\n", 2); break;
+		case '\t': write(fd, "\\t", 2); break;
+		case '"': case '\\': write(fd, "\\", 1);
+		default: write(fd, store.value+i, 1);
+	}
+	write(fd, "\n", 1);
+}
+
+int git_config_set(const char* key, const char* value)
+{
+	int i;
+	struct stat st;
+	int fd;
+	char* config_file = strdup(git_path("config"));
+	char* lock_file = strdup(git_path("config.lock"));
+
+	for (store.baselen = 0;
+			key[store.baselen] != '.' && key[store.baselen];
+			store.baselen++);
+	if (!key[store.baselen]) {
+		fprintf(stderr, "key does not contain a section: %s\n", key);
+		return 2;
+	}
+
+	for (i = 0; key[i]; i++)
+		if (i != store.baselen && !isalpha(key[i])) {
+			fprintf(stderr, "invalid key: %s\n", key);
+			return 1;
+		}
+
+	store.key = key;
+	store.value = value;
+
+	fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		fprintf(stderr, "could not lock config file\n");
+		return -1;
+	}
+
+	if (stat(config_file, &st)) {
+		/* write new file */
+		static const char contents[] =
+			"#\n"
+			"# This is the config file\n"
+			"#\n"
+			"\n";
+
+		write(fd, contents, sizeof(contents)-1);
+		store_write_section(fd);
+		store_write_pair(fd);
+	} else{
+		int in_fd;
+		char* contents;
+		int offset;
+
+		store.offset = 0;
+		store.state = START;
+
+		if (git_config(store_aux)) {
+			fprintf(stderr, "invalid config file\n");
+			return 3;
+		}
+
+		in_fd = open(config_file, O_RDONLY, 0666);
+		contents = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in_fd, 0);
+		close(in_fd);
+
+		if (store.offset == 0)
+			offset = st.st_size;
+		else {
+			for (offset = store.offset-2; offset > 0 
+					&& contents[offset] != '\n'; offset--);
+			offset++;
+		}
+		write(fd, contents, offset);
+		if (store.state == START)
+			store_write_section(fd);
+		store_write_pair(fd);
+		if (store.offset > offset)
+			write(fd, contents + store.offset,
+				st.st_size - store.offset);
+		
+		unlink(config_file);
+	}
+
+	close(fd);
+
+	if (rename(lock_file, config_file) < 0) {
+		fprintf(stderr, "Could not rename the lock file?\n");
+		return 4;
+	}
+
+	return 0;
+}
+
---
0.99.9.GIT

^ permalink raw reply related	[relevance 14%]

* [PATCH 1/5] Library code for user-relative paths, take three.
@ 2005-11-17 19:37 15% Andreas Ericsson
  0 siblings, 0 replies; 200+ results
From: Andreas Ericsson @ 2005-11-17 19:37 UTC (permalink / raw)
  To: git


See the threads "User-relative paths", "[RFC] GIT paths" and
"[PATCH 0/4] User-relative paths, take two" for previous discussions
on this topic.

This patch provides the work-horse of the user-relative paths feature,
using Linus' idea of a blind chdir() and getcwd() which makes it
remarkably simple.

Signed-off-by: Andreas Ericsson <ae@op5.se>

---

 cache.h |    1 +
 path.c  |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 0 deletions(-)

applies-to: 8ff699dffc817e92fb2101f538f84c38d5ed0a0f
416ee0a4f47244471b52b9dc8aca3e984b20445f
diff --git a/cache.h b/cache.h
index 99afa2c..d8be06b 100644
--- a/cache.h
+++ b/cache.h
@@ -192,6 +192,7 @@ extern int diff_rename_limit_default;
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern char *enter_repo(char *path, int strict);
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
 extern char *sha1_pack_name(const unsigned char *sha1);
diff --git a/path.c b/path.c
index 495d17c..5b61709 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
  * which is what it's designed for.
  */
 #include "cache.h"
+#include <pwd.h>
 
 static char pathname[PATH_MAX];
 static char bad_path[] = "/bad-path/";
@@ -89,3 +90,74 @@ char *safe_strncpy(char *dest, const cha
 
 	return dest;
 }
+
+static char *current_dir()
+{
+	return getcwd(pathname, sizeof(pathname));
+}
+
+/* Take a raw path from is_git_repo() and canonicalize it using Linus'
+ * idea of a blind chdir() and getcwd(). */
+static const char *canonical_path(char *path, int strict)
+{
+	char *dir = path;
+
+	if(strict && *dir != '/')
+		return NULL;
+
+	if(*dir == '~') {		/* user-relative path */
+		struct passwd *pw;
+		char *slash = strchr(dir, '/');
+
+		dir++;
+		/* '~/' and '~' (no slash) means users own home-dir */
+		if(!*dir || *dir == '/')
+			pw = getpwuid(getuid());
+		else {
+			if (slash) {
+				*slash = '\0';
+				pw = getpwnam(dir);
+				*slash = '/';
+			}
+			else
+				pw = getpwnam(dir);
+		}
+
+		/* make sure we got something back that we can chdir() to */
+		if(!pw || chdir(pw->pw_dir) < 0)
+			return NULL;
+
+		if(!slash || !slash[1]) /* no path following username */
+			return current_dir();
+
+		dir = slash + 1;
+	}
+
+	/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
+	if(chdir(dir) < 0)
+		return NULL;
+
+	return current_dir();
+}
+
+char *enter_repo(char *path, int strict)
+{
+	if(!path)
+		return NULL;
+
+	if(!canonical_path(path, strict)) {
+		if(strict || !canonical_path(mkpath("%s.git", path), strict))
+			return NULL;
+	}
+
+	/* This is perfectly safe, and people tend to think of the directory
+	 * where they ran git-init-db as their repository, so humour them. */
+	(void)chdir(".git");
+
+	if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0) {
+		putenv("GIT_DIR=.");
+		return current_dir();
+	}
+
+	return NULL;
+}
---
0.99.9.GIT

^ permalink raw reply related	[relevance 15%]

* [PATCH] Add functions git_config_set() and git_config_set_multivar()
@ 2005-11-17 21:32 10% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-11-17 21:32 UTC (permalink / raw)
  To: git, junkio

    
The function git_config_set() does exactly what you think it does.
Given a key (in the form "core.filemode") and a value, it sets the
key to the value. Example:

	git_config_set("core.filemode", "true");

The function git_config_set_multivar() is meant for setting variables which
can have several values for the same key. Example:

	[diff]
		twohead = resolve
		twohead = recarsive

the typo in the second line can be replaced by

	git_config_set_multivar("diff.twohead", "recursive", "^recar");

The third argument of the function is a POSIX extended regex which has to
match the value. If there is no key/value pair with a matching value, a new
key/value pair is added.

These commands are also capable of unsetting (deleting) entries:

	git_config_set_multivar("diff.twohead", NULL, "sol");

will delete the entry

		twohead = resolve

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 cache.h  |    2 
 config.c |  294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 295 insertions(+), 1 deletions(-)
diff --git a/cache.h b/cache.h
index 99afa2c..f93f516 100644
--- a/cache.h
+++ b/cache.h
@@ -386,6 +386,8 @@ extern int git_default_config(const char
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
+extern int git_config_set(const char *, const char *);
+extern int git_config_set_multivar(const char *, const char *, const char *);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
diff --git a/config.c b/config.c
index 915bb97..bbcafff 100644
--- a/config.c
+++ b/config.c
@@ -1,5 +1,12 @@
-
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ * Copyright (C) Johannes Schindelin, 2005
+ *
+ */
 #include "cache.h"
+#include <regex.h>
 
 #define MAXNAME (256)
 
@@ -252,3 +259,288 @@ int git_config(config_fn_t fn)
 	}
 	return ret;
 }
+
+/*
+ * Find all the stuff for git_config_set() below.
+ */
+static struct {
+	int baselen;
+	char* key;
+	regex_t* value_regex;
+	off_t offset;
+	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
+	int seen;
+} store;
+
+static int store_aux(const char* key, const char* value)
+{
+	switch (store.state) {
+	case KEY_SEEN:
+		if (!strcmp(key, store.key) &&
+				(store.value_regex == NULL ||
+				!regexec(store.value_regex, value, 0, NULL, 0))) {
+			if (store.seen == 1) {
+				fprintf(stderr,
+					"Warning: %s has multiple values\n",
+					key);
+			}
+			store.offset = ftell(config_file);
+			store.seen++;
+		}
+		break;
+	case SECTION_SEEN:
+		if (strncmp(key, store.key, store.baselen+1)) {
+			store.state = SECTION_END_SEEN;
+			break;
+		} else
+			store.offset = ftell(config_file);
+		/* fallthru */
+	case SECTION_END_SEEN:
+	case START:
+		if (!strcmp(key, store.key) &&
+				(store.value_regex == NULL ||
+				!regexec(store.value_regex, value, 0, NULL, 0))) {
+			store.offset = ftell(config_file);
+			store.state = KEY_SEEN;
+			store.seen++;
+		} else if(!strncmp(key, store.key, store.baselen))
+			store.state = SECTION_SEEN;
+	}
+	return 0;
+}
+
+static void store_write_section(int fd, const char* key)
+{
+	write(fd, "[", 1);
+	write(fd, key, store.baselen);
+	write(fd, "]\n", 2);
+}
+
+static void store_write_pair(int fd, const char* key, const char* value)
+{
+	int i;
+
+	write(fd, "\t", 1);
+	write(fd, key+store.baselen+1,
+		strlen(key+store.baselen+1));
+	write(fd, " = ", 3);
+	for (i = 0; value[i]; i++)
+		switch (value[i]) {
+		case '\n': write(fd, "\\n", 2); break;
+		case '\t': write(fd, "\\t", 2); break;
+		case '"': case '\\': write(fd, "\\", 1);
+		default: write(fd, value+i, 1);
+	}
+	write(fd, "\n", 1);
+}
+
+int git_config_set(const char* key, const char* value)
+{
+	return git_config_set_multivar(key, value, NULL);
+}
+
+/*
+ * If value==NULL, unset in (remove from) config,
+ * if value_regex!=NULL, disregard key/value pairs where value does not match.
+ *
+ * Returns 0 on success.
+ *
+ * This function does this:
+ *
+ * - it locks the config file by creating ".git/config.lock"
+ *
+ * - it then parses the config using store_aux() as validator to find
+ *   the position on the key/value pair to replace. If it is to be unset,
+ *   it must be found exactly once.
+ *
+ * - the config file is mmap()ed and the part before the match (if any) is
+ *   written to the lock file, then the changed part and the rest.
+ *
+ * - the config file is removed and the lock file rename()d to it.
+ *
+ */
+int git_config_set_multivar(const char* key, const char* value,
+	const char* value_regex)
+{
+	int i;
+	struct stat st;
+	int fd;
+	char* config_file = strdup(git_path("config"));
+	char* lock_file = strdup(git_path("config.lock"));
+
+	/*
+	 * Since "key" actually contains the section name and the real
+	 * key name separated by a dot, we have to know where the dot is.
+	 */
+	for (store.baselen = 0;
+			key[store.baselen] != '.' && key[store.baselen];
+			store.baselen++);
+	if (!key[store.baselen] || !key[store.baselen+1]) {
+		fprintf(stderr, "key does not contain a section: %s\n", key);
+		return 2;
+	}
+
+	/*
+	 * Validate the key and while at it, lower case it for matching.
+	 */
+	store.key = (char*)malloc(strlen(key)+1);
+	for (i = 0; key[i]; i++)
+		if (i != store.baselen && (!isalnum(key[i]) ||
+				(i == store.baselen+1 && !isalpha(key[i])))) {
+			fprintf(stderr, "invalid key: %s\n", key);
+			free(store.key);
+			return 1;
+		} else
+			store.key[i] = tolower(key[i]);
+
+	/*
+	 * The lock_file serves a purpose in addition to locking: the new
+	 * contents of .git/config will be written into it.
+	 */
+	fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	if (fd < 0) {
+		fprintf(stderr, "could not lock config file\n");
+		free(store.key);
+		return -1;
+	}
+
+	/*
+	 * If .git/config does not exist yet, write a minimal version.
+	 */
+	if (stat(config_file, &st)) {
+		static const char contents[] =
+			"#\n"
+			"# This is the config file\n"
+			"#\n"
+			"\n";
+
+		free(store.key);
+
+		/* if nothing to unset, error out */
+		if (value == NULL) {
+			close(fd);
+			unlink(lock_file);
+			return 5;
+		}
+
+		store.key = (char*)key;
+
+		write(fd, contents, sizeof(contents)-1);
+		store_write_section(fd, key);
+		store_write_pair(fd, key, value);
+	} else{
+		int in_fd;
+		char* contents;
+		int offset, new_line = 0;
+
+		if (value_regex == NULL)
+			store.value_regex = NULL;
+		else {
+			store.value_regex = (regex_t*)malloc(sizeof(regex_t));
+			if (regcomp(store.value_regex, value_regex,
+					REG_EXTENDED)) {
+				fprintf(stderr, "Invalid pattern: %s",
+					value_regex);
+				free(store.value_regex);
+				return 6;
+			}
+		}
+
+		store.offset = 0;
+		store.state = START;
+		store.seen = 0;
+
+		/*
+		 * After this, store.offset will contain the *end* offset
+		 * of the last match, or remain at 0 if no match was found.
+		 * As a side effect, we make sure to transform only a valid
+		 * existing config file.
+		 */
+		if (git_config(store_aux)) {
+			fprintf(stderr, "invalid config file\n");
+			free(store.key);
+			if (store.value_regex != NULL) {
+				regfree(store.value_regex);
+				free(store.value_regex);
+			}
+			return 3;
+		}
+
+		free(store.key);
+		if (store.value_regex != NULL) {
+			regfree(store.value_regex);
+			free(store.value_regex);
+		}
+
+		/* if nothing to unset, error out */
+		if (store.seen == 0 && value == NULL) {
+			close(fd);
+			unlink(lock_file);
+			return 5;
+		}
+
+		store.key = (char*)key;
+
+		in_fd = open(config_file, O_RDONLY, 0666);
+		contents = mmap(NULL, st.st_size, PROT_READ,
+			MAP_PRIVATE, in_fd, 0);
+		close(in_fd);
+
+		if (store.offset == 0) {
+			store.offset = offset = st.st_size;
+		} else if (store.state != KEY_SEEN) {
+			offset = store.offset;
+		} else {
+			int equal_offset = st.st_size,
+				bracket_offset = st.st_size;
+
+			if (value == NULL && store.seen > 1) {
+				fprintf(stderr, "Cannot remove multivar (%s has %d values\n", key, store.seen);
+				close(fd);
+				unlink(lock_file);
+				return 7;
+			}
+			for (offset = store.offset-2; offset > 0 
+					&& contents[offset] != '\n'; offset--)
+				switch (contents[offset]) {
+				case '=': equal_offset = offset; break;
+				case ']': bracket_offset = offset; break;
+				}
+			if (bracket_offset < equal_offset) {
+				new_line = 1;
+				offset = bracket_offset+1;
+			} else
+				offset++;
+		}
+
+		/* write the first part of the config */
+		write(fd, contents, offset);
+		if (new_line)
+			write(fd, "\n", 1);
+
+		/* write the pair (value == NULL means unset) */
+		if (value != NULL) {
+			if (store.state == START)
+				store_write_section(fd, key);
+			store_write_pair(fd, key, value);
+		}
+
+		/* write the rest of the config */
+		if (store.offset < st.st_size)
+			write(fd, contents + store.offset,
+				st.st_size - store.offset);
+
+		munmap(contents, st.st_size);
+		unlink(config_file);
+	}
+
+	close(fd);
+
+	if (rename(lock_file, config_file) < 0) {
+		fprintf(stderr, "Could not rename the lock file?\n");
+		return 4;
+	}
+
+	return 0;
+}
+

^ permalink raw reply related	[relevance 10%]

* [PATCH] git-config-set: add more options
@ 2005-11-20  5:52  7% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-11-20  5:52 UTC (permalink / raw)
  To: git, junkio

... namely

--replace-all, to replace any amount of matching lines, not just 0 or 1,
--get, to get the value of one key,
--get-all, the multivar version of --get, and
--unset-all, which deletes all matching lines from .git/config

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	This patch is on top of my previous patches, because it is not
	a bug fix, but provides new features.

	Also, it extends t1300-config-set.sh to test these, and moves it 
	into t/...

	The only thing I am concerned about now is how to deal with
	anti value_regex's, i.e.

		[proxy]
			command=ssh for kernel.org
			command=rsh

	I cannot think of a POSIX regex which matches all values *not*
	containing " for " (like the second command), short of matching
	the exact value.

	Note: we could adjust the pattern syntax so that a prefix "!"
	means "no match", and "\!" means "match literal !", but this
	is ugly.

 Documentation/git-config-set.txt |   62 ++++++++++++++++++--
 cache.h                          |    3 -
 config-set.c                     |   92 +++++++++++++++++++++++++++++-
 config.c                         |  116 +++++++++++++++++++++++---------------
 t/t1300-config-set.sh            |   46 +++++++++++++++
 5 files changed, 258 insertions(+), 61 deletions(-)
diff --git a/Documentation/git-config-set.txt b/Documentation/git-config-set.txt
index 8e897be..c707fbc 100644
--- a/Documentation/git-config-set.txt
+++ b/Documentation/git-config-set.txt
@@ -8,12 +8,18 @@ git-config-set - Set options in .git/con
 
 SYNOPSIS
 --------
-'git-config-set' ( name [value [value_regex]] | --unset name [value_regex] )
+'git-config-set' name [value [value_regex]]
+'git-config-set' --replace-all name [value [value_regex]]
+'git-config-set' --get name [value_regex]
+'git-config-set' --get-all name [value_regex]
+'git-config-set' --unset name [value_regex]
+'git-config-set' --unset-all name [value_regex]
 
 DESCRIPTION
 -----------
-You can set/replace/unset options with this command. The name is actually
-the section and the key separated by a dot, and the value will be escaped.
+You can query/set/replace/unset options with this command. The name is
+actually the section and the key separated by a dot, and the value will be
+escaped.
 
 If you want to set/unset an option which can occor on multiple lines, you
 should provide a POSIX regex for the value.
@@ -31,8 +37,23 @@ This command will fail if
 OPTIONS
 -------
 
+--replace-all::
+	Default behaviour is to replace at most one line. This replaces
+	all lines matching the key (and optionally the value_regex)
+
+--get::
+	Get the value for a given key (optionally filtered by a regex
+	matching the value).
+
+--get-all::
+	Like get, but does not fail if the number of values for the key
+	is not exactly one.
+
 --unset::
-	Remove the given option from .git/config
+	Remove the line matching the key from .git/config.
+
+--unset-all::
+	Remove all matching lines from .git/config.
 
 
 EXAMPLE
@@ -84,14 +105,39 @@ To delete the entry for renames, do
 % git config-set --unset diff.renames
 ------------
 
-or just
+If you want to delete an entry for a multivar (like proxy.command above),
+you have to provide a regex matching the value of exactly one line.
+
+To query the value for a given key, do
 
 ------------
-% git config-set diff.renames
+% git config-set --get core.filemode
 ------------
 
-If you want to delete an entry for a multivar (like proxy.command above),
-you have to provide a regex matching the value of exactly one line.
+or
+
+------------
+% git config-set core.filemode
+------------
+
+or, to query a multivar:
+
+------------
+% git config-set --get proxy.command "for kernel.org$"
+------------
+
+If you want to know all the values for a multivar, do:
+
+------------
+% git config-set --get-all proxy.command
+------------
+
+If you like to live dangerous, you can replace *all* proxy.commands by a
+new one with
+
+------------
+% git config-set --replace-all proxy.command ssh
+------------
 
 
 Author
diff --git a/cache.h b/cache.h
index e2be3e7..a7c1bbd 100644
--- a/cache.h
+++ b/cache.h
@@ -192,7 +192,6 @@ extern int diff_rename_limit_default;
 
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
-extern char *enter_repo(char *path, int strict);
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
 extern char *sha1_pack_name(const unsigned char *sha1);
@@ -388,7 +387,7 @@ extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_set(const char *, const char *);
-extern int git_config_set_multivar(const char *, const char *, const char *);
+extern int git_config_set_multivar(const char *, const char *, const char *, int);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
diff --git a/config-set.c b/config-set.c
index 1b1547b..90a28b3 100644
--- a/config-set.c
+++ b/config-set.c
@@ -1,24 +1,106 @@
 #include "cache.h"
+#include <regex.h>
 
 static const char git_config_set_usage[] =
-"git-config-set name [value [value_regex]] | --unset name [value_regex]";
+"git-config-set [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]]";
+
+static char* key = NULL;
+static char* value = NULL;
+static regex_t* regex = NULL;
+static int do_all = 0;
+static int seen = 0;
+
+static int show_config(const char* key_, const char* value_)
+{
+	if (!strcmp(key_, key) &&
+			(regex == NULL ||
+			 !regexec(regex, value_, 0, NULL, 0))) {
+		if (do_all) {
+			printf("%s\n", value_);
+			return 0;
+		}
+		if (seen > 0) {
+			fprintf(stderr, "More than one value: %s\n", value);
+			free(value);
+		}
+		value = strdup(value_);
+		seen++;
+	}
+	return 0;
+}
+
+static int get_value(const char* key_, const char* regex_)
+{
+	int i;
+
+	key = malloc(strlen(key_)+1);
+	for (i = 0; key_[i]; i++)
+		key[i] = tolower(key_[i]);
+
+	if (regex_) {
+		regex = (regex_t*)malloc(sizeof(regex_t));
+		if (regcomp(regex, regex_, REG_EXTENDED)) {
+			fprintf(stderr, "Invalid pattern: %s\n", regex_);
+			return -1;
+		}
+	}
+
+	i = git_config(show_config);
+	if (value) {
+		printf("%s\n", value);
+		free(value);
+	}
+	free(key);
+	if (regex) {
+		regfree(regex);
+		free(regex);
+	}
+
+	if (do_all)
+		return 0;
+
+	return seen == 1 ? 0 : 1;
+}
 
 int main(int argc, const char **argv)
 {
 	setup_git_directory();
 	switch (argc) {
 	case 2:
-		return git_config_set(argv[1], NULL);
+		return get_value(argv[1], NULL);
 	case 3:
 		if (!strcmp(argv[1], "--unset"))
 			return git_config_set(argv[2], NULL);
-		else
+		else if (!strcmp(argv[1], "--unset-all"))
+			return git_config_set_multivar(argv[2], NULL, NULL, 1);
+		else if (!strcmp(argv[1], "--get"))
+			return get_value(argv[2], NULL);
+		else if (!strcmp(argv[1], "--get-all")) {
+			do_all = 1;
+			return get_value(argv[2], NULL);
+		} else
+
 			return git_config_set(argv[1], argv[2]);
 	case 4:
 		if (!strcmp(argv[1], "--unset"))
-			return git_config_set_multivar(argv[2], NULL, argv[3]);
+			return git_config_set_multivar(argv[2], NULL, argv[3], 0);
+		else if (!strcmp(argv[1], "--unset-all"))
+			return git_config_set_multivar(argv[2], NULL, argv[3], 1);
+		else if (!strcmp(argv[1], "--get"))
+			return get_value(argv[2], argv[3]);
+		else if (!strcmp(argv[1], "--get-all")) {
+			do_all = 1;
+			return get_value(argv[2], argv[3]);
+		} else if (!strcmp(argv[1], "--replace-all"))
+
+			return git_config_set_multivar(argv[2], argv[3], NULL, 1);
 		else
-			return git_config_set_multivar(argv[1], argv[2], argv[3]);
+
+			return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
+	case 5:
+		if (!strcmp(argv[1], "--replace-all"))
+			return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
+	case 1:
 	default:
 		usage(git_config_set_usage);
 	}
diff --git a/config.c b/config.c
index bbcafff..697d79f 100644
--- a/config.c
+++ b/config.c
@@ -263,11 +263,15 @@ int git_config(config_fn_t fn)
 /*
  * Find all the stuff for git_config_set() below.
  */
+
+#define MAX_MATCHES 512
+
 static struct {
 	int baselen;
 	char* key;
 	regex_t* value_regex;
-	off_t offset;
+	int multi_replace;
+	off_t offset[MAX_MATCHES];
 	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
 	int seen;
 } store;
@@ -279,12 +283,16 @@ static int store_aux(const char* key, co
 		if (!strcmp(key, store.key) &&
 				(store.value_regex == NULL ||
 				!regexec(store.value_regex, value, 0, NULL, 0))) {
-			if (store.seen == 1) {
+			if (store.seen == 1 && store.multi_replace == 0) {
 				fprintf(stderr,
 					"Warning: %s has multiple values\n",
 					key);
+			} else if (store.seen >= MAX_MATCHES) {
+				fprintf(stderr, "Too many matches\n");
+				return 1;
 			}
-			store.offset = ftell(config_file);
+
+			store.offset[store.seen] = ftell(config_file);
 			store.seen++;
 		}
 		break;
@@ -293,14 +301,15 @@ static int store_aux(const char* key, co
 			store.state = SECTION_END_SEEN;
 			break;
 		} else
-			store.offset = ftell(config_file);
+			/* do not increment matches: this is no match */
+			store.offset[store.seen] = ftell(config_file);
 		/* fallthru */
 	case SECTION_END_SEEN:
 	case START:
 		if (!strcmp(key, store.key) &&
 				(store.value_regex == NULL ||
 				!regexec(store.value_regex, value, 0, NULL, 0))) {
-			store.offset = ftell(config_file);
+			store.offset[store.seen] = ftell(config_file);
 			store.state = KEY_SEEN;
 			store.seen++;
 		} else if(!strncmp(key, store.key, store.baselen))
@@ -334,14 +343,38 @@ static void store_write_pair(int fd, con
 	write(fd, "\n", 1);
 }
 
+static int find_beginning_of_line(const char* contents, int size,
+	int offset_, int* found_bracket)
+{
+	int equal_offset = size, bracket_offset = size;
+	int offset;
+
+	for (offset = offset_-2; offset > 0 
+			&& contents[offset] != '\n'; offset--)
+		switch (contents[offset]) {
+			case '=': equal_offset = offset; break;
+			case ']': bracket_offset = offset; break;
+		}
+	if (bracket_offset < equal_offset) {
+		*found_bracket = 1;
+		offset = bracket_offset+1;
+	} else
+		offset++;
+
+	return offset;
+}
+
 int git_config_set(const char* key, const char* value)
 {
-	return git_config_set_multivar(key, value, NULL);
+	return git_config_set_multivar(key, value, NULL, 0);
 }
 
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
+ * if multi_replace==0, nothing, or only one matching key/value is replaced,
+ *     else all matching key/values (regardless how many) are removed,
+ *     before the new pair is written.
  *
  * Returns 0 on success.
  *
@@ -360,7 +393,7 @@ int git_config_set(const char* key, cons
  *
  */
 int git_config_set_multivar(const char* key, const char* value,
-	const char* value_regex)
+	const char* value_regex, int multi_replace)
 {
 	int i;
 	struct stat st;
@@ -368,6 +401,8 @@ int git_config_set_multivar(const char* 
 	char* config_file = strdup(git_path("config"));
 	char* lock_file = strdup(git_path("config.lock"));
 
+	store.multi_replace = multi_replace;
+
 	/*
 	 * Since "key" actually contains the section name and the real
 	 * key name separated by a dot, we have to know where the dot is.
@@ -431,7 +466,7 @@ int git_config_set_multivar(const char* 
 	} else{
 		int in_fd;
 		char* contents;
-		int offset, new_line = 0;
+		int i, copy_begin, copy_end, new_line = 0;
 
 		if (value_regex == NULL)
 			store.value_regex = NULL;
@@ -446,7 +481,7 @@ int git_config_set_multivar(const char* 
 			}
 		}
 
-		store.offset = 0;
+		store.offset[0] = 0;
 		store.state = START;
 		store.seen = 0;
 
@@ -472,52 +507,42 @@ int git_config_set_multivar(const char* 
 			free(store.value_regex);
 		}
 
-		/* if nothing to unset, error out */
-		if (store.seen == 0 && value == NULL) {
+		/* if nothing to unset, or too many matches, error out */
+		if ((store.seen == 0 && value == NULL) ||
+				(store.seen > 1 && multi_replace == 0)) {
 			close(fd);
 			unlink(lock_file);
 			return 5;
 		}
 
-		store.key = (char*)key;
-
 		in_fd = open(config_file, O_RDONLY, 0666);
 		contents = mmap(NULL, st.st_size, PROT_READ,
 			MAP_PRIVATE, in_fd, 0);
 		close(in_fd);
 
-		if (store.offset == 0) {
-			store.offset = offset = st.st_size;
-		} else if (store.state != KEY_SEEN) {
-			offset = store.offset;
-		} else {
-			int equal_offset = st.st_size,
-				bracket_offset = st.st_size;
-
-			if (value == NULL && store.seen > 1) {
-				fprintf(stderr, "Cannot remove multivar (%s has %d values\n", key, store.seen);
-				close(fd);
-				unlink(lock_file);
-				return 7;
-			}
-			for (offset = store.offset-2; offset > 0 
-					&& contents[offset] != '\n'; offset--)
-				switch (contents[offset]) {
-				case '=': equal_offset = offset; break;
-				case ']': bracket_offset = offset; break;
-				}
-			if (bracket_offset < equal_offset) {
-				new_line = 1;
-				offset = bracket_offset+1;
+		if (store.seen == 0)
+			store.seen = 1;
+
+		for (i = 0, copy_begin = 0; i < store.seen; i++) {
+			if (store.offset[i] == 0) {
+				store.offset[i] = copy_end = st.st_size;
+			} else if (store.state != KEY_SEEN) {
+				copy_end = store.offset[i];
 			} else
-				offset++;
+				copy_end = find_beginning_of_line(
+					contents, st.st_size,
+					store.offset[i]-2, &new_line);
+
+			/* write the first part of the config */
+			if (copy_end > copy_begin) {
+				write(fd, contents + copy_begin,
+				copy_end - copy_begin);
+				if (new_line)
+					write(fd, "\n", 1);
+			}
+			copy_begin = store.offset[i];
 		}
 
-		/* write the first part of the config */
-		write(fd, contents, offset);
-		if (new_line)
-			write(fd, "\n", 1);
-
 		/* write the pair (value == NULL means unset) */
 		if (value != NULL) {
 			if (store.state == START)
@@ -526,9 +551,9 @@ int git_config_set_multivar(const char* 
 		}
 
 		/* write the rest of the config */
-		if (store.offset < st.st_size)
-			write(fd, contents + store.offset,
-				st.st_size - store.offset);
+		if (copy_begin < st.st_size)
+			write(fd, contents + copy_begin,
+				st.st_size - copy_begin);
 
 		munmap(contents, st.st_size);
 		unlink(config_file);
@@ -544,3 +569,4 @@ int git_config_set_multivar(const char* 
 	return 0;
 }
 
+
diff --git a/t1300-config-set.sh b/t/t1300-config-set.sh
similarity index 100%
rename from t1300-config-set.sh
rename to t/t1300-config-set.sh
index df89216..717bf4d 100644
--- a/t1300-config-set.sh
+++ b/t/t1300-config-set.sh
@@ -76,9 +76,44 @@ noIndent= sillyValue ; 'nother silly com
 # empty line
 		; comment
 		haha   ="beta" # last silly comment
+haha = hello
+	haha = bello
 [nextSection] noNewline = ouch
 EOF
 
+cp .git/config .git/config2
+
+test_expect_success 'multiple unset' \
+	'git-config-set --unset-all beta.haha'
+
+cat > expect << EOF
+[beta] ; silly comment # another comment
+noIndent= sillyValue ; 'nother silly comment
+
+# empty line
+		; comment
+[nextSection] noNewline = ouch
+EOF
+
+test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
+
+mv .git/config2 .git/config
+
+test_expect_success '--replace-all' \
+	'git-config-set --replace-all beta.haha gamma'
+
+cat > expect << EOF
+[beta] ; silly comment # another comment
+noIndent= sillyValue ; 'nother silly comment
+
+# empty line
+		; comment
+	haha = gamma
+[nextSection] noNewline = ouch
+EOF
+
+test_expect_success 'all replaced' 'cmp .git/config expect'
+
 git-config-set beta.haha alpha
 
 cat > expect << EOF
@@ -108,7 +143,8 @@ EOF
 
 test_expect_success 'really really mean test' 'cmp .git/config expect'
 
-git-config-set beta.haha
+test_expect_success 'get value' 'test alpha = $(git-config-set beta.haha)'
+git-config-set --unset beta.haha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -137,6 +173,12 @@ EOF
 
 test_expect_success 'multivar' 'cmp .git/config expect'
 
+test_expect_failure 'ambiguous get' \
+	'git-config-set --get nextsection.nonewline'
+
+test_expect_success 'get multivar' \
+	'git-config-set --get-all nextsection.nonewline'
+
 git-config-set nextsection.nonewline "wow3" "wow$"
 
 cat > expect << EOF
@@ -152,6 +194,8 @@ EOF
 
 test_expect_success 'multivar replace' 'cmp .git/config expect'
 
+test_expect_failure 'ambiguous value' 'git-config-set nextsection.nonewline'
+
 test_expect_failure 'ambiguous unset' \
 	'git-config-set --unset nextsection.nonewline'
 

^ permalink raw reply related	[relevance 7%]

* [PATCH] Fix sparse warnings
@ 2005-11-21  0:52 11% Timo Hirvonen
  0 siblings, 0 replies; 200+ results
From: Timo Hirvonen @ 2005-11-21  0:52 UTC (permalink / raw)
  To: git, junkio


Make some functions static and convert func() function prototypes to to
func(void).  Fix declaration after statement, missing declaration and
redundant declaration warnings.

Signed-off-by: Timo Hirvonen <tihirvon@gmail.com>

---

 cache.h          |    1 +
 name-rev.c       |    2 --
 pack-redundant.c |   58 +++++++++++++++++++++++++++---------------------------
 path.c           |    2 +-
 4 files changed, 31 insertions(+), 32 deletions(-)

applies-to: e12ceef6841365e64bb765294235a67e9263d7de
b29cab489ba0dbd6daf69b491978615a1a96f781
diff --git a/cache.h b/cache.h
index a7c1bbd..c7c6637 100644
--- a/cache.h
+++ b/cache.h
@@ -203,6 +203,7 @@ int git_mkstemp(char *path, size_t n, co
 
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
+char *enter_repo(char *path, int strict);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
diff --git a/name-rev.c b/name-rev.c
index 59194f1..817e36b 100644
--- a/name-rev.c
+++ b/name-rev.c
@@ -230,8 +230,6 @@ int main(int argc, char **argv)
 				fwrite(p_start, p - p_start, 1, stdout);
 		}
 	} else if (all) {
-		extern struct object **objs;
-		extern int nr_objs;
 		int i;
 
 		for (i = 0; i < nr_objs; i++)
diff --git a/pack-redundant.c b/pack-redundant.c
index fb6cb48..1519385 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -11,19 +11,19 @@
 static const char pack_redundant_usage[] =
 "git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
 
-int load_all_packs = 0, verbose = 0, alt_odb = 0;
+static int load_all_packs = 0, verbose = 0, alt_odb = 0;
 
 struct llist_item {
 	struct llist_item *next;
 	char *sha1;
 };
-struct llist {
+static struct llist {
 	struct llist_item *front;
 	struct llist_item *back;
 	size_t size;
 } *all_objects; /* all objects which must be present in local packfiles */
 
-struct pack_list {
+static struct pack_list {
 	struct pack_list *next;
 	struct packed_git *pack;
 	struct llist *unique_objects;
@@ -36,7 +36,7 @@ struct pll {
 	size_t pl_size;
 };
 
-inline void llist_free(struct llist *list)
+static inline void llist_free(struct llist *list)
 {
 	while((list->back = list->front)) {
 		list->front = list->front->next;
@@ -45,14 +45,14 @@ inline void llist_free(struct llist *lis
 	free(list);
 }
 
-inline void llist_init(struct llist **list)
+static inline void llist_init(struct llist **list)
 {
 	*list = xmalloc(sizeof(struct llist));
 	(*list)->front = (*list)->back = NULL;
 	(*list)->size = 0;
 }
 
-struct llist * llist_copy(struct llist *list)
+static struct llist * llist_copy(struct llist *list)
 {
 	struct llist *ret;
 	struct llist_item *new, *old, *prev;
@@ -79,7 +79,7 @@ struct llist * llist_copy(struct llist *
 	return ret;
 }
 
-inline struct llist_item * llist_insert(struct llist *list,
+static inline struct llist_item * llist_insert(struct llist *list,
 					struct llist_item *after, char *sha1)
 {
 	struct llist_item *new = xmalloc(sizeof(struct llist_item));
@@ -102,12 +102,12 @@ inline struct llist_item * llist_insert(
 	return new;
 }
 
-inline struct llist_item * llist_insert_back(struct llist *list, char *sha1)
+static inline struct llist_item * llist_insert_back(struct llist *list, char *sha1)
 {
 	return llist_insert(list, list->back, sha1);
 }
 
-inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
+static inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
 					char *sha1, struct llist_item *hint)
 {
 	struct llist_item *prev = NULL, *l;
@@ -129,7 +129,7 @@ inline struct llist_item * llist_insert_
 }
 
 /* returns a pointer to an item in front of sha1 */
-inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
+static inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
 					       struct llist_item *hint)
 {
 	struct llist_item *prev, *l;
@@ -164,7 +164,7 @@ redo_from_start:
 }
 
 /* computes A\B */
-void llist_sorted_difference_inplace(struct llist *A,
+static void llist_sorted_difference_inplace(struct llist *A,
 				     struct llist *B)
 {
 	struct llist_item *hint, *b;
@@ -178,7 +178,7 @@ void llist_sorted_difference_inplace(str
 	}
 }
 
-inline struct pack_list * pack_list_insert(struct pack_list **pl,
+static inline struct pack_list * pack_list_insert(struct pack_list **pl,
 					   struct pack_list *entry)
 {
 	struct pack_list *p = xmalloc(sizeof(struct pack_list));
@@ -188,7 +188,7 @@ inline struct pack_list * pack_list_inse
 	return p;
 }
 
-inline size_t pack_list_size(struct pack_list *pl)
+static inline size_t pack_list_size(struct pack_list *pl)
 {
 	size_t ret = 0;
 	while(pl) {
@@ -198,7 +198,7 @@ inline size_t pack_list_size(struct pack
 	return ret;
 }
 
-struct pack_list * pack_list_difference(struct pack_list *A,
+static struct pack_list * pack_list_difference(struct pack_list *A,
 					struct pack_list *B)
 {
 	struct pack_list *ret, *pl;
@@ -218,7 +218,7 @@ struct pack_list * pack_list_difference(
 	return ret;
 }
 
-void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
+static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
 {
 	int p1_off, p2_off;
 	void *p1_base, *p2_base;
@@ -250,7 +250,7 @@ void cmp_two_packs(struct pack_list *p1,
 	}
 }
 
-void pll_insert(struct pll **pll, struct pll **hint_table)
+static void pll_insert(struct pll **pll, struct pll **hint_table)
 {
 	struct pll *prev;
 	int i = (*pll)->pl_size - 1;
@@ -276,7 +276,7 @@ void pll_insert(struct pll **pll, struct
 /* all the permutations have to be free()d at the same time,
  * since they refer to each other
  */
-struct pll * get_all_permutations(struct pack_list *list)
+static struct pll * get_all_permutations(struct pack_list *list)
 {
 	struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
 	static struct pll **hint = NULL;
@@ -323,7 +323,7 @@ struct pll * get_all_permutations(struct
 	return hint[0];
 }
 
-int is_superset(struct pack_list *pl, struct llist *list)
+static int is_superset(struct pack_list *pl, struct llist *list)
 {
 	struct llist *diff;
 
@@ -342,7 +342,7 @@ int is_superset(struct pack_list *pl, st
 	return 0;
 }
 
-size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
+static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
 {
 	size_t ret = 0;
 	int p1_off, p2_off;
@@ -373,14 +373,14 @@ size_t sizeof_union(struct packed_git *p
 }
 
 /* another O(n^2) function ... */
-size_t get_pack_redundancy(struct pack_list *pl)
+static size_t get_pack_redundancy(struct pack_list *pl)
 {
 	struct pack_list *subset;
+	size_t ret = 0;
 
 	if (pl == NULL)
 		return 0;
 
-	size_t ret = 0;
 	while ((subset = pl->next)) {
 		while(subset) {
 			ret += sizeof_union(pl->pack, subset->pack);
@@ -391,7 +391,7 @@ size_t get_pack_redundancy(struct pack_l
 	return ret;
 }
 
-inline size_t pack_set_bytecount(struct pack_list *pl)
+static inline size_t pack_set_bytecount(struct pack_list *pl)
 {
 	size_t ret = 0;
 	while (pl) {
@@ -402,7 +402,7 @@ inline size_t pack_set_bytecount(struct 
 	return ret;
 }
 
-void minimize(struct pack_list **min)
+static void minimize(struct pack_list **min)
 {
 	struct pack_list *pl, *unique = NULL,
 		*non_unique = NULL, *min_perm = NULL;
@@ -469,7 +469,7 @@ void minimize(struct pack_list **min)
 	}
 }
 
-void load_all_objects()
+static void load_all_objects(void)
 {
 	struct pack_list *pl = local_packs;
 	struct llist_item *hint, *l;
@@ -497,7 +497,7 @@ void load_all_objects()
 }
 
 /* this scales like O(n^2) */
-void cmp_local_packs()
+static void cmp_local_packs(void)
 {
 	struct pack_list *subset, *pl = local_packs;
 
@@ -508,7 +508,7 @@ void cmp_local_packs()
 	}
 }
 
-void scan_alt_odb_packs()
+static void scan_alt_odb_packs(void)
 {
 	struct pack_list *local, *alt;
 
@@ -524,7 +524,7 @@ void scan_alt_odb_packs()
 	}
 }
 
-struct pack_list * add_pack(struct packed_git *p)
+static struct pack_list * add_pack(struct packed_git *p)
 {
 	struct pack_list l;
 	size_t off;
@@ -550,7 +550,7 @@ struct pack_list * add_pack(struct packe
 		return pack_list_insert(&altodb_packs, &l);
 }
 
-struct pack_list * add_pack_file(char *filename)
+static struct pack_list * add_pack_file(char *filename)
 {
 	struct packed_git *p = packed_git;
 
@@ -565,7 +565,7 @@ struct pack_list * add_pack_file(char *f
 	die("Filename %s not found in packed_git\n", filename);
 }
 
-void load_all()
+static void load_all(void)
 {
 	struct packed_git *p = packed_git;
 
diff --git a/path.c b/path.c
index d635470..84b3272 100644
--- a/path.c
+++ b/path.c
@@ -131,7 +131,7 @@ int validate_symref(const char *path)
 	return -1;
 }
 
-static char *current_dir()
+static char *current_dir(void)
 {
 	return getcwd(pathname, sizeof(pathname));
 }
---
0.99.9.GIT

^ permalink raw reply related	[relevance 11%]

* [PATCH] enter_repo missing its prototype
@ 2005-11-21  8:14 19% Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2005-11-21  8:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 88 bytes --]

enter_repo was missing its prototype

Signed-off-by: Alex Riesen <ariesen@gmail.com>

[-- Attachment #2: 0001-enter_repo-missing-its-prototype.txt --]
[-- Type: text/plain, Size: 935 bytes --]

Subject: [PATCH] enter_repo missing its prototype
(cherry picked from 00de97b561c4114e89a8d2f5c8af08403278d8fa commit)

Signed-off-by: Alex Riesen <ariesen@harmanbecker.com>


---

 cache.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

applies-to: e12ceef6841365e64bb765294235a67e9263d7de
64c38741ba2b5840990b695ec3dbaa51a3427c4b
diff --git a/cache.h b/cache.h
index a7c1bbd..80f69a7 100644
--- a/cache.h
+++ b/cache.h
@@ -204,6 +204,8 @@ int git_mkstemp(char *path, size_t n, co
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
 
+extern char *enter_repo(char *path, int strict);
+
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
 extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
---
0.99.9.GIT

^ permalink raw reply related	[relevance 19%]

* [PATCH 1/6] Add GIT_REPO_VERSION, and repository_format_version
    2005-11-22  0:28 19% ` [PATCH 3/6] Make get_git_dir take a flag that makes it re-read the env. variables Martin Atukunda
@ 2005-11-22  0:28 19% ` Martin Atukunda
  2005-11-22  0:28 18% ` [PATCH 5/6] Allow Specification of the conf file to read for git_config operations Martin Atukunda
  2 siblings, 0 replies; 200+ results
From: Martin Atukunda @ 2005-11-22  0:28 UTC (permalink / raw)
  To: git; +Cc: Martin Atukunda

This variable will enable git to track the repository version. It's
currently set to 0. (in true C style :)

Signed-Off-By: Martin Atukunda <matlads@dsmagic.com>

---

 cache.h       |    4 ++++
 environment.c |    1 +
 2 files changed, 5 insertions(+), 0 deletions(-)

applies-to: 339319e60db7b3f96f8c711407b135a54da7aa2e
976b8d57a80d79853df9c142ba30d39b414e1b8e
diff --git a/cache.h b/cache.h
index c7c6637..54c283d 100644
--- a/cache.h
+++ b/cache.h
@@ -182,6 +182,10 @@ extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 
+#define GIT_REPO_VERSION 0
+extern int repository_format_version;
+extern int check_repo_format(void);
+
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
 #define OWNER_CHANGED	0x0004
diff --git a/environment.c b/environment.c
index b5026f1..3f19473 100644
--- a/environment.c
+++ b/environment.c
@@ -13,6 +13,7 @@ char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
+int repository_format_version = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
---
0.99.9.GIT

^ permalink raw reply related	[relevance 19%]

* [PATCH 3/6] Make get_git_dir take a flag that makes it re-read the env. variables
  @ 2005-11-22  0:28 19% ` Martin Atukunda
  2005-11-22  0:28 19% ` [PATCH 1/6] Add GIT_REPO_VERSION, and repository_format_version Martin Atukunda
  2005-11-22  0:28 18% ` [PATCH 5/6] Allow Specification of the conf file to read for git_config operations Martin Atukunda
  2 siblings, 0 replies; 200+ results
From: Martin Atukunda @ 2005-11-22  0:28 UTC (permalink / raw)
  To: git; +Cc: Martin Atukunda

Signed-Off-By: Martin Atukunda <matlads@dsmagic.com>

---

 cache.h       |    2 +-
 environment.c |    4 ++--
 path.c        |    2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

applies-to: 0748fd804fbe155503235e2c36d812fc3ef641a0
e3973791e841440ad92d91340fd954b5a58101c7
diff --git a/cache.h b/cache.h
index 54c283d..a455373 100644
--- a/cache.h
+++ b/cache.h
@@ -138,7 +138,7 @@ extern unsigned int active_nr, active_al
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
 
-extern char *get_git_dir(void);
+extern char *get_git_dir(int recheck_env);
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
 extern char *get_index_file(void);
diff --git a/environment.c b/environment.c
index 3f19473..6a961ca 100644
--- a/environment.c
+++ b/environment.c
@@ -39,9 +39,9 @@ static void setup_git_env(void)
 		git_graft_file = strdup(git_path("info/grafts"));
 }
 
-char *get_git_dir(void)
+char *get_git_dir(int recheck_env)
 {
-	if (!git_dir)
+	if (!git_dir || recheck_env)
 		setup_git_env();
 	return git_dir;
 }
diff --git a/path.c b/path.c
index 4d88947..e322dc0 100644
--- a/path.c
+++ b/path.c
@@ -42,7 +42,7 @@ char *mkpath(const char *fmt, ...)
 
 char *git_path(const char *fmt, ...)
 {
-	const char *git_dir = get_git_dir();
+	const char *git_dir = get_git_dir(0);
 	va_list args;
 	unsigned len;
 
---
0.99.9.GIT

^ permalink raw reply related	[relevance 19%]

* [PATCH 5/6] Allow Specification of the conf file to read for git_config operations
    2005-11-22  0:28 19% ` [PATCH 3/6] Make get_git_dir take a flag that makes it re-read the env. variables Martin Atukunda
  2005-11-22  0:28 19% ` [PATCH 1/6] Add GIT_REPO_VERSION, and repository_format_version Martin Atukunda
@ 2005-11-22  0:28 18% ` Martin Atukunda
  2 siblings, 0 replies; 200+ results
From: Martin Atukunda @ 2005-11-22  0:28 UTC (permalink / raw)
  To: git; +Cc: Martin Atukunda

This patch adds a git_config_from_file which allows us to specify the
config file to use for git_config operations.

Signed-Off-By: Martin Atukunda <matlads@dsmagic.com>

---

 cache.h  |    1 +
 config.c |   10 +++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

applies-to: d6c3faa0566795b1c74e693ecc004439c116e6c6
39e4ab307abb445115f3c9ee0e09ed1812568247
diff --git a/cache.h b/cache.h
index a455373..48018ab 100644
--- a/cache.h
+++ b/cache.h
@@ -388,6 +388,7 @@ extern int gitfakemunmap(void *start, si
 
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
+extern int git_config_from_file(const char *, config_fn_t fn);
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
diff --git a/config.c b/config.c
index 5d237c8..c5a5312 100644
--- a/config.c
+++ b/config.c
@@ -245,11 +245,10 @@ int git_default_config(const char *var, 
 	return 0;
 }
 
-int git_config(config_fn_t fn)
+int git_config_from_file(const char *confpath, config_fn_t fn)
 {
 	int ret;
-	FILE *f = fopen(git_path("config"), "r");
-
+	FILE *f = fopen(confpath, "r");
 	ret = -1;
 	if (f) {
 		config_file = f;
@@ -260,6 +259,11 @@ int git_config(config_fn_t fn)
 	return ret;
 }
 
+int git_config(config_fn_t fn)
+{
+	return git_config_from_file(git_path("config"), fn);
+}
+
 /*
  * Find all the stuff for git_config_set() below.
  */
---
0.99.9.GIT

^ permalink raw reply related	[relevance 18%]

* [RFC/PATCH 1/3] git-find-git: a new helper.
@ 2005-11-24  3:36 12% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-24  3:36 UTC (permalink / raw)
  To: git; +Cc: Martin Atukunda

This is part of rev-format check work, which is currently my top
priority that is holding up any new 1.0rc updates to maint
branch.  It adds a new helper, git-find-git command, to the
suite, and rewrites git-sh-setup to use it.

It adds setup_git_directory_gently(), which is a variant of
existing setup_git_directory() but does not die() if we are not
in a git managed repository.  git-find-git uses it to find the
top-level, and if it was run from a subdirectory, outputs shell
script fragments that can be evaled to define the two variables:

    GIT_DIR_PREFIX is a string to be prepended to cwd relative
    paths to make them repository relative.

    GIT_DIR_UPLEVEL is a string (e.g. "../") for the command to
    use to cd to the top-level of repository.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Makefile        |    2 +-
 cache.h         |    1 +
 find-git.c      |   41 +++++++++++++++++++++++++++++++++++++++++
 git-sh-setup.sh |   39 ++++++++++++++++++++++++++++-----------
 setup.c         |   14 ++++++++++++--
 5 files changed, 83 insertions(+), 14 deletions(-)
 create mode 100644 find-git.c

applies-to: 10227b43e837a38d95d472a0b7c400749fbd46e9
15d4e27b74f4ff0c9faa5bbbfe8e915398f3be97
diff --git a/Makefile b/Makefile
index a97a5d9..dda363a 100644
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)
 # The ones that do not have to link with lcrypto nor lz.
 SIMPLE_PROGRAMS = \
 	git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
-	git-stripspace$X git-daemon$X
+	git-stripspace$X git-daemon$X git-find-git$X
 
 # ... and all the rest
 PROGRAMS = \
diff --git a/cache.h b/cache.h
index 6ac94c5..3104c59 100644
--- a/cache.h
+++ b/cache.h
@@ -148,6 +148,7 @@ extern char *get_graft_file(void);
 
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
 extern const char *setup_git_directory(void);
+extern const char *setup_git_directory_gently(int *);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
 
 #define alloc_nr(x) (((x)+16)*3/2)
diff --git a/find-git.c b/find-git.c
new file mode 100644
index 0000000..e063425
--- /dev/null
+++ b/find-git.c
@@ -0,0 +1,41 @@
+#include "cache.h"
+#include "quote.h"
+
+int main(int ac, char **av)
+{
+	int not_a_git = 0;
+	const char *prefix = setup_git_directory_gently(&not_a_git);
+
+	if (!prefix && not_a_git)
+		exit(1);
+
+	/* This can die with malformed configuration file --
+	 * exit code from die() is 128.
+	 */
+	git_config(git_default_config);
+
+	/* Later we check repository version and exit with non-zero
+	 * status after issuing an error message here.
+	 */
+
+	if (!prefix)
+		/* we are at the project toplevel or GIT_DIR is set.
+		 * either case we do not have to muck with the
+		 * environment further.
+		 */
+		exit(0);
+
+	/* this leaks but we do not care ;-) */
+	printf("GIT_DIR_PREFIX=%s\n", sq_quote(prefix));
+	printf("GIT_DIR_UPLEVEL='");
+	while (prefix) {
+		prefix = strchr(prefix, '/');
+		if (prefix) {
+			prefix++;
+			printf("../");
+		}
+	}
+	printf("'\n");
+	printf("export GIT_DIR_PREFIX GIT_DIR_UPLEVEL\n");
+	exit(0);
+}
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index dbb9884..8e30bf6 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -3,13 +3,11 @@
 # Set up GIT_DIR and GIT_OBJECT_DIRECTORY
 # and return true if everything looks ok
 #
-: ${GIT_DIR=.git}
-: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
 
 # Having this variable in your environment would break scripts because
-# you would cause "cd" to be be taken to unexpected places.  If you
-# like CDPATH, define it for your interactive shell sessions without
-# exporting it.
+# you would cause "cd" to be taken to unexpected places.  If you line
+# CDPATH, define it for your interactive shell sessions without exporting
+# it.
 unset CDPATH
 
 die() {
@@ -17,9 +15,28 @@ die() {
 	exit 1
 }
 
-case "$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD 2>/dev/null)" in
-refs/*)	: ;;
-*)	false ;;
-esac &&
-[ -d "$GIT_DIR/refs" ] &&
-[ -d "$GIT_OBJECT_DIRECTORY/" ]
+eval "`git-find-git`"
+case "$?" in
+0)
+	: ${GIT_DIR=.git}
+	: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+
+	case "$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD 2>/dev/null)" in
+	refs/*)	: ;;
+	*)	false ;;
+	esac &&
+	[ -d "$GIT_DIR/refs" ] &&
+	[ -d "$GIT_OBJECT_DIRECTORY/" ]
+	;;
+*)
+	# (1) we did not find a git directory.  This is sometimes OK.
+	# ls-remote (and parse-remote called from it) uses sh-set to
+	# pick up remotes shortcut if available, but outside git the
+	# user would want to use the command with explicitly spelled
+	# out URL.
+
+	# (128) git-find-git died -- malformed configuration and that
+	# is really fatal.  We have already given the error message.
+
+	;;
+esac
diff --git a/setup.c b/setup.c
index c487d7e..f64ca23 100644
--- a/setup.c
+++ b/setup.c
@@ -92,7 +92,7 @@ static int is_toplevel_directory(void)
 	return 1;
 }
 
-const char *setup_git_directory(void)
+const char *setup_git_directory_gently(int *just_fail_on_ungit)
 {
 	static char cwd[PATH_MAX+1];
 	int len, offset;
@@ -113,8 +113,13 @@ const char *setup_git_directory(void)
 			break;
 		chdir("..");
 		do {
-			if (!offset)
+			if (!offset) {
+				if (just_fail_on_ungit) {
+					*just_fail_on_ungit = 1;
+					return NULL;
+				}
 				die("Not a git repository");
+			}
 		} while (cwd[--offset] != '/');
 	}
 
@@ -127,3 +132,8 @@ const char *setup_git_directory(void)
 	cwd[len] = 0;
 	return cwd + offset;
 }
+
+const char *setup_git_directory(void)
+{
+	return setup_git_directory_gently(NULL);
+}
---
0.99.9.GIT

^ permalink raw reply related	[relevance 12%]

* [RFC/PATCH 2/3] Add GIT_REPO_VERSION, and repository_format_version
@ 2005-11-24  3:36 19% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-24  3:36 UTC (permalink / raw)
  To: git

From: Martin Atukunda <matlads@dsmagic.com>
Date: 1132619292 +0300

This variable will enable git to track the repository version. It's
currently set to 0. (in true C style :)

Signed-off-by: Martin Atukunda <matlads@dsmagic.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>

---
 * This is verbatim as I received from Martin.

 cache.h       |    4 ++++
 environment.c |    1 +
 2 files changed, 5 insertions(+), 0 deletions(-)

applies-to: 787c201a1691219d30c1a3fd849dc5ee9b35e2ce
abb173e753857d7360ae7ff1869be8d96e353ba7
diff --git a/cache.h b/cache.h
index 3104c59..7cde341 100644
--- a/cache.h
+++ b/cache.h
@@ -183,6 +183,10 @@ extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 
+#define GIT_REPO_VERSION 0
+extern int repository_format_version;
+extern int check_repo_format(void);
+
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
 #define OWNER_CHANGED	0x0004
diff --git a/environment.c b/environment.c
index b5026f1..3f19473 100644
--- a/environment.c
+++ b/environment.c
@@ -13,6 +13,7 @@ char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
+int repository_format_version = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
---
0.99.9.GIT

^ permalink raw reply related	[relevance 19%]

* [RFC/PATCH 3/3] Check repository format version.
@ 2005-11-24  3:36 14% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-24  3:36 UTC (permalink / raw)
  To: git; +Cc: Martin Atukunda

Add check_repository_format() that is to be called when we know
where the configuration file is and die if the format version
is too new to be understood by us.

Use it in enter_repo(), setup_git_directory(), and git-find-git
to prevent the commands that use them to corrupt future git
repositories.  What this patch does not cover are commands that
implicitly assumes it is always run from the toplevel, or the
user tells us where the git directory is with the GIT_DIR
environment variable.

setup_git_directory() users that could corrupt future repository
without this change are:

	config-set symbolic-ref update-index update-ref

and that could yield incorrect results are:

	cat-file diff-files diff-index diff-stages diff-tree
	ls-files name-rev rev-list rev-parse show-branch

enter_repo() users are:

	daemon receive-pack upload-pack

git-find-git is used by git-sh-setup, which means most of the
barebone Porcelain scripts are covered with this change upfront.
This might be enough for everyday use to futureproof us.

The repository format check code was originally done by Martin
Atukunda.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * The checks in this version is less intrusive compared to
   Martin's version, and tries to check only once when we know
   where the configuration file should be.

 cache.h         |    2 +-
 find-git.c      |    5 +++--
 git-sh-setup.sh |    2 +-
 path.c          |    1 +
 setup.c         |   24 ++++++++++++++++++++++--
 5 files changed, 28 insertions(+), 6 deletions(-)

applies-to: cfcbe85286bb9bfb4f04169269c543640626218d
08279559b1d63107c4e25abb4c882ad21e1ad43b
diff --git a/cache.h b/cache.h
index 7cde341..c3e46f3 100644
--- a/cache.h
+++ b/cache.h
@@ -185,7 +185,7 @@ extern int diff_rename_limit_default;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
-extern int check_repo_format(void);
+extern int check_repository_format(void);
 
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
diff --git a/find-git.c b/find-git.c
index e063425..430ba7c 100644
--- a/find-git.c
+++ b/find-git.c
@@ -14,9 +14,10 @@ int main(int ac, char **av)
 	 */
 	git_config(git_default_config);
 
-	/* Later we check repository version and exit with non-zero
-	 * status after issuing an error message here.
+	/* This would die after issuing an error message if we 
+	 * do not understand the repository format.
 	 */
+	check_repository_format();
 
 	if (!prefix)
 		/* we are at the project toplevel or GIT_DIR is set.
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 8e30bf6..2485bb9 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -37,6 +37,6 @@ case "$?" in
 
 	# (128) git-find-git died -- malformed configuration and that
 	# is really fatal.  We have already given the error message.
-
+	exit $?
 	;;
 esac
diff --git a/path.c b/path.c
index 4d88947..2c077c0 100644
--- a/path.c
+++ b/path.c
@@ -199,6 +199,7 @@ char *enter_repo(char *path, int strict)
 	if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 	   validate_symref("HEAD") == 0) {
 		putenv("GIT_DIR=.");
+		check_repository_format();
 		return current_dir();
 	}
 
diff --git a/setup.c b/setup.c
index f64ca23..48be931 100644
--- a/setup.c
+++ b/setup.c
@@ -73,7 +73,7 @@ const char **get_pathspec(const char *pr
 }
 
 /*
- * Test it it looks like we're at the top
+ * Test if it looks like we're at the top
  * level git directory. We want to see a
  *
  *  - either a .git/objects/ directory _or_ the proper
@@ -135,5 +135,25 @@ const char *setup_git_directory_gently(i
 
 const char *setup_git_directory(void)
 {
-	return setup_git_directory_gently(NULL);
+	const char *retval = setup_git_directory_gently(NULL);
+	check_repository_format();
+	return retval;
+}
+
+static int check_repository_format_version(const char *var, const char *value)
+{
+       if (strcmp(var, "core.repositoryformatversion") == 0) {
+               repository_format_version = git_config_int(var, value);
+       }
+       return 0;
+}
+
+int check_repository_format(void)
+{
+	if (git_config(check_repository_format_version) == -1)
+		return -1;
+	if (GIT_REPO_VERSION < repository_format_version)
+		die("Expected git repo version <= %d, found %d",
+		    GIT_REPO_VERSION, repository_format_version);
+	return 0;
 }
---
0.99.9.GIT

^ permalink raw reply related	[relevance 14%]

* [PATCH 1/4] Repository format version check.
@ 2005-11-26  1:15 18% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-26  1:15 UTC (permalink / raw)
  To: git

This adds the repository format version code, first done by
Martin Atukunda.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 cache.h       |    5 +++++
 environment.c |    1 +
 setup.c       |   16 ++++++++++++++++
 3 files changed, 22 insertions(+), 0 deletions(-)

applies-to: 31b3c7eeb719c61a19922f3e8bf5abd46b49b5bb
58fd7fb9718df942773862c9acd2358533c672d4
diff --git a/cache.h b/cache.h
index 6ac94c5..de53f41 100644
--- a/cache.h
+++ b/cache.h
@@ -182,6 +182,10 @@ extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 
+#define GIT_REPO_VERSION 0
+extern int repository_format_version;
+extern int check_repository_format(void);
+
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
 #define OWNER_CHANGED	0x0004
@@ -388,6 +392,7 @@ extern int git_config_int(const char *, 
 extern int git_config_bool(const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
+extern int check_repository_format_version(const char *var, const char *value);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
diff --git a/environment.c b/environment.c
index b5026f1..3f19473 100644
--- a/environment.c
+++ b/environment.c
@@ -13,6 +13,7 @@ char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
+int repository_format_version = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
diff --git a/setup.c b/setup.c
index ab3c778..0e2e3c8 100644
--- a/setup.c
+++ b/setup.c
@@ -154,6 +154,22 @@ static const char *setup_git_directory_1
 	return cwd + offset;
 }
 
+int check_repository_format_version(const char *var, const char *value)
+{
+       if (strcmp(var, "core.repositoryformatversion") == 0)
+               repository_format_version = git_config_int(var, value);
+       return 0;
+}
+
+int check_repository_format(void)
+{
+	git_config(check_repository_format_version);
+	if (GIT_REPO_VERSION < repository_format_version)
+		die ("Expected git repo version <= %d, found %d",
+		     GIT_REPO_VERSION, repository_format_version);
+	return 0;
+}
+
 const char *setup_git_directory(void)
 {
 	const char *retval = setup_git_directory_1();
---
0.99.9.GIT

^ permalink raw reply related	[relevance 18%]

* [PATCH 3/4] init-db: check template and repository format.
@ 2005-11-26  1:15 12% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-26  1:15 UTC (permalink / raw)
  To: git

This makes init-db repository version aware.

It checks if an existing config file says the repository being
reinitialized is of a wrong version and aborts before doing
further harm.

When copying the templates, it makes sure the they are of the
right repository format version.  Otherwise the templates are
ignored with an warning message.

It copies the templates before creating the HEAD, and if the
config file is copied from the template directory, reads it,
primarily to pick up the value of core.symrefsonly.

It changes the way the result of the filemode reliability test
is written to the configuration file using git_config_set().
The test is done even if the config file was copied from the
templates.

And finally, our own repository format version is written to the
config file.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 cache.h   |    1 +
 config.c  |   16 ++++++++---
 init-db.c |   89 +++++++++++++++++++++++++++++++++++--------------------------
 3 files changed, 64 insertions(+), 42 deletions(-)

applies-to: 3478f0c15277931430f7db669a8004da52c1a887
654494dfddb135db6187a3f00917e24c1dbcd569
diff --git a/cache.h b/cache.h
index de53f41..61bf884 100644
--- a/cache.h
+++ b/cache.h
@@ -387,6 +387,7 @@ extern int gitfakemunmap(void *start, si
 
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
+extern int git_config_from_file(config_fn_t fn, const char *);
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
diff --git a/config.c b/config.c
index 5cc8535..0c43d76 100644
--- a/config.c
+++ b/config.c
@@ -11,6 +11,7 @@
 #define MAXNAME (256)
 
 static FILE *config_file;
+static char *config_file_name;
 static int config_linenr;
 static int get_next_char(void)
 {
@@ -186,7 +187,7 @@ static int git_parse_file(config_fn_t fn
 		if (get_value(fn, var, baselen+1) < 0)
 			break;
 	}
-	die("bad config file line %d", config_linenr);
+	die("bad config file line %d in %s", config_linenr, config_file_name);
 }
 
 int git_config_int(const char *name, const char *value)
@@ -197,7 +198,7 @@ int git_config_int(const char *name, con
 		if (!*end)
 			return val;
 	}
-	die("bad config value for '%s'", name);
+	die("bad config value for '%s' in %s", name, config_file_name);
 }
 
 int git_config_bool(const char *name, const char *value)
@@ -240,21 +241,28 @@ int git_default_config(const char *var, 
 	return 0;
 }
 
-int git_config(config_fn_t fn)
+int git_config_from_file(config_fn_t fn, const char *filename)
 {
 	int ret;
-	FILE *f = fopen(git_path("config"), "r");
+	FILE *f = fopen(filename, "r");
 
 	ret = -1;
 	if (f) {
 		config_file = f;
+		config_file_name = filename;
 		config_linenr = 1;
 		ret = git_parse_file(fn);
 		fclose(f);
+		config_file_name = NULL;
 	}
 	return ret;
 }
 
+int git_config(config_fn_t fn)
+{
+	return git_config_from_file(fn, git_path("config"));
+}
+
 /*
  * Find all the stuff for git_config_set() below.
  */
diff --git a/init-db.c b/init-db.c
index bd88291..8195b68 100644
--- a/init-db.c
+++ b/init-db.c
@@ -132,6 +132,23 @@ static void copy_templates(const char *g
 		return;
 	}
 
+	/* Make sure that template is from the correct vintage */
+	strcpy(template_path + template_len, "config");
+	repository_format_version = 0;
+	git_config_from_file(check_repository_format_version,
+			     template_path);
+	template_path[template_len] = 0;
+
+	if (repository_format_version &&
+	    repository_format_version != GIT_REPO_VERSION) {
+		fprintf(stderr, "warning: not copying templates of "
+			"a wrong format version %d from '%s'\n",
+			repository_format_version,
+			template_dir);
+		closedir(dir);
+		return;
+	}
+
 	memcpy(path, git_dir, len);
 	path[len] = 0;
 	copy_templates_1(path, len,
@@ -140,12 +157,13 @@ static void copy_templates(const char *g
 	closedir(dir);
 }
 
-static void create_default_files(const char *git_dir,
-				 char *template_path)
+static void create_default_files(const char *git_dir, char *template_path)
 {
 	unsigned len = strlen(git_dir);
 	static char path[PATH_MAX];
 	unsigned char sha1[20];
+	struct stat st1;
+	char repo_version_string[10];
 
 	if (len > sizeof(path)-50)
 		die("insane git directory %s", git_dir);
@@ -164,6 +182,15 @@ static void create_default_files(const c
 	strcpy(path + len, "refs/tags");
 	safe_create_dir(path);
 
+	/* First copy the templates -- we might have the default
+	 * config file there, in which case we would want to read
+	 * from it after installing.
+	 */
+	path[len] = 0;
+	copy_templates(path, len, template_path);
+
+	git_config(git_default_config);
+
 	/*
 	 * Create the default symlink from ".git/HEAD" to the "master"
 	 * branch, if it does not exist yet.
@@ -173,44 +200,22 @@ static void create_default_files(const c
 		if (create_symref(path, "refs/heads/master") < 0)
 			exit(1);
 	}
-	path[len] = 0;
-	copy_templates(path, len, template_path);
 
-	/*
-	 * Find out if we can trust the executable bit.
-	 */
-	safe_create_dir(path);
+	/* This forces creation of new config file */
+	sprintf(repo_version_string, "%d", GIT_REPO_VERSION);
+	git_config_set("core.repositoryformatversion", repo_version_string);
+
+	path[len] = 0;
 	strcpy(path + len, "config");
-	if (access(path, R_OK) < 0) {
-		static const char contents[] =
-			"#\n"
-			"# This is the config file\n"
-			"#\n"
-			"\n"
-			"; core variables\n"
-			"[core]\n"
-			"	; Don't trust file modes\n"
-			"	filemode = false\n"
-			"\n";
-		FILE *config = fopen(path, "w");
-		struct stat st;
-
-		if (!config)
-			die("Can not write to %s?", path);
-
-		fwrite(contents, sizeof(contents)-1, 1, config);
-
-		fclose(config);
-
-		if (!lstat(path, &st)) {
-			struct stat st2;
-			if (!chmod(path, st.st_mode ^ S_IXUSR) &&
-					!lstat(path, &st2) &&
-					st.st_mode != st2.st_mode)
-				unlink(path);
-			else
-				fprintf(stderr, "Ignoring file modes\n");
-		}
+
+	/* Check filemode trustability */
+	if (!lstat(path, &st1)) {
+		struct stat st2;
+		int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+				!lstat(path, &st2) &&
+				st1.st_mode != st2.st_mode);
+		git_config_set("core.filemode",
+			       filemode ? "true" : "false");
 	}
 }
 
@@ -249,6 +254,14 @@ int main(int argc, char **argv)
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
 	safe_create_dir(git_dir);
+
+	/* Check to see if the repository version is right.
+	 * Note that a newly created repository does not have
+	 * config file, so this will not fail.  What we are catching
+	 * is an attempt to reinitialize new repository with an old tool.
+	 */
+	check_repository_format();
+
 	create_default_files(git_dir, template_dir);
 
 	/*
---
0.99.9.GIT

^ permalink raw reply related	[relevance 12%]

* [PATCH 1/8] git-apply: work from subdirectory.
  @ 2005-11-26  9:56 15%                               ` Junio C Hamano
  2005-11-26  9:56 17%                               ` [PATCH 2/8] peek-remote: honor proxy config even " Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-26  9:56 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This adds three things:

 - prefix_filename() is like prefix_path() but can be used to
   name any file on the filesystem, not the files that might go
   into the index file.

 - git-apply uses setup_git_directory() to find out the GIT_DIR
   and reads configuration file.  Later this would allow us to
   affect the behaviour of the command from the configuration.

 - When git-apply is run from a subdirectory, it applies the
   given patch only to the files under the current directory and
   below.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 apply.c |   15 +++++++++++++++
 cache.h |    1 +
 setup.c |   15 +++++++++++++++
 3 files changed, 31 insertions(+), 0 deletions(-)

applies-to: 9ccf8849fa9b522a344645c2f28f12ab036e30d5
c20b8d006edfa964b3df5e4c5cc28cb93edcb240
diff --git a/apply.c b/apply.c
index 50be8f3..ae06d41 100644
--- a/apply.c
+++ b/apply.c
@@ -16,6 +16,9 @@
 //  --numstat does numeric diffstat, and doesn't actually apply
 //  --index-info shows the old and new index info for paths if available.
 //
+static const char *prefix;
+static int prefix_length;
+
 static int allow_binary_replacement = 0;
 static int check_index = 0;
 static int write_index = 0;
@@ -1706,6 +1709,12 @@ static int use_patch(struct patch *p)
 			return 0;
 		x = x->next;
 	}
+	if (prefix && *prefix) {
+		int pathlen = strlen(pathname);
+		if (pathlen <= prefix_length ||
+		    memcmp(prefix, pathname, prefix_length))
+			return 0;
+	}
 	return 1;
 }
 
@@ -1784,6 +1793,10 @@ int main(int argc, char **argv)
 	int i;
 	int read_stdin = 1;
 
+	prefix = setup_git_directory();
+	prefix_length = prefix ? strlen(prefix) : 0;
+	git_config(git_default_config);
+
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		int fd;
@@ -1845,6 +1858,8 @@ int main(int argc, char **argv)
 			line_termination = 0;
 			continue;
 		}
+		arg = prefix_filename(prefix, prefix_length, arg);
+
 		fd = open(arg, O_RDONLY);
 		if (fd < 0)
 			usage(apply_usage);
diff --git a/cache.h b/cache.h
index 6ac94c5..62920ce 100644
--- a/cache.h
+++ b/cache.h
@@ -149,6 +149,7 @@ extern char *get_graft_file(void);
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
+extern const char *prefix_filename(const char *prefix, int len, const char *path);
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
diff --git a/setup.c b/setup.c
index ab3c778..54f6a34 100644
--- a/setup.c
+++ b/setup.c
@@ -47,6 +47,21 @@ const char *prefix_path(const char *pref
 	return path;
 }
 
+/* 
+ * Unlike prefix_path, this should be used if the named file does
+ * not have to interact with index entry; i.e. name of a random file
+ * on the filesystem.
+ */
+const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
+{
+	static char path[PATH_MAX];
+	if (!pfx || !*pfx || arg[0] == '/')
+		return arg;
+	memcpy(path, pfx, pfx_len);
+	strcpy(path + pfx_len, arg);
+	return path;
+}
+
 const char **get_pathspec(const char *prefix, const char **pathspec)
 {
 	const char *entry = *pathspec;
---
0.99.9.GIT

^ permalink raw reply related	[relevance 15%]

* [PATCH 2/8] peek-remote: honor proxy config even from subdirectory.
    2005-11-26  9:56 15%                               ` [PATCH 1/8] git-apply: work from subdirectory Junio C Hamano
@ 2005-11-26  9:56 17%                               ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-26  9:56 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Introduce setup_git_directory_gently() which does not die() if
called outside a git repository, and use it so that later
git_config() would work as expected even from a subdirectory,
without failing the whole command if run outside a git
repository.

Use it at the beginning of peek-remote so that git:// proxy can
be picked up from the configuration file.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 cache.h       |    1 +
 peek-remote.c |    3 +++
 setup.c       |   11 ++++++++---
 3 files changed, 12 insertions(+), 3 deletions(-)

applies-to: 6afe0a2dc5da18d1090e8d660e45e2c777bfeaaa
1fe3fae4e1dcd864af4010ee572a3bc6de996e95
diff --git a/cache.h b/cache.h
index 62920ce..13806d3 100644
--- a/cache.h
+++ b/cache.h
@@ -147,6 +147,7 @@ extern char *get_graft_file(void);
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
+extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
 extern const char *prefix_filename(const char *prefix, int len, const char *path);
diff --git a/peek-remote.c b/peek-remote.c
index ee49bf3..a90cf22 100644
--- a/peek-remote.c
+++ b/peek-remote.c
@@ -27,6 +27,9 @@ int main(int argc, char **argv)
 	char *dest = NULL;
 	int fd[2];
 	pid_t pid;
+	int nongit = 0;
+
+	setup_git_directory_gently(&nongit);
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
diff --git a/setup.c b/setup.c
index 54f6a34..b697bf9 100644
--- a/setup.c
+++ b/setup.c
@@ -107,7 +107,7 @@ static int is_toplevel_directory(void)
 	return 1;
 }
 
-static const char *setup_git_directory_1(void)
+const char *setup_git_directory_gently(int *nongit_ok)
 {
 	static char cwd[PATH_MAX+1];
 	int len, offset;
@@ -154,8 +154,13 @@ static const char *setup_git_directory_1
 			break;
 		chdir("..");
 		do {
-			if (!offset)
+			if (!offset) {
+				if (nongit_ok) {
+					*nongit_ok = 1;
+					return NULL;
+				}
 				die("Not a git repository");
+			}
 		} while (cwd[--offset] != '/');
 	}
 
@@ -171,6 +176,6 @@ static const char *setup_git_directory_1
 
 const char *setup_git_directory(void)
 {
-	const char *retval = setup_git_directory_1();
+	const char *retval = setup_git_directory_gently(NULL);
 	return retval;
 }
---
0.99.9.GIT

^ permalink raw reply related	[relevance 17%]

* [PATCH 1/3] Introduce i18n.commitencoding.
@ 2005-11-28  0:39 17% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-11-28  0:39 UTC (permalink / raw)
  To: git

This is to hold what the project-local rule as to the
charset/encoding for the commit log message is.  Lack of it
defaults to utf-8.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * This is not needed to make the gitk patch I just sent out
   work, because git-repo-config can do its own thing without
   the C-level integration like this.

   That may or may not be a good thing, though.  I wished either
   'git-var i18n.commitencoding' or 'git-repo-config --get
   i18n.commitencoding' in a vanilla repository to emit the
   default "utf-8".  Johannes?

 cache.h       |    3 +++
 config.c      |    5 +++++
 environment.c |    1 +
 3 files changed, 9 insertions(+), 0 deletions(-)

applies-to: 5596ac6f4661c80f823d93de7fa9aeec65ace1f1
4e72dcec89c7cda7022d4ec2dd686e77deb5376e
diff --git a/cache.h b/cache.h
index 61bf884..634b5aa 100644
--- a/cache.h
+++ b/cache.h
@@ -399,6 +399,9 @@ extern int check_repository_format_versi
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
 
+#define MAX_ENCODING_LENGTH 64
+extern char git_commit_encoding[MAX_ENCODING_LENGTH];
+
 /* Sane ctype - no locale, and works with signed chars */
 #undef isspace
 #undef isdigit
diff --git a/config.c b/config.c
index 0c43d76..152fa28 100644
--- a/config.c
+++ b/config.c
@@ -237,6 +237,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "i18n.commitencoding")) {
+		strncpy(git_commit_encoding, value, sizeof(git_commit_encoding));
+		return 0;
+	}
+
 	/* Add other config variables here.. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 3f19473..0886ad3 100644
--- a/environment.c
+++ b/environment.c
@@ -14,6 +14,7 @@ char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
 int repository_format_version = 0;
+char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
---
0.99.9.GIT

^ permalink raw reply related	[relevance 17%]

* make gitfakemmap standalone to fix linking error in git.c
@ 2005-12-05 13:19 17% Alex Riesen
    0 siblings, 1 reply; 200+ results
From: Alex Riesen @ 2005-12-05 13:19 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 225 bytes --]

The patch is to fix linking error because of gitfakemmap referencing
die living in usage.c, and git.c not linking in the file. Instead of
hardcoding usage.o in git.c prerequisites, I separated mmap from the
main sources.

[-- Attachment #2: 0001-make-fakemmap-standalone-to-fix-linking-error-because-of-gitfakemmap.txt --]
[-- Type: text/plain, Size: 2720 bytes --]

Subject: [PATCH] make fakemmap standalone to fix linking error because of gitfakemmap
referencing die living in usage.c, and git.c not linking in the file.
Instead of hardcoding usage.o in git.c prerequisites, I separated mmap.

Signed-off-by: Alex Riesen <fork0@gmail.com>


---

 cache.h       |   18 +++---------------
 compat/mmap.c |   11 +++++++----
 compat/mmap.h |   15 +++++++++++++++
 3 files changed, 25 insertions(+), 19 deletions(-)
 create mode 100644 compat/mmap.h

e1e24d29b684d468a7be5d097ba3e1679170e7db
diff --git a/cache.h b/cache.h
index f9b367f..c70a467 100644
--- a/cache.h
+++ b/cache.h
@@ -11,7 +11,9 @@
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
-#ifndef NO_MMAP
+#ifdef NO_MMAP
+#include "compat/mmap.h"
+#else
 #include <sys/mman.h>
 #endif
 #include <sys/param.h>
@@ -373,20 +375,6 @@ extern void packed_object_info_detail(st
 /* Dumb servers support */
 extern int update_server_info(int);
 
-#ifdef NO_MMAP
-
-#ifndef PROT_READ
-#define PROT_READ 1
-#define PROT_WRITE 2
-#define MAP_PRIVATE 1
-#define MAP_FAILED ((void*)-1)
-#endif
-
-extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
-extern int gitfakemunmap(void *start, size_t length);
-
-#endif
-
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
 extern int git_config_from_file(config_fn_t fn, const char *);
diff --git a/compat/mmap.c b/compat/mmap.c
index a051c47..98cf3cb 100644
--- a/compat/mmap.c
+++ b/compat/mmap.c
@@ -2,21 +2,24 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
-#include "../cache.h"
+#include <string.h>
+#include "mmap.h"
 
 void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
 {
 	int n = 0;
 
-	if (start != NULL || !(flags & MAP_PRIVATE))
-		die("Invalid usage of gitfakemmap.");
+	if (!start || !(flags & MAP_PRIVATE)) {
+		fprintf(stderr, "Invalid usage of gitfakemmap.\n");
+		exit(128); /* see die() in ../usage.c */
+	}
 
 	if (lseek(fd, offset, SEEK_SET) < 0) {
 		errno = EINVAL;
 		return MAP_FAILED;
 	}
 
-	start = xmalloc(length);
+	start = malloc(length);
 	if (start == NULL) {
 		errno = ENOMEM;
 		return MAP_FAILED;
diff --git a/compat/mmap.h b/compat/mmap.h
new file mode 100644
index 0000000..08d7f99
--- /dev/null
+++ b/compat/mmap.h
@@ -0,0 +1,15 @@
+#ifndef MMAP_H
+#define MMAP_H
+
+#ifndef PROT_READ
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define MAP_PRIVATE 1
+#define MAP_FAILED ((void*)-1)
+#endif
+
+extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
+extern int gitfakemunmap(void *start, size_t length);
+
+#endif
+
-- 
0.99.9.GIT

^ permalink raw reply related	[relevance 17%]

* [PATCH] Clean up compatibility definitions.
  @ 2005-12-05 20:22 10%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-12-05 20:22 UTC (permalink / raw)
  To: git; +Cc: Alex Riesen

This attempts to clean up the way various compatibility
functions are defined and used.

 - A new header file, git-compat-util.h, is introduced.  This
   looks at various NO_XXX and does necessary function name
   replacements, equivalent of -Dstrcasestr=gitstrcasestr in the
   Makefile.

 - Those function name replacements are removed from the Makefile.

 - Common features such as usage(), die(), xmalloc() are moved
   from cache.h to git-compat-util.h; cache.h includes
   git-compat-util.h itself.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

  Junio C Hamano <junkio@cox.net> writes:

  > When I took setenv patch for git.c, I was thinking about
  > something similar.  It may be cleaner to split out the pieces so
  > that the functions like usage(), die(), xmalloc() and friends
  > could be linkable in git.c and others that want to link in only
  > the minimum set without including "cache.h" which has more
  > intimate knowledge of other git internals.

  Maybe something like this...

 Makefile            |   16 ++++---
 cache.h             |   96 -------------------------------------------
 compat/mmap.c       |    2 -
 compat/strcasestr.c |    3 -
 git-compat-util.h   |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++
 git.c               |   15 +++----
 mailinfo.c          |    4 --
 usage.c             |    2 -
 8 files changed, 132 insertions(+), 119 deletions(-)
 create mode 100644 git-compat-util.h

2823be66bb4a1f6a6b4240e24dfd402e4146c43c
diff --git a/Makefile b/Makefile
index df3c6eb..1f1088e 100644
--- a/Makefile
+++ b/Makefile
@@ -162,7 +162,7 @@ LIB_FILE=libgit.a
 LIB_H = \
 	blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
 	diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
-	run-command.h strbuf.h tag.h tree.h
+	run-command.h strbuf.h tag.h tree.h git-compat-util.h
 
 DIFF_OBJS = \
 	diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
@@ -174,9 +174,11 @@ LIB_OBJS = \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
-	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
+	tag.o tree.o config.o environment.o copy.o \
 	$(DIFF_OBJS)
 
+COMPAT_OBJS = usage.o ctype.o
+
 LIBS = $(LIB_FILE)
 LIBS += -lz
 
@@ -320,15 +322,15 @@ ifdef NEEDS_NSL
 	SIMPLE_LIB += -lnsl
 endif
 ifdef NO_STRCASESTR
-	COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
+	COMPAT_CFLAGS += -DNO_STRCASESTR
 	COMPAT_OBJS += compat/strcasestr.o
 endif
 ifdef NO_SETENV
-	COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
+	COMPAT_CFLAGS += -DNO_SETENV
 	COMPAT_OBJS += compat/setenv.o
 endif
 ifdef NO_MMAP
-	COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
+	COMPAT_CFLAGS += -DNO_MMAP
 	COMPAT_OBJS += compat/mmap.o
 endif
 ifdef NO_IPV6
@@ -363,9 +365,9 @@ all: $(ALL_PROGRAMS)
 all:
 	$(MAKE) -C templates
 
-git$(X): git.c $(COMPAT_OBJS) Makefile
+git$X: git.c $(LIB_FILE) Makefile
 	$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
-		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(filter %.o,$^)
+		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
 
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
 	rm -f $@
diff --git a/cache.h b/cache.h
index f9b367f..86fc250 100644
--- a/cache.h
+++ b/cache.h
@@ -1,23 +1,7 @@
 #ifndef CACHE_H
 #define CACHE_H
 
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#ifndef NO_MMAP
-#include <sys/mman.h>
-#endif
-#include <sys/param.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <dirent.h>
+#include "git-compat-util.h"
 
 #include SHA1_HEADER
 #include <zlib.h>
@@ -36,15 +20,6 @@
 #define DTYPE(de)	DT_UNKNOWN
 #endif
 
-#ifdef __GNUC__
-#define NORETURN __attribute__((__noreturn__))
-#else
-#define NORETURN
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
 /*
  * Intensive research over the course of many years has shown that
  * port 9418 is totally unused by anything else. Or
@@ -250,11 +225,6 @@ extern const char *resolve_ref(const cha
 extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
 extern int validate_symref(const char *git_HEAD);
 
-/* General helper functions */
-extern void usage(const char *err) NORETURN;
-extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
-extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
-
 extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 
@@ -272,30 +242,6 @@ extern int setup_ident(void);
 extern const char *git_author_info(void);
 extern const char *git_committer_info(void);
 
-static inline void *xmalloc(size_t size)
-{
-	void *ret = malloc(size);
-	if (!ret)
-		die("Out of memory, malloc failed");
-	return ret;
-}
-
-static inline void *xrealloc(void *ptr, size_t size)
-{
-	void *ret = realloc(ptr, size);
-	if (!ret)
-		die("Out of memory, realloc failed");
-	return ret;
-}
-
-static inline void *xcalloc(size_t nmemb, size_t size)
-{
-	void *ret = calloc(nmemb, size);
-	if (!ret)
-		die("Out of memory, calloc failed");
-	return ret;
-}
-
 struct checkout {
 	const char *base_dir;
 	int base_dir_len;
@@ -373,20 +319,6 @@ extern void packed_object_info_detail(st
 /* Dumb servers support */
 extern int update_server_info(int);
 
-#ifdef NO_MMAP
-
-#ifndef PROT_READ
-#define PROT_READ 1
-#define PROT_WRITE 2
-#define MAP_PRIVATE 1
-#define MAP_FAILED ((void*)-1)
-#endif
-
-extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
-extern int gitfakemunmap(void *start, size_t length);
-
-#endif
-
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
 extern int git_config_from_file(config_fn_t fn, const char *);
@@ -404,31 +336,5 @@ extern char git_default_name[MAX_GITNAME
 #define MAX_ENCODING_LENGTH 64
 extern char git_commit_encoding[MAX_ENCODING_LENGTH];
 
-/* Sane ctype - no locale, and works with signed chars */
-#undef isspace
-#undef isdigit
-#undef isalpha
-#undef isalnum
-#undef tolower
-#undef toupper
-extern unsigned char sane_ctype[256];
-#define GIT_SPACE 0x01
-#define GIT_DIGIT 0x02
-#define GIT_ALPHA 0x04
-#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
-#define isspace(x) sane_istest(x,GIT_SPACE)
-#define isdigit(x) sane_istest(x,GIT_DIGIT)
-#define isalpha(x) sane_istest(x,GIT_ALPHA)
-#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
-#define tolower(x) sane_case((unsigned char)(x), 0x20)
-#define toupper(x) sane_case((unsigned char)(x), 0)
-
-static inline int sane_case(int x, int high)
-{
-	if (sane_istest(x, GIT_ALPHA))
-		x = (x & ~0x20) | high;
-	return x;
-}
-
 extern int copy_fd(int ifd, int ofd);
 #endif /* CACHE_H */
diff --git a/compat/mmap.c b/compat/mmap.c
index a051c47..55cb120 100644
--- a/compat/mmap.c
+++ b/compat/mmap.c
@@ -2,7 +2,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
-#include "../cache.h"
+#include "../git-compat-util.h"
 
 void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
 {
diff --git a/compat/strcasestr.c b/compat/strcasestr.c
index b96414d..26896de 100644
--- a/compat/strcasestr.c
+++ b/compat/strcasestr.c
@@ -1,5 +1,4 @@
-#include <string.h>
-#include <ctype.h>
+#include "../git-compat-util.h"
 
 char *gitstrcasestr(const char *haystack, const char *needle)
 {
diff --git a/git-compat-util.h b/git-compat-util.h
new file mode 100644
index 0000000..4185b12
--- /dev/null
+++ b/git-compat-util.h
@@ -0,0 +1,113 @@
+#ifndef GIT_COMPAT_UTIL_H
+#define GIT_COMPAT_UTIL_H
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#ifdef __GNUC__
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+/* General helper functions */
+extern void usage(const char *err) NORETURN;
+extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
+
+#ifdef NO_MMAP
+
+#ifndef PROT_READ
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define MAP_PRIVATE 1
+#define MAP_FAILED ((void*)-1)
+#endif
+
+#define mmap gitfakemmap
+#define munmap gitfakemunmap
+extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
+extern int gitfakemunmap(void *start, size_t length);
+
+#else /* NO_MMAP */
+
+#include <sys/mman.h>
+
+#endif /* NO_MMAP */
+
+#ifdef NO_SETENV
+#define setenv gitsetenv
+extern int gitsetenv(const char *, const char *, int);
+#endif
+
+#ifdef NO_STRCASESTR
+#define strcasestr gitstrcasestr
+extern char *gitstrcasestr(const char *haystack, const char *needle);
+#endif
+
+static inline void *xmalloc(size_t size)
+{
+	void *ret = malloc(size);
+	if (!ret)
+		die("Out of memory, malloc failed");
+	return ret;
+}
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+	void *ret = realloc(ptr, size);
+	if (!ret)
+		die("Out of memory, realloc failed");
+	return ret;
+}
+
+static inline void *xcalloc(size_t nmemb, size_t size)
+{
+	void *ret = calloc(nmemb, size);
+	if (!ret)
+		die("Out of memory, calloc failed");
+	return ret;
+}
+
+/* Sane ctype - no locale, and works with signed chars */
+#undef isspace
+#undef isdigit
+#undef isalpha
+#undef isalnum
+#undef tolower
+#undef toupper
+extern unsigned char sane_ctype[256];
+#define GIT_SPACE 0x01
+#define GIT_DIGIT 0x02
+#define GIT_ALPHA 0x04
+#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
+#define isspace(x) sane_istest(x,GIT_SPACE)
+#define isdigit(x) sane_istest(x,GIT_DIGIT)
+#define isalpha(x) sane_istest(x,GIT_ALPHA)
+#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define tolower(x) sane_case((unsigned char)(x), 0x20)
+#define toupper(x) sane_case((unsigned char)(x), 0)
+
+static inline int sane_case(int x, int high)
+{
+	if (sane_istest(x, GIT_ALPHA))
+		x = (x & ~0x20) | high;
+	return x;
+}
+
+#endif
diff --git a/git.c b/git.c
index ee5048a..c26cac6 100644
--- a/git.c
+++ b/git.c
@@ -8,15 +8,12 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include "git-compat-util.h"
 
 #ifndef PATH_MAX
 # define PATH_MAX 4096
 #endif
 
-#ifdef NO_SETENV
-extern int gitsetenv(const char *, const char *, int);
-#endif
-
 static const char git_usage[] =
 	"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
 
@@ -156,10 +153,10 @@ static void list_commands(const char *ex
 }
 
 #ifdef __GNUC__
-static void usage(const char *exec_path, const char *fmt, ...)
+static void cmd_usage(const char *exec_path, const char *fmt, ...)
 	__attribute__((__format__(__printf__, 2, 3), __noreturn__));
 #endif
-static void usage(const char *exec_path, const char *fmt, ...)
+static void cmd_usage(const char *exec_path, const char *fmt, ...)
 {
 	if (fmt) {
 		va_list ap;
@@ -254,12 +251,12 @@ int main(int argc, char **argv, char **e
 		else if (!strcmp(arg, "help"))
 			show_help = 1;
 		else if (!show_help)
-			usage(NULL, NULL);
+			cmd_usage(NULL, NULL);
 	}
 
 	if (i >= argc || show_help) {
 		if (i >= argc)
-			usage(exec_path, NULL);
+			cmd_usage(exec_path, NULL);
 
 		show_man_page(argv[i]);
 	}
@@ -297,7 +294,7 @@ int main(int argc, char **argv, char **e
 	execve(git_command, &argv[i], envp);
 
 	if (errno == ENOENT)
-		usage(exec_path, "'%s' is not a git-command", argv[i]);
+		cmd_usage(exec_path, "'%s' is not a git-command", argv[i]);
 
 	fprintf(stderr, "Failed to run command '%s': %s\n",
 		git_command, strerror(errno));
diff --git a/mailinfo.c b/mailinfo.c
index 890e348..3b97a89 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -10,10 +10,6 @@
 #include <iconv.h>
 #include "cache.h"
 
-#ifdef NO_STRCASESTR
-extern char *gitstrcasestr(const char *haystack, const char *needle);
-#endif
-
 static FILE *cmitmsg, *patchfile;
 
 static int keep_subject = 0;
diff --git a/usage.c b/usage.c
index dfa87fe..1fa924c 100644
--- a/usage.c
+++ b/usage.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "git-compat-util.h"
 
 static void report(const char *prefix, const char *err, va_list params)
 {
-- 
0.99.9.GIT

^ permalink raw reply related	[relevance 10%]

* [PATCH] Allow updating the index from a pipe
@ 2005-12-10  6:57 12% Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-12-10  6:57 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

In order to allow the index to be modified in simple ways without
having a working tree, this adds an option to git-update-index which
updates a single path with a mode of 100644 and reads the content from
stdin. Somebody should probably give the option a better name.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

---

This is for a git-backed wiki I'm writing, which doesn't want to use a 
working tree when preparing changes, but wants to work entirely with pipes 
and index files.

 Documentation/git-update-index.txt |    7 ++++++
 cache.h                            |    1 +
 sha1_file.c                        |   27 ++++++++++++++++++++++++
 update-index.c                     |   40 +++++++++++++++++++++++++++++++++++-
 4 files changed, 74 insertions(+), 1 deletions(-)

7883add98deb548c7c10681ae3d71b7a7d949a9a
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index e4678cd..d35340a 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -14,6 +14,7 @@ SYNOPSIS
 	     [--cacheinfo <mode> <object> <file>]\*
 	     [--chmod=(+|-)x]
 	     [--info-only] [--index-info]
+	     [--name=<file>]
 	     [-z] [--stdin]
 	     [--verbose]
 	     [--] [<file>]\*
@@ -87,6 +88,12 @@ OPTIONS
 	read list of paths from the standard input.  Paths are
 	separated by LF (i.e. one path per line) by default.
 
+--name=<file>:: 
+	Instead of taking a list of paths, only operate on a single
+	path, and get the content from the standard input instead of
+	from the file system.  The mode for the file will be 100644
+	(regular non-executable file).
+
 --verbose::
         Report what is being added and removed from index.
 
diff --git a/cache.h b/cache.h
index 86fc250..1b30f44 100644
--- a/cache.h
+++ b/cache.h
@@ -144,6 +144,7 @@ extern int ce_match_stat(struct cache_en
 extern int ce_modified(struct cache_entry *ce, struct stat *st);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
+extern int index_pipe(unsigned char *sha1, int fd, const char *type);
 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
diff --git a/sha1_file.c b/sha1_file.c
index 111a71d..0073187 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1528,6 +1528,33 @@ int has_sha1_file(const unsigned char *s
 	return find_sha1_file(sha1, &st) ? 1 : 0;
 }
 
+int index_pipe(unsigned char *sha1, int fd, const char *type)
+{
+	unsigned long size = 4096;
+	char *buf = malloc(size);
+	int iret, ret;
+	unsigned long off = 0;
+	do {
+		iret = read(fd, buf + off, size - off);
+		if (iret > 0) {
+			off += iret;
+			if (off == size) {
+				size *= 2;
+				buf = realloc(buf, size);
+			}
+		}
+	} while (iret > 0);
+	if (iret < 0) {
+		free(buf);
+		return -1;
+	}
+	if (!type)
+		type = "blob";
+	ret = write_sha1_file(buf, off, type, sha1);
+	free(buf);
+	return ret;
+}
+
 int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
 {
 	unsigned long size = st->st_size;
diff --git a/update-index.c b/update-index.c
index 11b7f6a..f3d79af 100644
--- a/update-index.c
+++ b/update-index.c
@@ -24,6 +24,8 @@ static int info_only;
 static int force_remove;
 static int verbose;
 
+static char *single_name = NULL;
+
 /* Three functions to allow overloaded pointer return; see linux/err.h */
 static inline void *ERR_PTR(long error)
 {
@@ -117,6 +119,33 @@ static int add_file_to_cache(const char 
 	return 0;
 }
 
+
+static int add_stdin_to_cache(const char *path)
+{
+	int size, namelen, option;
+	struct cache_entry *ce;
+	struct stat st;
+
+	namelen = strlen(path);
+	size = cache_entry_size(namelen);
+	ce = xmalloc(size);
+	memset(ce, 0, size);
+	memcpy(ce->name, path, namelen);
+	ce->ce_mode = create_ce_mode(0100644);
+	ce->ce_flags = create_ce_flags(namelen, 0);
+
+	st.st_size = 0;
+	
+	if (index_pipe(ce->sha1, 0, NULL))
+		return -1;
+	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
+	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
+	if (add_cache_entry(ce, option))
+		return error("%s: cannot add to the index - missing --add option?",
+			     path);
+	return 0;
+}
+
 /*
  * "refresh" does not calculate a new sha1 file or bring the
  * cache up-to-date for mode/content changes. But what it
@@ -396,7 +425,7 @@ static void read_index_info(int line_ter
 }
 
 static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [--name=<file>] [-z] [--verbose] [--] <file>...";
 
 int main(int argc, const char **argv)
 {
@@ -464,6 +493,10 @@ int main(int argc, const char **argv)
 					die("git-update-index: %s cannot chmod %s", path, argv[i]);
 				continue;
 			}
+			if (!strncmp(path, "--name=", strlen("--name="))) {
+				single_name = strdup(path + strlen("--name="));
+				continue;
+			}
 			if (!strcmp(path, "--info-only")) {
 				info_only = 1;
 				continue;
@@ -499,6 +532,8 @@ int main(int argc, const char **argv)
 				usage(update_index_usage);
 			die("unknown option %s", path);
 		}
+		if (single_name)
+			die("--name=<file> is incompatible with filenames");
 		update_one(path, prefix, prefix_length);
 	}
 	if (read_from_stdin) {
@@ -511,6 +546,9 @@ int main(int argc, const char **argv)
 			update_one(buf.buf, prefix, prefix_length);
 		}
 	}
+	if (single_name) {
+		add_stdin_to_cache(single_name);
+	}
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
 		    commit_index_file(&cache_file))
-- 
0.99.9.GIT

^ permalink raw reply related	[relevance 12%]

* [PATCH 21/25] git-send-email: Usage message clean-up.
  @ 2005-12-10 19:37 39% ` freku045
  0 siblings, 0 replies; 200+ results
From: freku045 @ 2005-12-10 19:37 UTC (permalink / raw)
  To: git; +Cc: Fredrik Kuivinen

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>

---

 git-send-email.perl |   62 ++++++++++++++++++++++++++++-----------------------
 1 files changed, 34 insertions(+), 28 deletions(-)

38fde073a59d00a19111a30e8f804c4e784835e7
diff --git a/git-send-email.perl b/git-send-email.perl
index ec1428d..5f6b729 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -27,6 +27,38 @@ use Email::Valid;
 sub unique_email_list(@);
 sub cleanup_compose_files();
 
+sub usage {
+	print <<EOT;
+$0 [options] <file | directory> [... file | directory ]
+Options:
+   --from         Specify the "From:" line of the email to be sent.
+
+   --to           Specify the primary "To:" line of the email.
+
+   --compose      Use \$EDITOR to edit an introductory message for the
+                  patch series.
+
+   --subject      Specify the initial "Subject:" line.
+                  Only necessary if --compose is also set.  If --compose
+		  is not set, this will be prompted for.
+
+   --in-reply-to  Specify the first "In-Reply-To:" header line.
+                  Only used if --compose is also set.  If --compose is not
+		  set, this will be prompted for.
+
+   --chain-reply-to If set, the replies will all be to the previous
+                  email sent, rather than to the first email sent.
+                  Defaults to on.
+
+   --smtp-server  If set, specifies the outgoing SMTP server to use.
+                  Defaults to localhost.
+EOT
+
+	print $_[0], "\n" if defined $_[0];
+
+	exit(1);
+}
+
 # Constants (essentially)
 my $compose_filename = ".msg.$$";
 
@@ -51,6 +83,7 @@ my $rc = GetOptions("from=s" => \$from,
 		    "chain-reply-to!" => \$chain_reply_to,
 		    "smtp-server=s" => \$smtp_server,
 		    "compose" => \$compose,
+		    "help|h" => sub { usage; },
 	 );
 
 # Now, let's fill any that aren't set in with defaults:
@@ -187,34 +220,7 @@ for my $f (@ARGV) {
 if (@files) {
 	print $_,"\n" for @files;
 } else {
-	print <<EOT;
-git-send-email [options] <file | directory> [... file | directory ]
-Options:
-   --from         Specify the "From:" line of the email to be sent.
-
-   --to           Specify the primary "To:" line of the email.
-
-   --compose      Use \$EDITOR to edit an introductory message for the
-                  patch series.
-
-   --subject      Specify the initial "Subject:" line.
-                  Only necessary if --compose is also set.  If --compose
-		  is not set, this will be prompted for.
-
-   --in-reply-to  Specify the first "In-Reply-To:" header line.
-                  Only used if --compose is also set.  If --compose is not
-		  set, this will be prompted for.
-
-   --chain-reply-to If set, the replies will all be to the previous
-                  email sent, rather than to the first email sent.
-                  Defaults to on.
-
-   --smtp-server  If set, specifies the outgoing SMTP server to use.
-                  Defaults to localhost.
-
-Error: Please specify a file or a directory on the command line.
-EOT
-	exit(1);
+	usage "Error: Please specify a file or a directory on the command line.";
 }
 
 # Variables we set as part of the loop over files
-- 
0.99.9.GIT

^ permalink raw reply related	[relevance 39%]

* [PATCH] Allow saving an object from a pipe
@ 2005-12-10 22:25 15% Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2005-12-10 22:25 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

In order to support getting data into git with scripts, this adds a
--stdin option to git-hash-object, which will make it read from stdin.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

---

 Documentation/git-hash-object.txt |    3 +++
 cache.h                           |    1 +
 hash-object.c                     |   15 +++++++++++++--
 sha1_file.c                       |   34 ++++++++++++++++++++++++++++++++++
 4 files changed, 51 insertions(+), 2 deletions(-)

fac4c3a5c27839006e5d086ef282b252bd5f390e
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt
index db12e92..eaac4c9 100644
--- a/Documentation/git-hash-object.txt
+++ b/Documentation/git-hash-object.txt
@@ -29,6 +29,9 @@ OPTIONS
 -w::
 	Actually write the object into the object database.
 
+--stdin::
+	Read the object from standard input instead of from a file.
+
 Author
 ------
 Written by Junio C Hamano <junkio@cox.net>
diff --git a/cache.h b/cache.h
index 86fc250..c78d8ae 100644
--- a/cache.h
+++ b/cache.h
@@ -144,6 +144,7 @@ extern int ce_match_stat(struct cache_en
 extern int ce_modified(struct cache_entry *ce, struct stat *st);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
+extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
diff --git a/hash-object.c b/hash-object.c
index 6227936..6502b5b 100644
--- a/hash-object.c
+++ b/hash-object.c
@@ -21,8 +21,16 @@ static void hash_object(const char *path
 	printf("%s\n", sha1_to_hex(sha1));
 }
 
+static void hash_stdin(const char *type, int write_object)
+{
+	unsigned char sha1[20];
+	if (index_pipe(sha1, 0, type, write_object))
+		die("Unable to add stdin to database");
+	printf("%s\n", sha1_to_hex(sha1));
+}
+
 static const char hash_object_usage[] =
-"git-hash-object [-t <type>] [-w] <file>...";
+"git-hash-object [-t <type>] [-w] [--stdin] <file>...";
 
 int main(int argc, char **argv)
 {
@@ -53,9 +61,12 @@ int main(int argc, char **argv)
 			}
 			else if (!strcmp(argv[i], "--help"))
 				usage(hash_object_usage);
+			else if (!strcmp(argv[i], "--stdin")) {
+				hash_stdin(type, write_object);
+			}
 			else
 				die(hash_object_usage);
-		}
+		} 
 		else {
 			const char *arg = argv[i];
 			if (0 <= prefix_length)
diff --git a/sha1_file.c b/sha1_file.c
index 111a71d..fa22e9c 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1528,6 +1528,40 @@ int has_sha1_file(const unsigned char *s
 	return find_sha1_file(sha1, &st) ? 1 : 0;
 }
 
+int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
+{
+	unsigned long size = 4096;
+	char *buf = malloc(size);
+	int iret, ret;
+	unsigned long off = 0;
+	unsigned char hdr[50];
+	int hdrlen;
+	do {
+		iret = read(fd, buf + off, size - off);
+		if (iret > 0) {
+			off += iret;
+			if (off == size) {
+				size *= 2;
+				buf = realloc(buf, size);
+			}
+		}
+	} while (iret > 0);
+	if (iret < 0) {
+		free(buf);
+		return -1;
+	}
+	if (!type)
+		type = "blob";
+	if (write_object)
+		ret = write_sha1_file(buf, off, type, sha1);
+	else {
+		write_sha1_file_prepare(buf, off, type, sha1, hdr, &hdrlen);
+		ret = 0;
+	}
+	free(buf);
+	return ret;
+}
+
 int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
 {
 	unsigned long size = st->st_size;
-- 
0.99.9.GIT

^ permalink raw reply related	[relevance 15%]

* Re: How to clone-pack the HEAD?
  @ 2005-12-15  6:21  7%           ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-12-15  6:21 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Junio C Hamano <junkio@cox.net> writes:

> Also I might want to give --keep option to fetch-pack as well;
> clone-pack has some static functions that we can extract out to
> a common file to link to both.

And this is the second installment, on top of the previous one.
I am a bit reluctant about this one only because of its size,
but I suspect it may be much easier to use for your purpose.

I'll keep this in the proposed updates branch for now (the other
one goes to master tonight), so if you like this one, please
holler, test out and ack.

-- >8 --
Subject: [PATCH] fetch-pack: -k option to keep downloaded pack.

Split out the functions that deal with the socketpair after
finishing git protocol handshake to receive the packed data into
a separate file, and use it in fetch-pack to keep/explode the
received pack data.  We earlier had something like that on
clone-pack side once, but the list discussion resulted in the
decision that it makes sense to always keep the pack for
clone-pack, so unpacking option is not enabled on the clone-pack
side, but we later still could do so easily if we wanted to with
this change.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Documentation/git-fetch-pack.txt |    7 +-
 Makefile                         |    1 
 cache.h                          |    5 +
 clone-pack.c                     |  136 ------------------------------
 fetch-clone.c                    |  172 ++++++++++++++++++++++++++++++++++++++
 fetch-pack.c                     |   58 +++++--------
 6 files changed, 206 insertions(+), 173 deletions(-)
 create mode 100644 fetch-clone.c

32cf3b780b1cf77cf2fa7042d31dfe969ad0b9b9
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index ea6faab..b507e9b 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects
 
 SYNOPSIS
 --------
-git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
+git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
 
 DESCRIPTION
 -----------
@@ -29,6 +29,11 @@ OPTIONS
 	Pass '-q' flag to 'git-unpack-objects'; this makes the
 	cloning process less verbose.
 
+-k::
+	Do not invoke 'git-unpack-objects' on received data, but
+	create a single packfile out of it instead, and store it
+	in the object database.
+
 --exec=<git-upload-pack>::
 	Use this to specify the path to 'git-upload-pack' on the
 	remote side, if is not found on your $PATH.
diff --git a/Makefile b/Makefile
index d494ad4..9fd2ed3 100644
--- a/Makefile
+++ b/Makefile
@@ -175,6 +175,7 @@ LIB_OBJS = \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
+	fetch-clone.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/cache.h b/cache.h
index c78d8ae..cb87bec 100644
--- a/cache.h
+++ b/cache.h
@@ -338,4 +338,9 @@ extern char git_default_name[MAX_GITNAME
 extern char git_commit_encoding[MAX_ENCODING_LENGTH];
 
 extern int copy_fd(int ifd, int ofd);
+
+/* Finish off pack transfer receiving end */
+extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
+extern int receive_keep_pack(int fd[2], const char *me);
+
 #endif /* CACHE_H */
diff --git a/clone-pack.c b/clone-pack.c
index b5ce5d3..03dbc2e 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "refs.h"
 #include "pkt-line.h"
-#include <sys/wait.h>
 
 static const char clone_pack_usage[] =
 "git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
@@ -112,139 +111,6 @@ static void write_refs(struct ref *ref)
 	free(head_path);
 }
 
-static int finish_pack(const char *pack_tmp_name)
-{
-	int pipe_fd[2];
-	pid_t pid;
-	char idx[PATH_MAX];
-	char final[PATH_MAX];
-	char hash[41];
-	unsigned char sha1[20];
-	char *cp;
-	int err = 0;
-
-	if (pipe(pipe_fd) < 0)
-		die("git-clone-pack: unable to set up pipe");
-
-	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
-	cp = strrchr(idx, '/');
-	memcpy(cp, "/pidx", 5);
-
-	pid = fork();
-	if (pid < 0)
-		die("git-clone-pack: unable to fork off git-index-pack");
-	if (!pid) {
-		close(0);
-		dup2(pipe_fd[1], 1);
-		close(pipe_fd[0]);
-		close(pipe_fd[1]);
-		execlp("git-index-pack","git-index-pack",
-		       "-o", idx, pack_tmp_name, NULL);
-		error("cannot exec git-index-pack <%s> <%s>",
-		      idx, pack_tmp_name);
-		exit(1);
-	}
-	close(pipe_fd[1]);
-	if (read(pipe_fd[0], hash, 40) != 40) {
-		error("git-clone-pack: unable to read from git-index-pack");
-		err = 1;
-	}
-	close(pipe_fd[0]);
-
-	for (;;) {
-		int status, code;
-		int retval = waitpid(pid, &status, 0);
-
-		if (retval < 0) {
-			if (errno == EINTR)
-				continue;
-			error("waitpid failed (%s)", strerror(retval));
-			goto error_die;
-		}
-		if (WIFSIGNALED(status)) {
-			int sig = WTERMSIG(status);
-			error("git-index-pack died of signal %d", sig);
-			goto error_die;
-		}
-		if (!WIFEXITED(status)) {
-			error("git-index-pack died of unnatural causes %d",
-			      status);
-			goto error_die;
-		}
-		code = WEXITSTATUS(status);
-		if (code) {
-			error("git-index-pack died with error code %d", code);
-			goto error_die;
-		}
-		if (err)
-			goto error_die;
-		break;
-	}
-	hash[40] = 0;
-	if (get_sha1_hex(hash, sha1)) {
-		error("git-index-pack reported nonsense '%s'", hash);
-		goto error_die;
-	}
-	/* Now we have pack in pack_tmp_name[], and
-	 * idx in idx[]; rename them to their final names.
-	 */
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
-	move_temp_to_file(pack_tmp_name, final);
-	chmod(final, 0444);
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
-	move_temp_to_file(idx, final);
-	chmod(final, 0444);
-	return 0;
-
- error_die:
-	unlink(idx);
-	unlink(pack_tmp_name);
-	exit(1);
-}
-
-static int clone_without_unpack(int fd[2])
-{
-	char tmpfile[PATH_MAX];
-	int ofd, ifd;
-
-	ifd = fd[0];
-	snprintf(tmpfile, sizeof(tmpfile),
-		 "%s/pack/tmp-XXXXXX", get_object_directory());
-	ofd = mkstemp(tmpfile);
-	if (ofd < 0)
-		return error("unable to create temporary file %s", tmpfile);
-
-	while (1) {
-		char buf[8192];
-		ssize_t sz, wsz, pos;
-		sz = read(ifd, buf, sizeof(buf));
-		if (sz == 0)
-			break;
-		if (sz < 0) {
-			error("error reading pack (%s)", strerror(errno));
-			close(ofd);
-			unlink(tmpfile);
-			return -1;
-		}
-		pos = 0;
-		while (pos < sz) {
-			wsz = write(ofd, buf + pos, sz - pos);
-			if (wsz < 0) {
-				error("error writing pack (%s)",
-				      strerror(errno));
-				close(ofd);
-				unlink(tmpfile);
-				return -1;
-			}
-			pos += wsz;
-		}
-	}
-	close(ofd);
-	return finish_pack(tmpfile);
-}
-
 static int clone_pack(int fd[2], int nr_match, char **match)
 {
 	struct ref *refs;
@@ -257,7 +123,7 @@ static int clone_pack(int fd[2], int nr_
 	}
 	clone_handshake(fd, refs);
 
-	status = clone_without_unpack(fd);
+	status = receive_keep_pack(fd, "git-clone-pack");
 
 	if (!status) {
 		if (nr_match == 0)
diff --git a/fetch-clone.c b/fetch-clone.c
new file mode 100644
index 0000000..2b2aa15
--- /dev/null
+++ b/fetch-clone.c
@@ -0,0 +1,172 @@
+#include "cache.h"
+#include <sys/wait.h>
+
+static int finish_pack(const char *pack_tmp_name, const char *me)
+{
+	int pipe_fd[2];
+	pid_t pid;
+	char idx[PATH_MAX];
+	char final[PATH_MAX];
+	char hash[41];
+	unsigned char sha1[20];
+	char *cp;
+	int err = 0;
+
+	if (pipe(pipe_fd) < 0)
+		die("%s: unable to set up pipe", me);
+
+	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
+	cp = strrchr(idx, '/');
+	memcpy(cp, "/pidx", 5);
+
+	pid = fork();
+	if (pid < 0)
+		die("git-clone-pack: unable to fork off git-index-pack");
+	if (!pid) {
+		close(0);
+		dup2(pipe_fd[1], 1);
+		close(pipe_fd[0]);
+		close(pipe_fd[1]);
+		execlp("git-index-pack","git-index-pack",
+		       "-o", idx, pack_tmp_name, NULL);
+		error("cannot exec git-index-pack <%s> <%s>",
+		      idx, pack_tmp_name);
+		exit(1);
+	}
+	close(pipe_fd[1]);
+	if (read(pipe_fd[0], hash, 40) != 40) {
+		error("%s: unable to read from git-index-pack", me);
+		err = 1;
+	}
+	close(pipe_fd[0]);
+
+	for (;;) {
+		int status, code;
+		int retval = waitpid(pid, &status, 0);
+
+		if (retval < 0) {
+			if (errno == EINTR)
+				continue;
+			error("waitpid failed (%s)", strerror(retval));
+			goto error_die;
+		}
+		if (WIFSIGNALED(status)) {
+			int sig = WTERMSIG(status);
+			error("git-index-pack died of signal %d", sig);
+			goto error_die;
+		}
+		if (!WIFEXITED(status)) {
+			error("git-index-pack died of unnatural causes %d",
+			      status);
+			goto error_die;
+		}
+		code = WEXITSTATUS(status);
+		if (code) {
+			error("git-index-pack died with error code %d", code);
+			goto error_die;
+		}
+		if (err)
+			goto error_die;
+		break;
+	}
+	hash[40] = 0;
+	if (get_sha1_hex(hash, sha1)) {
+		error("git-index-pack reported nonsense '%s'", hash);
+		goto error_die;
+	}
+	/* Now we have pack in pack_tmp_name[], and
+	 * idx in idx[]; rename them to their final names.
+	 */
+	snprintf(final, sizeof(final),
+		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
+	move_temp_to_file(pack_tmp_name, final);
+	chmod(final, 0444);
+	snprintf(final, sizeof(final),
+		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
+	move_temp_to_file(idx, final);
+	chmod(final, 0444);
+	return 0;
+
+ error_die:
+	unlink(idx);
+	unlink(pack_tmp_name);
+	exit(1);
+}
+
+int receive_unpack_pack(int fd[2], const char *me, int quiet)
+{
+	int status;
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0)
+		die("%s: unable to fork off git-unpack-objects", me);
+	if (!pid) {
+		dup2(fd[0], 0);
+		close(fd[0]);
+		close(fd[1]);
+		execlp("git-unpack-objects", "git-unpack-objects",
+		       quiet ? "-q" : NULL, NULL);
+		die("git-unpack-objects exec failed");
+	}
+	close(fd[0]);
+	close(fd[1]);
+	while (waitpid(pid, &status, 0) < 0) {
+		if (errno != EINTR)
+			die("waiting for git-unpack-objects: %s",
+			    strerror(errno));
+	}
+	if (WIFEXITED(status)) {
+		int code = WEXITSTATUS(status);
+		if (code)
+			die("git-unpack-objects died with error code %d",
+			    code);
+		return 0;
+	}
+	if (WIFSIGNALED(status)) {
+		int sig = WTERMSIG(status);
+		die("git-unpack-objects died of signal %d", sig);
+	}
+	die("git-unpack-objects died of unnatural causes %d", status);
+}
+
+int receive_keep_pack(int fd[2], const char *me)
+{
+	char tmpfile[PATH_MAX];
+	int ofd, ifd;
+
+	ifd = fd[0];
+	snprintf(tmpfile, sizeof(tmpfile),
+		 "%s/pack/tmp-XXXXXX", get_object_directory());
+	ofd = mkstemp(tmpfile);
+	if (ofd < 0)
+		return error("unable to create temporary file %s", tmpfile);
+
+	while (1) {
+		char buf[8192];
+		ssize_t sz, wsz, pos;
+		sz = read(ifd, buf, sizeof(buf));
+		if (sz == 0)
+			break;
+		if (sz < 0) {
+			error("error reading pack (%s)", strerror(errno));
+			close(ofd);
+			unlink(tmpfile);
+			return -1;
+		}
+		pos = 0;
+		while (pos < sz) {
+			wsz = write(ofd, buf + pos, sz - pos);
+			if (wsz < 0) {
+				error("error writing pack (%s)",
+				      strerror(errno));
+				close(ofd);
+				unlink(tmpfile);
+				return -1;
+			}
+			pos += wsz;
+		}
+	}
+	close(ofd);
+	return finish_pack(tmpfile, me);
+}
diff --git a/fetch-pack.c b/fetch-pack.c
index 58ba209..2528053 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -3,13 +3,12 @@
 #include "pkt-line.h"
 #include "commit.h"
 #include "tag.h"
-#include <time.h>
-#include <sys/wait.h>
 
+static int keep_pack;
 static int quiet;
 static int verbose;
 static const char fetch_pack_usage[] =
-"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [-q] [-v] [-k] [--exec=upload-pack] [host:]directory <refs>...";
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE	(1U << 0)
@@ -363,7 +362,6 @@ static int fetch_pack(int fd[2], int nr_
 	struct ref *ref;
 	unsigned char sha1[20];
 	int status;
-	pid_t pid;
 
 	get_remote_heads(fd[0], &ref, 0, NULL, 0);
 	if (server_supports("multi_ack")) {
@@ -381,40 +379,22 @@ static int fetch_pack(int fd[2], int nr_
 	}
 	if (find_common(fd, sha1, ref) < 0)
 		fprintf(stderr, "warning: no common commits\n");
-	pid = fork();
-	if (pid < 0)
-		die("git-fetch-pack: unable to fork off git-unpack-objects");
-	if (!pid) {
-		dup2(fd[0], 0);
-		close(fd[0]);
-		close(fd[1]);
-		execlp("git-unpack-objects", "git-unpack-objects",
-		       quiet ? "-q" : NULL, NULL);
-		die("git-unpack-objects exec failed");
-	}
-	close(fd[0]);
-	close(fd[1]);
-	while (waitpid(pid, &status, 0) < 0) {
-		if (errno != EINTR)
-			die("waiting for git-unpack-objects: %s", strerror(errno));
-	}
-	if (WIFEXITED(status)) {
-		int code = WEXITSTATUS(status);
-		if (code)
-			die("git-unpack-objects died with error code %d", code);
-all_done:
-		while (ref) {
-			printf("%s %s\n",
-			       sha1_to_hex(ref->old_sha1), ref->name);
-			ref = ref->next;
-		}
-		return 0;
-	}
-	if (WIFSIGNALED(status)) {
-		int sig = WTERMSIG(status);
-		die("git-unpack-objects died of signal %d", sig);
+
+	if (keep_pack)
+		status = receive_keep_pack(fd, "git-fetch-pack");
+	else
+		status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
+
+	if (status)
+		die("git-fetch-pack: fetch failed.");
+
+ all_done:
+	while (ref) {
+		printf("%s %s\n",
+		       sha1_to_hex(ref->old_sha1), ref->name);
+		ref = ref->next;
 	}
-	die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
+	return 0;
 }
 
 int main(int argc, char **argv)
@@ -440,6 +420,10 @@ int main(int argc, char **argv)
 				quiet = 1;
 				continue;
 			}
+			if (!strcmp("-k", arg)) {
+				keep_pack = 1;
+				continue;
+			}
 			if (!strcmp("-v", arg)) {
 				verbose = 1;
 				continue;
-- 
0.99.9n

^ permalink raw reply related	[relevance 7%]

* [PATCH] Introduce core.sharedrepository
@ 2005-12-22 22:13 16% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-12-22 22:13 UTC (permalink / raw)
  To: git, junkio


This is the second attempt, after Junio convinced me that my simple approach
to set umask was misguided.

If the config variable 'core.sharedrepository' is set, the directories

	$GIT_DIR/objects/
	$GIT_DIR/objects/??
	$GIT_DIR/objects/pack
	$GIT_DIR/refs
	$GIT_DIR/refs/heads
	$GIT_DIR/refs/heads/tags

are set group writable (and g+s, since the git group may be not the primary
group of all users).

Since all files are written as lock files first,
and then moved to their destination, they do not have to be group writable.
Indeed, if this leads to problems you found a bug.

Note that -- as in my first attempt -- the config variable is set in the
function which checks the repository format. If this were done in
git_default_config instead, a lot of programs would need to be modified
to call git_config(git_default_config) first.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 cache.h     |    1 +
 setup.c     |    4 ++++
 sha1_file.c |   21 +++++++++++++++++++++
 3 files changed, 26 insertions(+), 0 deletions(-)

1a164f16e90378ba66e70e6082266645d3b45c57
diff --git a/cache.h b/cache.h
index cb87bec..0f875dd 100644
--- a/cache.h
+++ b/cache.h
@@ -159,6 +159,7 @@ extern void rollback_index_file(struct c
 extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
+extern int shared_repository;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
diff --git a/setup.c b/setup.c
index d3556ed..3de372e 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,7 @@
 #include "cache.h"
 
+int shared_repository = 0;
+
 const char *prefix_path(const char *prefix, int len, const char *path)
 {
 	const char *orig = path;
@@ -180,6 +182,8 @@ int check_repository_format_version(cons
 {
        if (strcmp(var, "core.repositoryformatversion") == 0)
                repository_format_version = git_config_int(var, value);
+	else if (strcmp(var, "core.sharedrepository") == 0)
+		shared_repository = git_config_bool(var, value);
        return 0;
 }
 
diff --git a/sha1_file.c b/sha1_file.c
index d451a94..e109a07 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -48,6 +48,21 @@ int get_sha1_hex(const char *hex, unsign
 	return 0;
 }
 
+static int make_group_writable(const char *path)
+{
+	struct stat st;
+
+	if (lstat(path, &st) < 0)
+		return -1;
+	if (st.st_mode & S_IWUSR)
+		st.st_mode |= S_IWGRP;
+	if (S_ISDIR(st.st_mode))
+		st.st_mode |= S_ISGID;
+	if (chmod(path, st.st_mode) < 0)
+		return -2;
+	return 0;
+}
+
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path;
@@ -64,6 +79,10 @@ int safe_create_leading_directories(char
 				*pos = '/';
 				return -1;
 			}
+		if (shared_repository && make_group_writable(path)) {
+			*pos = '/';
+			return -2;
+		}
 		*pos++ = '/';
 	}
 	return 0;
@@ -1241,6 +1260,8 @@ static int link_temp_to_file(const char 
 		if (dir) {
 			*dir = 0;
 			mkdir(filename, 0777);
+			if (shared_repository && make_group_writable(filename))
+				return -2;
 			*dir = '/';
 			if (!link(tmpfile, filename))
 				return 0;
-- 
1.0.GIT

^ permalink raw reply related	[relevance 16%]

* [PATCH] git-init-db: initialize shared repositories with --shared
@ 2005-12-22 22:19 14% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-12-22 22:19 UTC (permalink / raw)
  To: git, junkio


Now you can say

	git-init-db --shared

if you want other users to be able to push into that repository.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	So, I lied in my last message. This patch actually changes the
	modes of the $GIT_DIR/{objects,objects/pack,refs,refs/heads,
	refs/tags} directories.

	I just forgot to commit this before sending the patch :-(

 cache.h     |    1 +
 init-db.c   |   36 ++++++++++++++++++++++++++----------
 sha1_file.c |    2 +-
 3 files changed, 28 insertions(+), 11 deletions(-)

e60956946509622bda221cea567f841568f4cd20
diff --git a/cache.h b/cache.h
index 0f875dd..63acc72 100644
--- a/cache.h
+++ b/cache.h
@@ -184,6 +184,7 @@ extern const unsigned char null_sha1[20]
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+int make_group_writable(const char *path);
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
 char *enter_repo(char *path, int strict);
diff --git a/init-db.c b/init-db.c
index c58b92d..b66b5cd 100644
--- a/init-db.c
+++ b/init-db.c
@@ -9,7 +9,7 @@
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
 #endif
 
-static void safe_create_dir(const char *dir)
+static void safe_create_dir(const char *dir, int share)
 {
 	if (mkdir(dir, 0777) < 0) {
 		if (errno != EEXIST) {
@@ -17,6 +17,11 @@ static void safe_create_dir(const char *
 			exit(1);
 		}
 	}
+
+	if (shared_repository && share && make_group_writable(dir)) {
+		fprintf(stderr, "Could not make %s writable by group\n", dir);
+		exit(2);
+	}
 }
 
 static int copy_file(const char *dst, const char *src, int mode)
@@ -32,6 +37,11 @@ static int copy_file(const char *dst, co
 	}
 	status = copy_fd(fdi, fdo);
 	close(fdo);
+
+	if (shared_repository && !status && (mode & 0200) &&
+			make_group_writable(dst))
+		return -1;
+
 	return status;
 }
 
@@ -48,7 +58,7 @@ static void copy_templates_1(char *path,
 	 * with the way the namespace under .git/ is organized, should
 	 * be really carefully chosen.
 	 */
-	safe_create_dir(path);
+	safe_create_dir(path, 0);
 	while ((de = readdir(dir)) != NULL) {
 		struct stat st_git, st_template;
 		int namelen;
@@ -176,11 +186,11 @@ static void create_default_files(const c
 	 * Create .git/refs/{heads,tags}
 	 */
 	strcpy(path + len, "refs");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path + len, "refs/heads");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path + len, "refs/tags");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 
 	/* First copy the templates -- we might have the default
 	 * config file there, in which case we would want to read
@@ -220,7 +230,7 @@ static void create_default_files(const c
 }
 
 static const char init_db_usage[] =
-"git-init-db [--template=<template-directory>]";
+"git-init-db [--template=<template-directory>] [--shared]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -239,6 +249,8 @@ int main(int argc, char **argv)
 		char *arg = argv[1];
 		if (!strncmp(arg, "--template=", 11))
 			template_dir = arg+11;
+		else if (!strcmp(arg, "--shared"))
+			shared_repository = 1;
 		else
 			die(init_db_usage);
 	}
@@ -251,7 +263,7 @@ int main(int argc, char **argv)
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
-	safe_create_dir(git_dir);
+	safe_create_dir(git_dir, 0);
 
 	/* Check to see if the repository version is right.
 	 * Note that a newly created repository does not have
@@ -270,10 +282,14 @@ int main(int argc, char **argv)
 	path = xmalloc(len + 40);
 	memcpy(path, sha1_dir, len);
 
-	safe_create_dir(sha1_dir);
+	safe_create_dir(sha1_dir, 1);
 	strcpy(path+len, "/pack");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path+len, "/info");
-	safe_create_dir(path);
+	safe_create_dir(path, 0);
+
+	if (shared_repository)
+		git_config_set("core.sharedRepository", "true");
+
 	return 0;
 }
diff --git a/sha1_file.c b/sha1_file.c
index e109a07..10d63f1 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -48,7 +48,7 @@ int get_sha1_hex(const char *hex, unsign
 	return 0;
 }
 
-static int make_group_writable(const char *path)
+int make_group_writable(const char *path)
 {
 	struct stat st;
 
-- 
1.0.GIT

^ permalink raw reply related	[relevance 14%]

* [PATCH 3/4] add xmktime() function that always accounts for the TZ env
  @ 2005-12-24 12:13 15% ` Eric Wong
  0 siblings, 0 replies; 200+ results
From: Eric Wong @ 2005-12-24 12:13 UTC (permalink / raw)
  To: git list

This function was added because mktime in dietlibc doesn't seem to
account for the TZ env.  Also, xmktime() now shares the same
always-summer bug TZ parsing elsewhere, so at least we can
be wrong about summer consistently.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 cache.h           |    2 ++
 convert-objects.c |    4 ++--
 date.c            |   30 ++++++++++++++++++++++++++----
 3 files changed, 30 insertions(+), 6 deletions(-)

3b0763ae6fce6c69021e1216660f4c0ee301512b
diff --git a/cache.h b/cache.h
index cb87bec..c5ff4b7 100644
--- a/cache.h
+++ b/cache.h
@@ -5,6 +5,7 @@
 
 #include SHA1_HEADER
 #include <zlib.h>
+#include <time.h>
 
 #if ZLIB_VERNUM < 0x1200
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
@@ -236,6 +237,7 @@ extern void *read_object_with_reference(
 
 const char *show_date(unsigned long time, int timezone);
 int parse_date(const char *date, char *buf, int bufsize);
+time_t xmktime(struct tm *tm);
 void datestamp(char *buf, int bufsize);
 unsigned long approxidate(const char *);
 
diff --git a/convert-objects.c b/convert-objects.c
index b49bce2..0fe1229 100644
--- a/convert-objects.c
+++ b/convert-objects.c
@@ -178,7 +178,7 @@ static unsigned long parse_oldstyle_date
 		const char *next = strptime(buf, *fmt, &tm);
 		if (next) {
 			if (!*next)
-				return mktime(&tm);
+				return xmktime(&tm);
 			buf = next;
 		} else {
 			const char **p = timezones;
@@ -195,7 +195,7 @@ static unsigned long parse_oldstyle_date
 		fmt++;
 	} while (*buf && *fmt);
 	printf("left: %s\n", buf);
-	return mktime(&tm);				
+	return xmktime(&tm);				
 }
 
 static int convert_date_line(char *dst, void **buf, unsigned long *sp)
diff --git a/date.c b/date.c
index 3e11500..5596476 100644
--- a/date.c
+++ b/date.c
@@ -141,6 +141,28 @@ static int match_string(const char *date
 	return i;
 }
 
+time_t xmktime(struct tm *tm)
+{
+	time_t ret = my_mktime(tm);
+	char * tz = getenv("TZ");
+
+	if (tz) {
+		int i;
+		for (i = 0; i < NR_TZ; i++) {
+			int match = match_string(tz, timezone_names[i].name);
+			if (match >= 3) {
+				int off = timezone_names[i].offset;
+
+				/* This is bogus, but we like summer */
+				off += timezone_names[i].dst;
+				
+				ret += 60*off;
+			}
+		}
+	}
+	return ret;
+}
+
 static int skip_alpha(const char *date)
 {
 	int i = 0;
@@ -436,10 +458,10 @@ int parse_date(const char *date, char *r
 		date += match;
 	}
 
-	/* mktime uses local timezone */
+	/* (x)mktime uses local timezone */
 	then = my_mktime(&tm); 
 	if (offset == -1)
-		offset = (then - mktime(&tm)) / 60;
+		offset = (then - xmktime(&tm)) / 60;
 
 	if (then == -1)
 		return -1;
@@ -464,7 +486,7 @@ void datestamp(char *buf, int bufsize)
 
 static void update_tm(struct tm *tm, unsigned long sec)
 {
-	time_t n = mktime(tm) - sec;
+	time_t n = xmktime(tm) - sec;
 	localtime_r(&n, tm);
 }
 
@@ -642,5 +664,5 @@ unsigned long approxidate(const char *da
 		tm.tm_mday = number;
 	if (tm.tm_mon > now.tm_mon)
 		tm.tm_year--;
-	return mktime(&tm);
+	return xmktime(&tm);
 }
-- 
1.0.GIT

^ permalink raw reply related	[relevance 15%]

* [PATCH] add strcpy_user_path() and use it in init-db.c and git.c
@ 2005-12-24 12:20 15% Eric Wong
  0 siblings, 0 replies; 200+ results
From: Eric Wong @ 2005-12-24 12:20 UTC (permalink / raw)
  To: git list

strcpy_user_path(dest,src) acts just like strcpy() except tildes
in src are expanded appropriately to point to a user's home
directory.

The following expansions are supported:

~user/path	reads home directory from getpwnam()
~/path	 	reads home directory from $HOME env,
		or getpwuid() if $HOME is not set

This patch makes it easier for an ordinary user to share compiled
binaries across different machines, especially if they have different
account names and home directories on those machines.

Hint: build git with: make 'prefix=~'

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 cache.h   |    1 +
 git.c     |    6 ++++++
 init-db.c |    3 ++-
 path.c    |   41 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 50 insertions(+), 1 deletions(-)

c46a17b746572e6d16aa026de50d7911eddf8664
diff --git a/cache.h b/cache.h
index c5ff4b7..041bf94 100644
--- a/cache.h
+++ b/cache.h
@@ -184,6 +184,7 @@ extern const unsigned char null_sha1[20]
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+char * strcpy_user_path(char *dest, const char *path);
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
 char *enter_repo(char *path, int strict);
diff --git a/git.c b/git.c
index 434a3d9..15f4c69 100644
--- a/git.c
+++ b/git.c
@@ -12,6 +12,8 @@
 #include <termios.h>
 #include "git-compat-util.h"
 
+extern char * strcpy_user_path(char *dest, const char *path);
+
 #ifndef PATH_MAX
 # define PATH_MAX 4096
 #endif
@@ -234,6 +236,7 @@ int main(int argc, char **argv, char **e
 {
 	char git_command[PATH_MAX + 1];
 	char wd[PATH_MAX + 1];
+	char tmp[PATH_MAX + 1];
 	int i, len, show_help = 0;
 	char *exec_path = getenv("GIT_EXEC_PATH");
 
@@ -269,6 +272,9 @@ int main(int argc, char **argv, char **e
 			cmd_usage(NULL, NULL);
 	}
 
+	strcpy_user_path(tmp, exec_path);
+	exec_path = tmp;
+
 	if (i >= argc || show_help) {
 		if (i >= argc)
 			cmd_usage(exec_path, NULL);
diff --git a/init-db.c b/init-db.c
index ead37b5..468c93a 100644
--- a/init-db.c
+++ b/init-db.c
@@ -119,7 +119,8 @@ static void copy_templates(const char *g
 
 	if (!template_dir)
 		template_dir = DEFAULT_GIT_TEMPLATE_DIR;
-	strcpy(template_path, template_dir);
+	strcpy_user_path(template_path, template_dir);
+	
 	template_len = strlen(template_path);
 	if (template_path[template_len-1] != '/') {
 		template_path[template_len++] = '/';
diff --git a/path.c b/path.c
index 334b2bd..3caa188 100644
--- a/path.c
+++ b/path.c
@@ -131,6 +131,47 @@ int validate_symref(const char *path)
 	return -1;
 }
 
+char * strcpy_user_path(char *dest, const char *path)
+{
+	if (path[0] == '~') {
+		struct passwd *pw;
+
+		if (path[1] == '/' || path[1] == '\0') {
+			char *home;
+			
+			if (!(home = getenv("HOME"))) {
+				pw = getpwuid(getuid());
+				if (pw && pw->pw_dir)
+					home = pw->pw_dir;
+			}
+				
+			strcpy(dest, home);
+			
+			if (path[1] == '/')
+				strcat(dest, path + 1);
+		} else {
+			char *slash;
+			
+			if ((slash = strchr(path,'/'))) {
+				memcpy(pathname, path + 1, slash - path - 1);
+				pathname[slash - path] = '\0';
+				pw = getpwnam(pathname);
+			} else
+				pw = getpwnam(path + 1);
+
+			if (pw && pw->pw_dir) {
+				strcpy(dest, pw->pw_dir);
+				if (slash)
+					strcat(dest,slash);
+			} else
+				strcpy(dest, path);
+		}
+	} else
+		strcpy(dest, path);
+
+	return dest;
+}
+
 static char *user_path(char *buf, char *path, int sz)
 {
 	struct passwd *pw;
-- 
1.0.GIT

^ permalink raw reply related	[relevance 15%]

* Re: Howto send many commits as mail-patches?
  @ 2006-01-03 17:24 48% ` Ryan Anderson
  0 siblings, 0 replies; 200+ results
From: Ryan Anderson @ 2006-01-03 17:24 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: git

On Tue, Jan 03, 2006 at 12:38:59PM +0100, Sam Ravnborg wrote:
> Hi all.
> 
> I have a collection of commits in my GIT repository that I like to send
> out to linux-kernel.
> But my initial experiments with git-send-emails.perl fall out bad.
> 
> I did the following:
> 
> 1) First I created a mbox with the patches:
> git format-patch -n --mbox --stdout -M -B b286e39207237e2f6929959372bf66d9a8d05a82 > mbox


> The mbox looked OK. -M -B were from the man page and since the patchset
> includes a number of renames it made the mbox considerably smaller.
> 
> So I went on an tried to send the mails:
> 
> It just send out two huge mails containing all of the mbox.
> Also it cc:ed all people included in "Signed-off-by". That is sometimes
> a nice feature but for testing I like it to be optional.
> 
> Can someone give me a nice howto so I can see how to send out the mails.

Try:
	mkdir ../pending/
	git format-patch -n --mbox -o ../pending/ -M -B b286e39207237e2f6929959372bf66d9a8d05a82
	git-send-email.perl --from "Sam Ravnborg <sam@ravnborg.org>" --to "sam@ravnborg.org" --chain-reply-to "" ../pending/

With this method, you can examine the files in ../pending/, edit patch
comments if you want, add an "introductory" mail, etc.

The Signed-off-by: cc:ing is currently not something that can be
disabled, but you can do something like this to stop it temporarily:

(cut and pasted, so it probably won't directly apply)
diff --git a/git-send-email.perl b/git-send-email.perl
index ec1428d..9c7d0b8 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -322,7 +322,7 @@ foreach my $t (@files) {
                        }
                } else {
                        $message .=  $_;
-                       if (/^Signed-off-by: (.*)$/i) {
+                       if (/^XSigned-off-by: (.*)$/i) {
                                my $c = $1;
                                chomp $c;
                                push @cc, $c;

Hope that helped,

-- 

Ryan Anderson
  sometimes Pug Majere

^ permalink raw reply related	[relevance 48%]

* Re: [ANNOUNCE] GIT 1.0.7
  @ 2006-01-07  9:56 17%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-01-07  9:56 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明; +Cc: git

Junio C Hamano <junkio@cox.net> writes:

> YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> writes:
>
>> Allow compilation w/ gcc 2.95.4.
>> (Or, it is okay to replace path[] with path[0].)
>
> This is unfortunate; path[] is the correct C (and path[0] is
> not---it is an gcc extension), and we have quite a few of them.
> Last time somebody wanted to change all of them to path[] we
> found out gcc 2.95 did not like it, and ended up doing path[0]
> form.  So I'd say change it to path[0] for now.

Here is what I am planning to merge into the master/maint.  The
patch is for maint which does not ship with describe, but the
problematic path[] can be updated to path[FLEX_ARRAY] as others
when merging it to the master branch.

-- >8 --
Subject: [PATCH] Compilation: zero-length array declaration.

ISO C99 (and GCC 3.x or later) lets you write a flexible array
at the end of a structure, like this:

	struct frotz {
		int xyzzy;
		char nitfol[]; /* more */
	};

GCC 2.95 lets you to do this with "char nitfol[0]";
unfortunately this is not allowed by ISO C90.

This declares such construct like this:

	struct frotz {
		int xyzzy;
		char nitfol[FLEX_ARRAY]; /* more */
	};

and git-compat-util.h defines FLEX_ARRAY to 0 for gcc 2.95 and
empty for others.

Although I have not tried this myself, if you are using a C90 C
compiler, you should be able to override this with
CFLAGS=-DFLEX_ARRAY=1 from the command line of "make".

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 blob.c            |    2 +-
 cache.h           |    9 +++++----
 commit.c          |    2 +-
 git-compat-util.h |    8 ++++++++
 ls-files.c        |    2 +-
 object.c          |    2 +-
 object.h          |    2 +-
 receive-pack.c    |    2 +-
 tag.c             |    2 +-
 tree.c            |    2 +-
 10 files changed, 21 insertions(+), 12 deletions(-)

33751f1c4e23e928f18a019292cb8562cd7c7f76
diff --git a/blob.c b/blob.c
index ea52ad5..84ec121 100644
--- a/blob.c
+++ b/blob.c
@@ -1,5 +1,5 @@
-#include "blob.h"
 #include "cache.h"
+#include "blob.h"
 #include <stdlib.h>
 
 const char *blob_type = "blob";
diff --git a/cache.h b/cache.h
index cb87bec..5fd2687 100644
--- a/cache.h
+++ b/cache.h
@@ -81,7 +81,7 @@ struct cache_entry {
 	unsigned int ce_size;
 	unsigned char sha1[20];
 	unsigned short ce_flags;
-	char name[0];
+	char name[FLEX_ARRAY]; /* more */
 };
 
 #define CE_NAMEMASK  (0x0fff)
@@ -257,7 +257,7 @@ extern int checkout_entry(struct cache_e
 extern struct alternate_object_database {
 	struct alternate_object_database *next;
 	char *name;
-	char base[0]; /* more */
+	char base[FLEX_ARRAY]; /* more */
 } *alt_odb_list;
 extern void prepare_alt_odb(void);
 
@@ -271,7 +271,8 @@ extern struct packed_git {
 	unsigned int pack_use_cnt;
 	int pack_local;
 	unsigned char sha1[20];
-	char pack_name[0]; /* something like ".git/objects/pack/xxxxx.pack" */
+	/* something like ".git/objects/pack/xxxxx.pack" */
+	char pack_name[FLEX_ARRAY]; /* more */
 } *packed_git;
 
 struct pack_entry {
@@ -286,7 +287,7 @@ struct ref {
 	unsigned char new_sha1[20];
 	unsigned char force;
 	struct ref *peer_ref; /* when renaming */
-	char name[0];
+	char name[FLEX_ARRAY]; /* more */
 };
 
 extern int git_connect(int fd[2], char *url, const char *prog);
diff --git a/commit.c b/commit.c
index edd4ded..fb02ba6 100644
--- a/commit.c
+++ b/commit.c
@@ -1,6 +1,6 @@
+#include "cache.h"
 #include "tag.h"
 #include "commit.h"
-#include "cache.h"
 
 int save_commit_buffer = 1;
 
diff --git a/git-compat-util.h b/git-compat-util.h
index c353b27..1a263a6 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1,6 +1,14 @@
 #ifndef GIT_COMPAT_UTIL_H
 #define GIT_COMPAT_UTIL_H
 
+#ifndef FLEX_ARRAY
+#if (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
+#define FLEX_ARRAY 0
+#else
+#define FLEX_ARRAY /* empty */
+#endif
+#endif
+
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/stat.h>
diff --git a/ls-files.c b/ls-files.c
index cd87430..74ec8c0 100644
--- a/ls-files.c
+++ b/ls-files.c
@@ -208,7 +208,7 @@ static int excluded(const char *pathname
 
 struct nond_on_fs {
 	int len;
-	char name[0];
+	char name[FLEX_ARRAY]; /* more */
 };
 
 static struct nond_on_fs **dir;
diff --git a/object.c b/object.c
index cf5931a..1577f74 100644
--- a/object.c
+++ b/object.c
@@ -1,8 +1,8 @@
+#include "cache.h"
 #include "object.h"
 #include "blob.h"
 #include "tree.h"
 #include "commit.h"
-#include "cache.h"
 #include "tag.h"
 
 struct object **objs;
diff --git a/object.h b/object.h
index 336d986..0e76182 100644
--- a/object.h
+++ b/object.h
@@ -9,7 +9,7 @@ struct object_list {
 
 struct object_refs {
 	unsigned count;
-	struct object *ref[0];
+	struct object *ref[FLEX_ARRAY]; /* more */
 };
 
 struct object {
diff --git a/receive-pack.c b/receive-pack.c
index 92878ec..ce986fe 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -24,7 +24,7 @@ struct command {
 	unsigned char updated;
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
-	char ref_name[0];
+	char ref_name[FLEX_ARRAY]; /* more */
 };
 
 static struct command *commands = NULL;
diff --git a/tag.c b/tag.c
index 61ac434..ac0e573 100644
--- a/tag.c
+++ b/tag.c
@@ -1,5 +1,5 @@
-#include "tag.h"
 #include "cache.h"
+#include "tag.h"
 
 const char *tag_type = "tag";
 
diff --git a/tree.c b/tree.c
index e7a7b71..dc1c41e 100644
--- a/tree.c
+++ b/tree.c
@@ -1,8 +1,8 @@
+#include "cache.h"
 #include "tree.h"
 #include "blob.h"
 #include "commit.h"
 #include "tag.h"
-#include "cache.h"
 #include <stdlib.h>
 
 const char *tree_type = "tree";
-- 
1.0.7-g0263

^ permalink raw reply related	[relevance 17%]

* [PATCH 1/2] Remember and use GIT_EXEC_PATH on exec()'s
  @ 2006-01-09 23:35 16% ` Michal Ostrowski
  0 siblings, 0 replies; 200+ results
From: Michal Ostrowski @ 2006-01-09 23:35 UTC (permalink / raw)
  To: git

If git-upload-pack is invoked by ssh, it may have been invoked because
ssh was explicitly told which program to execute on the remote end
(i.e. --exec had been used with git-clone-pack).  In this case, the
git suite may not be in the PATH, and so subsequent exec's by
git-upload-pack (i.e. git-rev-list, git-pack-objects) will fail.

These changes provide for ${bindir} to be stored at compile time in
environment.c. git_setup_exec_path() is implemented; this function
will append GIT_EXEC_PATH or the saved ${bindir} to PATH.

Signed-off-by: Michal Ostrowski <mostrows@watson.ibm.com>

---

 Makefile      |    7 +++++++
 cache.h       |    1 +
 environment.c |   29 +++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 0 deletions(-)

b24fde016c2d7382016b80bc0b9a011db3413bb3
diff --git a/Makefile b/Makefile
index c9c15b5..ffd2a68 100644
--- a/Makefile
+++ b/Makefile
@@ -437,6 +437,13 @@ init-db.o: init-db.c
 	$(CC) -c $(ALL_CFLAGS) \
 		-DDEFAULT_GIT_TEMPLATE_DIR=$(call shellquote,"$(template_dir)") $*.c
 
+# Recompile environment.o if GIT_EXEC_PATH changes
+.environment.GIT_EXEC_PATH:
+	@(test -e $@ && grep -h -e '^$(bindir)$$' $@) || echo $(bindir) > $@
+environment.o: .environment.GIT_EXEC_PATH
+environment.o: CFLAGS+= -DGIT_EXEC_PATH=\"$(bindir)\"
+
+
 $(LIB_OBJS): $(LIB_H)
 $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H)
 $(DIFF_OBJS): diffcore.h
diff --git a/cache.h b/cache.h
index 29c9e81..d73071e 100644
--- a/cache.h
+++ b/cache.h
@@ -244,6 +244,7 @@ unsigned long approxidate(const char *);
 extern int setup_ident(void);
 extern const char *git_author_info(void);
 extern const char *git_committer_info(void);
+extern void git_setup_exec_path(void);
 
 struct checkout {
 	const char *base_dir;
diff --git a/environment.c b/environment.c
index 0596fc6..4dc0249 100644
--- a/environment.c
+++ b/environment.c
@@ -9,6 +9,10 @@
  */
 #include "cache.h"
 
+#ifndef GIT_EXEC_PATH
+#define GIT_EXEC_PATH NULL
+#endif
+
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
@@ -16,6 +20,7 @@ int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 int shared_repository = 0;
+char *git_exec_path = GIT_EXEC_PATH;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
@@ -76,4 +81,28 @@ char *get_graft_file(void)
 	return git_graft_file;
 }
 
+void git_setup_exec_path(void)
+{
+	char *path, *old_path = getenv("PATH");
+	int path_len, len, old_len;
+	char *exec_path = getenv("GIT_EXEC_PATH");
+
+	if (!exec_path)
+		exec_path = git_exec_path;
+
+	len = strlen(exec_path);
+
+	if (!old_path)
+		old_path = "/usr/local/bin:/usr/bin:/bin";
 
+	old_len = strlen(old_path);
+	path_len = len + old_len + 1;
+
+	path = malloc(path_len + 1);
+
+	memcpy(path, old_path, old_len);
+	path[old_len] = ':';
+	memcpy(path + old_len + 1, exec_path, len);
+
+	setenv("PATH", path, 1);
+}
-- 
0.99.9m-g02ad

^ permalink raw reply related	[relevance 16%]

* cygwin-latest: compile errors related to sockaddr_storage, dirent->d_type and dirent->d_ino
@ 2006-01-18 13:47 15% Alex Riesen
  2006-01-20  1:13 17% ` [PATCH] DT_UNKNOWN: do not fully trust existence of DT_UNKNOWN Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Alex Riesen @ 2006-01-18 13:47 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 996 bytes --]

For reasons unknown, cygwin decided to use our sockaddr_storage.
As it is redefined to sockaddr_in it'd cause compilation errors in
cygwin headers. Fixed by first patch, which uses a more git-related
name (can we claim rights for the symbol, being first to use it? :-)

For the other, probably unrelated, reasons, they decided to leave
declarations of DT_* macros in dirent.h without providing dirent->d_type.
This is what NO_DTYPE in the 0002-patch is all about.

And on top of that, they removed dirent->d_ino (or probably replaced
it by __ino32, if at all).
BTW, can we somehow avoid using d_ino? It is referenced only in fsck-objects.c
Anyway, to workaround this I put

  COMPAT_CFLAGS += -Dd_ino=__ino32

It helps, but surely is not the solution.

P.S. For all you poor souls on Win2k, my config.mak contains:

  NO_MMAP = YesPlease
  NO_DTYPE = YesPlease
  COMPAT_CFLAGS += -Dd_ino=__ino32

Just to make it work (at least it's enough for me, even the tests run...)

[-- Attachment #2: 0001-fix-compilation-of-sockaddr_storage.txt --]
[-- Type: text/plain, Size: 1355 bytes --]

>From nobody Mon Sep 17 00:00:00 2001
From: Alex Riesen <raa.lkml@gmail.com>
Date: Wed Jan 18 14:02:54 2006 +0100
Subject: fix compilation of sockaddr_storage

---

 Makefile |    2 +-
 daemon.c |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

59379c380a6c2829c5614aadd4a5492abb8d14c8
diff --git a/Makefile b/Makefile
index f6d9e0a..5782e2a 100644
--- a/Makefile
+++ b/Makefile
@@ -342,7 +342,7 @@ ifdef NO_MMAP
 	COMPAT_OBJS += compat/mmap.o
 endif
 ifdef NO_IPV6
-	ALL_CFLAGS += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
+	ALL_CFLAGS += -DNO_IPV6 -Dsockaddr_stg_git=sockaddr_in
 endif
 
 ifdef PPC_SHA1
diff --git a/daemon.c b/daemon.c
index bb014fa..b424e5e 100644
--- a/daemon.c
+++ b/daemon.c
@@ -277,7 +277,7 @@ static unsigned int children_deleted = 0
 static struct child {
 	pid_t pid;
 	int addrlen;
-	struct sockaddr_storage address;
+	struct sockaddr_stg_git address;
 } live_child[MAX_CHILDREN];
 
 static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
@@ -578,7 +578,7 @@ static int service_loop(int socknum, int
 
 		for (i = 0; i < socknum; i++) {
 			if (pfd[i].revents & POLLIN) {
-				struct sockaddr_storage ss;
+				struct sockaddr_stg_git ss;
 				unsigned int sslen = sizeof(ss);
 				int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
 				if (incoming < 0) {
-- 
1.1.2-ge577




[-- Attachment #3: 0002-fix-compilation-of-dirent-d_type.txt --]
[-- Type: text/plain, Size: 1137 bytes --]

>From nobody Mon Sep 17 00:00:00 2001
From: Alex Riesen <raa.lkml@gmail.com>
Date: Wed Jan 18 14:04:34 2006 +0100
Subject: fix compilation of dirent->d_type

---

 Makefile |    3 +++
 cache.h  |   10 +++++++++-
 2 files changed, 12 insertions(+), 1 deletions(-)

5232f9128ad9d10368525fe709954acc2d6f49b3
diff --git a/Makefile b/Makefile
index 5782e2a..c3bae0f 100644
--- a/Makefile
+++ b/Makefile
@@ -329,6 +329,9 @@ ifdef NEEDS_NSL
 	LIBS += -lnsl
 	SIMPLE_LIB += -lnsl
 endif
+ifdef NO_DTYPE
+	COMPAT_CFLAGS += -DNO_DTYPE
+endif
 ifdef NO_STRCASESTR
 	COMPAT_CFLAGS += -DNO_STRCASESTR
 	COMPAT_OBJS += compat/strcasestr.o
diff --git a/cache.h b/cache.h
index 29c9e81..3846fb9 100644
--- a/cache.h
+++ b/cache.h
@@ -10,13 +10,21 @@
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
-#ifdef DT_UNKNOWN
+#ifndef NO_DTYPE
 #define DTYPE(de)	((de)->d_type)
 #else
+#ifndef DT_UNKNOWN
 #define DT_UNKNOWN	0
+#endif
+#ifndef DT_DIR
 #define DT_DIR		1
+#endif
+#ifndef DT_REG
 #define DT_REG		2
+#endif
+#ifndef DT_LNK
 #define DT_LNK		3
+#endif
 #define DTYPE(de)	DT_UNKNOWN
 #endif
 
-- 
1.1.2-ge577



^ permalink raw reply related	[relevance 15%]

* [PATCH] Support precise tracking of file modes
  @ 2006-01-19  9:41 18%           ` Petr Baudis
  0 siblings, 0 replies; 200+ results
From: Petr Baudis @ 2006-01-19  9:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ryan Anderson, Adam Hunt, git

Dear diary, on Thu, Jan 19, 2006 at 08:50:22AM CET, I got a letter
where Junio C Hamano <junkio@cox.net> said that...
> Ryan Anderson <ryan@michonline.com> writes:
> 
> > Junio C Hamano wrote:
> >> Adam Hunt <kinema@gmail.com> writes:
> >> 
> >> 
> >>>Do you have any more details by chance?  Does it work?  Does it work
> >>>well?  How does one do it?
> >> 
> >> 
> >> I personally feel it is a horrible and stupid thing to do, if by
> >> "version control /etc" you mean to have /.git which controls
> >> /etc/hosts and stuff in place.  It would work (git does not
> >> refuse to run as root).  But being a *source* control system, we
> >> deliberately refuse to store the full permission bits, so if
> >> your /etc/shadow is mode 0600 while /etc/hosts is mode 0644, you
> >> have to make sure they stay that way after checking things out.
> >
> > This is, admittedly, a major problem.
> 
> An SCM is not a replacement of a backup.

It seems that this is mostly an artificial imposition and it's annoying.
Hey, I need to leave for an exam in 15 minutes and I have few urgent
items in my Cogito TODO (sorry, Pavel!), but I couldn't resist.

Taking "quick'n'dirty" to the extreme _and_ combining it with Linus'
attitude to testing and documentation... ;-)

diff --git a/cache.h b/cache.h
index 29c9e81..0311066 100644
--- a/cache.h
+++ b/cache.h
@@ -94,7 +94,9 @@ struct cache_entry {
 #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 #define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
 
-#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
+extern int track_filemode;
+
+#define ce_permissions(mode) (track_filemode ? (mode) : (((mode) & 0100) ? 0755 : 0644))
 static inline unsigned int create_ce_mode(unsigned int mode)
 {
 	if (S_ISLNK(mode))
diff --git a/checkout-index.c b/checkout-index.c
index 53dd8cb..b073baa 100644
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -115,6 +115,8 @@ int main(int argc, char **argv)
 	int newfd = -1;
 	int all = 0;
 
+	git_config(git_default_config);
+
 	prefix = setup_git_directory();
 	prefix_length = prefix ? strlen(prefix) : 0;
 
diff --git a/config.c b/config.c
index 8355224..a92ee0f 100644
--- a/config.c
+++ b/config.c
@@ -222,6 +222,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "core.trackallfilemodes")) {
+		track_filemode = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.symrefsonly")) {
 		only_use_symrefs = git_config_bool(var, value);
 		return 0;
diff --git a/entry.c b/entry.c
index 410b758..493f2b9 100644
--- a/entry.c
+++ b/entry.c
@@ -87,6 +87,11 @@ static int write_entry(struct cache_entr
 			return error("git-checkout-index: unable to create file %s (%s)",
 				path, strerror(errno));
 		}
+		if (track_filemode) {
+			if (fchmod(fd, ntohl(ce->ce_mode)) < 0)
+				return error("git-checkout-index: unable to chmod file %s (%s)",
+					path, strerror(errno));
+		}
 		wrote = write(fd, new, size);
 		close(fd);
 		free(new);
diff --git a/environment.c b/environment.c
index 0596fc6..53248ec 100644
--- a/environment.c
+++ b/environment.c
@@ -12,6 +12,7 @@
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
+int track_filemode = 0;
 int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
diff --git a/fsck-objects.c b/fsck-objects.c
index 90e638e..719add2 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -174,7 +174,8 @@ static int fsck_tree(struct tree *item)
 			if (!check_strict)
 				break;
 		default:
-			has_bad_modes = 1;
+			if (!track_filemode || (entry->mode & ~(S_IFREG|0777)))
+				has_bad_modes = 1;
 		}
 
 		if (last) {
diff --git a/read-cache.c b/read-cache.c
index c5474d4..624d2c3 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -98,7 +98,7 @@ static int ce_match_stat_basic(struct ca
 		 * "mode changes"
 		 */
 		if (trust_executable_bit &&
-		    (0100 & (ntohl(ce->ce_mode) ^ st->st_mode)))
+		    ((track_filemode ? 0777 : 0100) & (ntohl(ce->ce_mode) ^ st->st_mode)))
 			changed |= MODE_CHANGED;
 		break;
 	case S_IFLNK:


-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply related	[relevance 18%]

* [PATCH] DT_UNKNOWN: do not fully trust existence of DT_UNKNOWN
  2006-01-18 13:47 15% cygwin-latest: compile errors related to sockaddr_storage, dirent->d_type and dirent->d_ino Alex Riesen
@ 2006-01-20  1:13 17% ` Junio C Hamano
    0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2006-01-20  1:13 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git, Christopher Faylor

The recent Cygwin defines DT_UNKNOWN although it does not have d_type
in struct dirent.  Give an option to tell us not to use d_type on such
platforms.  Hopefully this problem will be transient.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * By sending this out, I am not claiming this is better than
   your version or anything like that.  This is just for
   completeness and convenience, because my other two patches
   touch overlapping areas in the same Makefile.  This patch
   comes after the other two.

 Makefile |    7 +++++++
 cache.h  |    2 +-
 2 files changed, 8 insertions(+), 1 deletions(-)

80a4322a9bfbf0389ba8cb50f674682349f40a3a
diff --git a/Makefile b/Makefile
index 31898f7..84f5d24 100644
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,9 @@ all:
 #
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
 #
+# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
+# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
+#
 # Define NO_STRCASESTR if you don't have strcasestr.
 #
 # Define NO_SETENV if you don't have setenv in the C library.
@@ -233,6 +236,7 @@ ifeq ($(uname_S),SunOS)
 	ALL_CFLAGS += -D__EXTENSIONS__
 endif
 ifeq ($(uname_O),Cygwin)
+	NO_D_TYPE_IN_DIRENT = YesPlease
 	NO_D_INO_IN_DIRENT = YesPlease
 	NO_STRCASESTR = YesPlease
 	NEEDS_LIBICONV = YesPlease
@@ -335,6 +339,9 @@ ifdef NEEDS_NSL
 	LIBS += -lnsl
 	SIMPLE_LIB += -lnsl
 endif
+ifdef NO_D_TYPE_IN_DIRENT
+	ALL_CFLAGS += -DNO_D_TYPE_IN_DIRENT
+endif
 ifdef NO_D_INO_IN_DIRENT
 	ALL_CFLAGS += -DNO_D_INO_IN_DIRENT
 endif
diff --git a/cache.h b/cache.h
index 29c9e81..3d79c55 100644
--- a/cache.h
+++ b/cache.h
@@ -10,7 +10,7 @@
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
-#ifdef DT_UNKNOWN
+#if defined(DT_UNKNOWN) && !NO_D_TYPE_IN_DIRENT
 #define DTYPE(de)	((de)->d_type)
 #else
 #define DT_UNKNOWN	0
-- 
1.1.3-gacdd

^ permalink raw reply related	[relevance 17%]

* Re: [PATCH] DT_UNKNOWN: do not fully trust existence of DT_UNKNOWN
  @ 2006-01-20 19:10 19%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-01-20 19:10 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git, Christopher Faylor

Alex Riesen <raa.lkml@gmail.com> writes:

> On 1/20/06, Junio C Hamano <junkio@cox.net> wrote:
>> The recent Cygwin defines DT_UNKNOWN although it does not have d_type
>> in struct dirent.  Give an option to tell us not to use d_type on such
>> platforms.  Hopefully this problem will be transient.
>
> You still have to #undef all the DT_ macros if you have a somewhat old Cygwin
> (before Christopher removed the macros).
> -

Ah, you mean something like this?

-- >8 --
diff --git a/cache.h b/cache.h
index 8339931..6f13434 100644
--- a/cache.h
+++ b/cache.h
@@ -13,6 +13,10 @@
 #if defined(DT_UNKNOWN) && !NO_D_TYPE_IN_DIRENT
 #define DTYPE(de)	((de)->d_type)
 #else
+#undef DT_UNKNOWN
+#undef DT_DIR
+#undef DT_REG
+#undef DT_LNK
 #define DT_UNKNOWN	0
 #define DT_DIR		1
 #define DT_REG		2

^ permalink raw reply related	[relevance 19%]

* [PATCH] Only use a single parser for tree objects
@ 2006-01-26  6:13 15% Daniel Barkalow
  0 siblings, 0 replies; 200+ results
From: Daniel Barkalow @ 2006-01-26  6:13 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This makes read_tree_recursive and read_tree take a struct tree
instead of a buffer. It also move the declaration of read_tree into
tree.h (where struct tree is defined), and updates ls-tree and
diff-index (the only places that presently use read_tree*()) to use
the new versions.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>

---

 cache.h      |    3 ---
 diff-index.c |    8 ++++----
 ls-tree.c    |    9 ++++-----
 tree.c       |   50 +++++++++++++++++++-------------------------------
 tree.h       |    9 +++++----
 5 files changed, 32 insertions(+), 47 deletions(-)

973280cda82b9ead56881d453c6101e4bf298c94
diff --git a/cache.h b/cache.h
index 6f13434..24a679b 100644
--- a/cache.h
+++ b/cache.h
@@ -210,9 +210,6 @@ extern char *write_sha1_file_prepare(voi
 
 extern int check_sha1_signature(const 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, const char **paths);
-
 extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
 			      size_t bufsize, size_t *bufposn);
 extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
diff --git a/diff-index.c b/diff-index.c
index 87e1061..bbd873b 100644
--- a/diff-index.c
+++ b/diff-index.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "tree.h"
 #include "diff.h"
 
 static int cached_only = 0;
@@ -174,8 +175,7 @@ int main(int argc, const char **argv)
 	unsigned char sha1[20];
 	const char *prefix = setup_git_directory();
 	const char **pathspec = NULL;
-	void *tree;
-	unsigned long size;
+	struct tree *tree;
 	int ret;
 	int allow_options = 1;
 	int i;
@@ -233,10 +233,10 @@ int main(int argc, const char **argv)
 
 	mark_merge_entries();
 
-	tree = read_object_with_reference(sha1, "tree", &size, NULL);
+	tree = parse_tree_indirect(sha1);
 	if (!tree)
 		die("bad tree object %s", tree_name);
-	if (read_tree(tree, size, 1, pathspec))
+	if (read_tree(tree, 1, pathspec))
 		die("unable to read tree object %s", tree_name);
 
 	ret = diff_cache(active_cache, active_nr, pathspec);
diff --git a/ls-tree.c b/ls-tree.c
index d585b6f..d005643 100644
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -84,8 +84,7 @@ static int show_tree(unsigned char *sha1
 int main(int argc, const char **argv)
 {
 	unsigned char sha1[20];
-	char *buf;
-	unsigned long size;
+	struct tree *tree;
 
 	prefix = setup_git_directory();
 	if (prefix && *prefix)
@@ -131,10 +130,10 @@ int main(int argc, const char **argv)
 		usage(ls_tree_usage);
 
 	pathspec = get_pathspec(prefix, argv + 2);
-	buf = read_object_with_reference(sha1, "tree", &size, NULL);
-	if (!buf)
+	tree = parse_tree_indirect(sha1);
+	if (!tree)
 		die("not a tree object");
-	read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
+	read_tree_recursive(tree, "", 0, 0, pathspec, show_tree);
 
 	return 0;
 }
diff --git a/tree.c b/tree.c
index dc1c41e..962ee89 100644
--- a/tree.c
+++ b/tree.c
@@ -74,27 +74,24 @@ static int match_tree_entry(const char *
 	return 0;
 }
 
-int read_tree_recursive(void *buffer, unsigned long size,
+int read_tree_recursive(struct tree *tree,
 			const char *base, int baselen,
 			int stage, const char **match,
 			read_tree_fn_t fn)
 {
-	while (size) {
-		int len = strlen(buffer)+1;
-		unsigned char *sha1 = buffer + len;
-		char *path = strchr(buffer, ' ')+1;
-		unsigned int mode;
-
-		if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
-			return -1;
-
-		buffer = sha1 + 20;
-		size -= len + 20;
-
-		if (!match_tree_entry(base, baselen, path, mode, match))
+	struct tree_entry_list *list;
+	if (parse_tree(tree))
+		return -1;
+	list = tree->entries;
+	while (list) {
+		struct tree_entry_list *current = list;
+		list = list->next;
+		if (!match_tree_entry(base, baselen, current->name, 
+				      current->mode, match))
 			continue;
 
-		switch (fn(sha1, base, baselen, path, mode, stage)) {
+		switch (fn(current->item.any->sha1, base, baselen, 
+			   current->name, current->mode, stage)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -102,28 +99,19 @@ int read_tree_recursive(void *buffer, un
 		default:
 			return -1;
 		}
-		if (S_ISDIR(mode)) {
+		if (current->directory) {
 			int retval;
-			int pathlen = strlen(path);
+			int pathlen = strlen(current->name);
 			char *newbase;
-			void *eltbuf;
-			char elttype[20];
-			unsigned long eltsize;
-
-			eltbuf = read_sha1_file(sha1, elttype, &eltsize);
-			if (!eltbuf || strcmp(elttype, "tree")) {
-				if (eltbuf) free(eltbuf);
-				return -1;
-			}
+
 			newbase = xmalloc(baselen + 1 + pathlen);
 			memcpy(newbase, base, baselen);
-			memcpy(newbase + baselen, path, pathlen);
+			memcpy(newbase + baselen, current->name, pathlen);
 			newbase[baselen + pathlen] = '/';
-			retval = read_tree_recursive(eltbuf, eltsize,
+			retval = read_tree_recursive(current->item.tree,
 						     newbase,
 						     baselen + pathlen + 1,
 						     stage, match, fn);
-			free(eltbuf);
 			free(newbase);
 			if (retval)
 				return -1;
@@ -133,9 +121,9 @@ int read_tree_recursive(void *buffer, un
 	return 0;
 }
 
-int read_tree(void *buffer, unsigned long size, int stage, const char **match)
+int read_tree(struct tree *tree, int stage, const char **match)
 {
-	return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
+	return read_tree_recursive(tree, "", 0, stage, match, read_one_entry);
 }
 
 struct tree *lookup_tree(const unsigned char *sha1)
diff --git a/tree.h b/tree.h
index 57a5bf7..330ab64 100644
--- a/tree.h
+++ b/tree.h
@@ -37,10 +37,11 @@ struct tree *parse_tree_indirect(const u
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);
 
-extern int read_tree_recursive(void *buffer, unsigned long size,
-			const char *base, int baselen,
-			int stage, const char **match,
-			read_tree_fn_t fn);
+extern int read_tree_recursive(struct tree *tree,
+			       const char *base, int baselen,
+			       int stage, const char **match,
+			       read_tree_fn_t fn);
 
+extern int read_tree(struct tree *tree, int stage, const char **paths);
 
 #endif /* TREE_H */
-- 
1.0.GIT

^ permalink raw reply related	[relevance 15%]

* Re: git describe fails without tags
  @ 2006-01-26  8:41 16%   ` Uwe Zeisberger
  0 siblings, 0 replies; 200+ results
From: Uwe Zeisberger @ 2006-01-26  8:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hello Junio,

Junio C Hamano wrote:
> diff --git a/rev-parse.c b/rev-parse.c
> index 0c951af..c1646e4 100644
> --- a/rev-parse.c
> +++ b/rev-parse.c
> @@ -20,6 +20,7 @@ static char *def = NULL;
>  #define REVERSED 1
>  static int show_type = NORMAL;
>  static int symbolic = 0;
> +static int abbrev = 0;
>  static int output_sq = 0;
>  
>  static int revs_count = 0;
> @@ -95,6 +96,8 @@ static void show_rev(int type, const uns
>  		putchar('^');
>  	if (symbolic && name)
>  		show(name);
> +	else if (abbrev)
> +		show(find_unique_abbrev(sha1, abbrev));
>  	else
>  		show(sha1_to_hex(sha1));
>  }
> @@ -195,6 +198,17 @@ int main(int argc, char **argv)
>  				verify = 1;
>  				continue;
>  			}
> +			if (!strcmp(arg, "--abbrev") ||
> +			    !strncmp(arg, "--abbrev=", 9)) {
> +				filter &= ~(DO_FLAGS|DO_NOREV);
> +				verify = 1;
> +				abbrev = DEFAULT_ABBREV;
> +				if (arg[8] == '=')
> +					abbrev = strtoul(arg + 9, NULL, 10);
> +				if (abbrev < 0 || 40 <= abbrev)
> +					abbrev = DEFAULT_ABBREV;
> +				continue;
> +			}
>  			if (!strcmp(arg, "--sq")) {
>  				output_sq = 1;
>  				continue;
I see two things to fix in that patch:

 1) define DEFAULT_ABBREV (e.g. by moving it to cache.h, where
    find_unique_abbrev is defined.)

 2) describe.c allows only abbrev >= 4.  (Allowing values less than 2
    failes, because find_short_object_filename (and maybe others) assume
    len to be at least 2.)  I think 4 is sensible.

This results in the following patch:

--8<--
[PATCH] rev-parse: --abbrev option.

The new option behaves just like --verify, but outputs an abbreviated object
name that is unique within the repository.

This patch is a modification of a suggestion by Junio C Hamano.

Signed-off-by: Uwe Zeisberger <zeisberg@informatik.uni-freiburg.de>

---

 cache.h     |    2 ++
 describe.c  |    1 -
 rev-parse.c |   14 ++++++++++++++
 3 files changed, 16 insertions(+), 1 deletions(-)

0d43ec7461b38d6a1d1563fd7dc2ebf399eabe9e
diff --git a/cache.h b/cache.h
index b493b65..139c670 100644
--- a/cache.h
+++ b/cache.h
@@ -177,6 +177,8 @@ extern int check_repository_format(void)
 #define DATA_CHANGED    0x0020
 #define TYPE_CHANGED    0x0040
 
+#define DEFAULT_ABBREV 8 /* maybe too many */
+
 /* Return a statically allocated filename matching the sha1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
diff --git a/describe.c b/describe.c
index 4866510..6518f06 100644
--- a/describe.c
+++ b/describe.c
@@ -11,7 +11,6 @@ static const char describe_usage[] =
 static int all = 0;	/* Default to annotated tags only */
 static int tags = 0;	/* But allow any tags if --tags is specified */
 
-#define DEFAULT_ABBREV 8 /* maybe too many */
 static int abbrev = DEFAULT_ABBREV;
 
 static int names = 0, allocs = 0;
diff --git a/rev-parse.c b/rev-parse.c
index 0c951af..58cff6f 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -20,6 +20,7 @@ static char *def = NULL;
 #define REVERSED 1
 static int show_type = NORMAL;
 static int symbolic = 0;
+static int abbrev = 0;
 static int output_sq = 0;
 
 static int revs_count = 0;
@@ -95,6 +96,8 @@ static void show_rev(int type, const uns
 		putchar('^');
 	if (symbolic && name)
 		show(name);
+	else if (abbrev)
+		show(find_unique_abbrev(sha1, abbrev));
 	else
 		show(sha1_to_hex(sha1));
 }
@@ -195,6 +198,17 @@ int main(int argc, char **argv)
 				verify = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--abbrev") ||
+					!strncmp(arg, "--abbrev=", 9)) {
+				filter &= ~(DO_FLAGS|DO_NOREV);
+				verify = 1;
+				abbrev = DEFAULT_ABBREV;
+				if (arg[8] == '=')
+					abbrev = strtoul(arg + 9, NULL, 10);
+				if (abbrev < 4 || 40 <= abbrev)
+					abbrev = DEFAULT_ABBREV;
+				continue;
+			}
 			if (!strcmp(arg, "--sq")) {
 				output_sq = 1;
 				continue;
-- 
1.1.4.g3e6c

Best regards
Uwe

-- 
Uwe Zeisberger

http://www.google.com/search?q=72+PS+point+in+inch

^ permalink raw reply related	[relevance 16%]

* [PATCH] Shallow clone: low level machinery.
  @ 2006-01-31 11:02 10%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-01-31 11:02 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

This adds --shallow=refname option to git-clone-pack, and
extends upload-pack protocol with "shallow" extension.

An example:

	$ mkdir junk && cd junk && git init-db
	$ git clone-pack --shallow=refs/heads/master ../git.git master

This creates a very shallow clone of my repository.  It says
"pretend refs/heads/master commit is the beginning of time, and
clone your master branch".  As before, clone-pack with explicit
head name outputs the commit object name and refname to the
standard output instead of creating the branch.  The command
creates a .git/info/grafts file to cauterize the history at that
commit as well.

I think upload-pack side is more or less ready to be debugged,
but the client side is highly experimental.  It has quite
serious limitations and is more of a proof of correctness at the
protocol extension level than for practical use:

 - Currently it can take only one ---shallow option.

 - It has to be spelled in full (refs/heads/master, not
   "master").

 - It has to be included as part of explicit refname list.

 - There is no matching --shallow in git-fetch-pack.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 cache.h       |    9 +++
 clone-pack.c  |   69 ++++++++++++++++++++++-
 commit-tree.c |    5 --
 commit.c      |  174 +++++++++++++++++++++++++++++++++++++++------------------
 commit.h      |   14 +++++
 connect.c     |   24 ++++++++
 object.c      |    7 ++
 object.h      |    2 +
 upload-pack.c |   94 +++++++++++++++++++++++++++++--
 9 files changed, 331 insertions(+), 67 deletions(-)

75f1f4871277f403991c771eb642bdbd6fe82021
diff --git a/cache.h b/cache.h
index bdbe2d6..18d4cdb 100644
--- a/cache.h
+++ b/cache.h
@@ -111,11 +111,18 @@ static inline unsigned int create_ce_mod
 extern struct cache_entry **active_cache;
 extern unsigned int active_nr, active_alloc, active_cache_changed;
 
+/*
+ * Having more than two parents is not strange at all, and this is
+ * how multi-way merges are represented.
+ */
+#define MAXPARENT (16)
+
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define GRAFT_INFO_ENVIRONMENT "GIT_GRAFT_INFO"
 
 extern char *get_git_dir(void);
 extern char *get_object_directory(void);
@@ -296,6 +303,8 @@ struct ref {
 	char name[FLEX_ARRAY]; /* more */
 };
 
+extern void send_graft_info(int);
+
 extern int git_connect(int fd[2], char *url, const char *prog);
 extern int finish_connect(pid_t pid);
 extern int path_match(const char *path, int nr, char **match);
diff --git a/clone-pack.c b/clone-pack.c
index f634431..c1708d5 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -1,15 +1,76 @@
 #include "cache.h"
 #include "refs.h"
 #include "pkt-line.h"
+#include "commit.h"
 
 static const char clone_pack_usage[] =
-"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
+"git-clone-pack [--shallow=name] [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
 static const char *exec = "git-upload-pack";
+static char *shallow = NULL;
+
+static void shallow_exchange(int fd[2], struct ref *ref)
+{
+	char line[1024];
+	char *graft_file;
+	FILE *fp;
+	int i, j;
+
+	while (ref) {
+		if (!strcmp(ref->name, shallow))
+			break;
+		ref = ref->next;
+	}
+	if (!ref)
+		die("No matching ref specified for shallow clone %s",
+		    shallow);
+	if (!server_supports("shallow"))
+		die("The other end does not support shallow clone");
+	packet_write(fd[1], "shallow\n");
+	packet_flush(fd[1]);
+
+	/* Read their graft */
+	prepare_commit_graft();
+	for (;;) {
+		int len;
+		len = packet_read_line(fd[0], line, sizeof(line));
+		if (!len)
+			break;
+		add_graft_info(line);
+	}
+	/* And cauterize at --shallow=<sha1> */
+	sprintf(line, "%s\n", sha1_to_hex(ref->old_sha1));
+	add_graft_info(line);
+
+	/* tell ours */
+	packet_write(fd[1], "custom\n");
+	send_graft_info(fd[1]);
+	packet_flush(fd[1]);
+
+	/* write out ours */
+	graft_file = get_graft_file();
+	fp = fopen(graft_file, "w");
+	if (!fp)
+		die("cannot update grafts!");
+
+	for (i = 0; i < commit_graft_nr; i++) {
+		struct commit_graft *g = commit_graft[i];
+		fputs(sha1_to_hex(g->sha1), fp);
+		for (j = 0; j < g->nr_parent; j++) {
+			fputc(' ', fp);
+			fputs(sha1_to_hex(g->parent[j]), fp);
+		}
+		fputc('\n', fp);
+	}
+	fclose(fp);
+}
 
 static void clone_handshake(int fd[2], struct ref *ref)
 {
 	unsigned char sha1[20];
 
+	if (shallow)
+		shallow_exchange(fd, ref);
+
 	while (ref) {
 		packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1));
 		ref = ref->next;
@@ -160,6 +221,10 @@ int main(int argc, char **argv)
 				exec = arg + 7;
 				continue;
 			}
+			if (!strncmp("--shallow=", arg, 10)) {
+				shallow = arg + 10;
+				continue;
+			}
 			usage(clone_pack_usage);
 		}
 		dest = arg;
@@ -167,6 +232,8 @@ int main(int argc, char **argv)
 		nr_heads = argc - i - 1;
 		break;
 	}
+	if (shallow && !nr_heads)
+		die("shallow clone needs an explicit head name");
 	if (!dest)
 		usage(clone_pack_usage);
 	pid = git_connect(fd, dest, exec);
diff --git a/commit-tree.c b/commit-tree.c
index 4634b50..cbf2979 100644
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -53,11 +53,6 @@ static void check_valid(unsigned char *s
 	free(buf);
 }
 
-/*
- * Having more than two parents is not strange at all, and this is
- * how multi-way merges are represented.
- */
-#define MAXPARENT (16)
 static unsigned char parent_sha1[MAXPARENT][20];
 
 static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
diff --git a/commit.c b/commit.c
index 97205bf..a862287 100644
--- a/commit.c
+++ b/commit.c
@@ -102,12 +102,8 @@ static unsigned long parse_commit_date(c
 	return date;
 }
 
-static struct commit_graft {
-	unsigned char sha1[20];
-	int nr_parent;
-	unsigned char parent[0][20]; /* more */
-} **commit_graft;
-static int commit_graft_alloc, commit_graft_nr;
+struct commit_graft **commit_graft;
+int commit_graft_alloc, commit_graft_nr;
 
 static int commit_graft_pos(const unsigned char *sha1)
 {
@@ -128,62 +124,104 @@ static int commit_graft_pos(const unsign
 	return -lo - 1;
 }
 
-static void prepare_commit_graft(void)
+int add_graft_info(char *buf)
 {
-	char *graft_file = get_graft_file();
-	FILE *fp = fopen(graft_file, "r");
+	/* The format is just "Commit Parent1 Parent2 ...\n" */
+	int len = strlen(buf);
+	int i;
+	struct commit_graft *graft = NULL;
+
+	if (buf[len-1] == '\n')
+		buf[--len] = 0;
+	if (buf[0] == '#')
+		return 0;
+	if ((len + 1) % 41) {
+	bad_graft_data:
+		error("bad graft data: %s", buf);
+		free(graft);
+		return -1;
+	}
+	i = (len + 1) / 41 - 1;
+	graft = xmalloc(sizeof(*graft) + 20 * i);
+	graft->nr_parent = i;
+	if (get_sha1_hex(buf, graft->sha1))
+		goto bad_graft_data;
+	for (i = 40; i < len; i += 41) {
+		if (buf[i] != ' ')
+			goto bad_graft_data;
+		if (get_sha1_hex(buf + i + 1, graft->parent[i/41]))
+			goto bad_graft_data;
+	}
+	i = commit_graft_pos(graft->sha1);
+	if (0 <= i) {
+		free(commit_graft[i]);
+		commit_graft[i] = graft;
+		return 0;
+	}
+	i = -i - 1;
+	if (commit_graft_alloc <= ++commit_graft_nr) {
+		commit_graft_alloc = alloc_nr(commit_graft_alloc);
+		commit_graft = xrealloc(commit_graft,
+					sizeof(*commit_graft) *
+					commit_graft_alloc);
+	}
+	if (i < commit_graft_nr)
+		memmove(commit_graft + i + 1,
+			commit_graft + i,
+			(commit_graft_nr - i - 1) *
+			sizeof(*commit_graft));
+	commit_graft[i] = graft;
+	return 0;
+}
+
+void clear_commit_graft(void)
+{
+	int i;
+	for (i = 0; i < commit_graft_nr; i++)
+		free(commit_graft[i]);
+	free(commit_graft);
+	commit_graft_nr = commit_graft_alloc = 0;
+	commit_graft = NULL;
+}
+
+void prepare_commit_graft(void)
+{
+	char *graft_file;
+	FILE *fp;
 	char buf[1024];
+
+	if (getenv(GRAFT_INFO_ENVIRONMENT)) {
+		char *cp, *ep;
+		for (cp = getenv(GRAFT_INFO_ENVIRONMENT);
+		     *cp;
+		     cp = ep) {
+			int more = 0;
+			ep = strchr(cp, '\n');
+			if (ep) {
+				more = 1;
+				*ep = '\0';
+			}
+			else {
+				ep = cp + strlen(cp);
+			}
+			if (ep != cp)
+				add_graft_info(cp);
+			if (!more)
+				break;
+			*ep = '\n';
+			ep++;
+		}
+		return;
+	}
+	graft_file = get_graft_file();
+	fp = fopen(graft_file, "r");
 	if (!fp) {
-		commit_graft = (struct commit_graft **) "hack";
+		commit_graft = (struct commit_graft **) xmalloc(1);
 		return;
 	}
-	while (fgets(buf, sizeof(buf), fp)) {
-		/* The format is just "Commit Parent1 Parent2 ...\n" */
-		int len = strlen(buf);
-		int i;
-		struct commit_graft *graft = NULL;
+	while (fgets(buf, sizeof(buf), fp))
+		add_graft_info(buf);
 
-		if (buf[len-1] == '\n')
-			buf[--len] = 0;
-		if (buf[0] == '#')
-			continue;
-		if ((len + 1) % 41) {
-		bad_graft_data:
-			error("bad graft data: %s", buf);
-			free(graft);
-			continue;
-		}
-		i = (len + 1) / 41 - 1;
-		graft = xmalloc(sizeof(*graft) + 20 * i);
-		graft->nr_parent = i;
-		if (get_sha1_hex(buf, graft->sha1))
-			goto bad_graft_data;
-		for (i = 40; i < len; i += 41) {
-			if (buf[i] != ' ')
-				goto bad_graft_data;
-			if (get_sha1_hex(buf + i + 1, graft->parent[i/41]))
-				goto bad_graft_data;
-		}
-		i = commit_graft_pos(graft->sha1);
-		if (0 <= i) {
-			error("duplicate graft data: %s", buf);
-			free(graft);
-			continue;
-		}
-		i = -i - 1;
-		if (commit_graft_alloc <= ++commit_graft_nr) {
-			commit_graft_alloc = alloc_nr(commit_graft_alloc);
-			commit_graft = xrealloc(commit_graft,
-						sizeof(*commit_graft) *
-						commit_graft_alloc);
-		}
-		if (i < commit_graft_nr)
-			memmove(commit_graft + i + 1,
-				commit_graft + i,
-				(commit_graft_nr - i - 1) *
-				sizeof(*commit_graft));
-		commit_graft[i] = graft;
-	}
 	fclose(fp);
 }
 
@@ -288,6 +326,30 @@ int parse_commit(struct commit *item)
 	return ret;
 }
 
+static void reparse_commit_parents(struct object *o)
+{
+	struct commit *c;
+	struct commit_list *parents;
+	if ((o->type != commit_type) || !o->parsed)
+		return;
+	c = (struct commit *)o;
+	parents = c->parents;
+	o->parsed = 0;
+	while (parents) {
+		struct commit_list *next = parents->next;
+		free(parents);
+		parents = next;
+	}
+	c->parents = NULL;
+	free(c->buffer);
+	c->buffer = NULL;
+}
+
+void reparse_all_parsed_commits(void)
+{
+	for_each_object(reparse_commit_parents);
+}
+
 struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
 {
 	struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
diff --git a/commit.h b/commit.h
index 986b22d..abc5b9e 100644
--- a/commit.h
+++ b/commit.h
@@ -17,6 +17,20 @@ struct commit {
 	char *buffer;
 };
 
+struct commit_graft {
+	unsigned char sha1[20];
+	int nr_parent;
+	unsigned char parent[0][20]; /* more */
+};
+
+extern struct commit_graft **commit_graft;
+extern int commit_graft_alloc, commit_graft_nr;
+
+extern void prepare_commit_graft(void);
+extern void clear_commit_graft(void);
+extern int add_graft_info(char *);
+extern void reparse_all_parsed_commits(void);
+
 extern int save_commit_buffer;
 extern const char *commit_type;
 
diff --git a/connect.c b/connect.c
index 3f2d65c..046d1da 100644
--- a/connect.c
+++ b/connect.c
@@ -3,6 +3,7 @@
 #include "pkt-line.h"
 #include "quote.h"
 #include "refs.h"
+#include "commit.h"
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -298,6 +299,29 @@ int match_refs(struct ref *src, struct r
 	return 0;
 }
 
+void send_graft_info(int outfd)
+{
+	int i, j;
+	char packet_buf[41*MAXPARENT], *buf;
+
+	for (i = 0; i < commit_graft_nr; i++) {
+		struct commit_graft *g = commit_graft[i];
+		buf = packet_buf;
+		memcpy(buf, sha1_to_hex(g->sha1), 40);
+		buf += 40;
+		if (MAXPARENT <= g->nr_parent)
+			die("insanely big octopus graft with %d parents: %s",
+			    g->nr_parent, sha1_to_hex(g->sha1));
+		for (j = 0; j < g->nr_parent; j++) {
+			*buf++ = ' ';
+			memcpy(buf, sha1_to_hex(g->parent[j]), 40);
+			buf += 40;
+		}
+		*buf = 0;
+		packet_write(outfd, "%s\n", packet_buf);
+	}
+}
+
 enum protocol {
 	PROTO_LOCAL = 1,
 	PROTO_SSH,
diff --git a/object.c b/object.c
index 1577f74..bbcfcd8 100644
--- a/object.c
+++ b/object.c
@@ -252,3 +252,10 @@ int object_list_contains(struct object_l
 	}
 	return 0;
 }
+
+void for_each_object(void (*fn)(struct object *))
+{
+	int i;
+	for (i = 0; i < nr_objs; i++)
+		fn(objs[i]);
+}
diff --git a/object.h b/object.h
index 0e76182..b4c9729 100644
--- a/object.h
+++ b/object.h
@@ -55,4 +55,6 @@ unsigned object_list_length(struct objec
 
 int object_list_contains(struct object_list *list, struct object *obj);
 
+void for_each_object(void (*)(struct object *));
+
 #endif /* OBJECT_H */
diff --git a/upload-pack.c b/upload-pack.c
index d198055..90ea549 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -13,11 +13,16 @@ static const char upload_pack_usage[] = 
 #define WANTED (1U << 2)
 #define MAX_HAS 256
 #define MAX_NEEDS 256
-static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 0;
+#define MAX_PARENTS 20
+static int nr_has = 0, nr_needs = 0, nr_our_refs = 0;
 static unsigned char has_sha1[MAX_HAS][20];
 static unsigned char needs_sha1[MAX_NEEDS][20];
 static unsigned int timeout = 0;
 
+/* protocol extensions */
+static int multi_ack = 0;
+static int using_custom_graft = 0;
+
 static void reset_timeout(void)
 {
 	alarm(timeout);
@@ -163,6 +168,77 @@ static int get_common_commits(void)
 	}
 }
 
+static void exchange_grafts(void)
+{
+	int len;
+	char line[41*MAX_PARENTS];
+
+	/* We heard "shallow"; drop up to the next flush */
+	for (;;) {
+		len = packet_read_line(0, line, sizeof(line));
+		reset_timeout();
+		if (!len)
+			break;
+	}
+
+	/* Send our graft */
+	prepare_commit_graft();
+	send_graft_info(1);
+	packet_flush(1);
+
+	/* For precise common commits discovery, we need to use
+	 * the graft information we received from them.
+	 * But this is expensive, so the downloader first says
+	 * if it wants to use our graft as is.
+	 */
+	len = packet_read_line(0, line, sizeof(line));
+	reset_timeout();
+	if (!len)
+		; /* use ours as is */
+	else if (!strcmp(line, "custom\n")) {
+		using_custom_graft = 1;
+		clear_commit_graft();
+		for (;;) {
+			len = packet_read_line(0, line, sizeof(line));
+			reset_timeout();
+			if (!len)
+				break;
+			if (add_graft_info(line))
+				die("Bad graft line %s", line);
+		}
+		/* And using that, we prepare our end. */
+		reparse_all_parsed_commits();
+	}
+	else
+		die("expected 'custom', got '%s'", line);
+}
+
+static void setup_custom_graft(void)
+{
+	char *graft_env = strdup(GRAFT_INFO_ENVIRONMENT "=");
+	int envlen = strlen(graft_env);
+	int i, j;
+
+	for (i = 0; i < commit_graft_nr; i++) {
+		struct commit_graft *g = commit_graft[i];
+		char buf[41*MAX_PARENTS], *ptr;
+		ptr = buf;
+		memcpy(ptr, sha1_to_hex(g->sha1), 40);
+		ptr += 40;
+		for (j = 0; j < g->nr_parent; j++) {
+			*ptr++ = ' ';
+			memcpy(ptr, sha1_to_hex(g->parent[j]), 40);
+			ptr += 40;
+		}
+		*ptr++ = '\n';
+		*ptr = 0;
+		graft_env = xrealloc(graft_env, envlen + (ptr - buf));
+		memcpy(graft_env + envlen, buf, ptr - buf + 1);
+		envlen += ptr - buf;
+	}
+	putenv(graft_env);
+}
+
 static int receive_needs(void)
 {
 	static char line[1000];
@@ -180,16 +256,22 @@ static int receive_needs(void)
 		sha1_buf = dummy;
 		if (needs == MAX_NEEDS) {
 			fprintf(stderr,
-				"warning: supporting only a max of %d requests. "
+				"warning: supporting only a max of "
+				"%d requests. "
 				"sending everything instead.\n",
 				MAX_NEEDS);
 		}
 		else if (needs < MAX_NEEDS)
 			sha1_buf = needs_sha1[needs];
 
-		if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
+		if (!strcmp("shallow\n", line)) {
+			exchange_grafts();
+			continue;
+		}
+		if (strncmp("want ", line, 5) ||
+		    get_sha1_hex(line+5, sha1_buf))
 			die("git-upload-pack: protocol error, "
-			    "expected to get sha, not '%s'", line);
+			    "expected to get want-sha1, not '%s'", line);
 		if (strstr(line+45, "multi_ack"))
 			multi_ack = 1;
 
@@ -213,7 +295,7 @@ static int receive_needs(void)
 
 static int send_ref(const char *refname, const unsigned char *sha1)
 {
-	static char *capabilities = "multi_ack";
+	static char *capabilities = "multi_ack shallow";
 	struct object *o = parse_object(sha1);
 
 	if (capabilities)
@@ -243,6 +325,8 @@ static int upload_pack(void)
 	if (!nr_needs)
 		return 0;
 	get_common_commits();
+	if (using_custom_graft)
+		setup_custom_graft();
 	create_pack_file();
 	return 0;
 }
-- 
1.1.6.gefef

^ permalink raw reply related	[relevance 10%]

* Re: [Census] So who uses git?
  @ 2006-02-01  2:09 21%                       ` Linus Torvalds
  2006-02-09  5:15 10%                         ` [PATCH] "Assume unchanged" git Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Linus Torvalds @ 2006-02-01  2:09 UTC (permalink / raw)
  To: Ray Lehtiniemi
  Cc: Alex Riesen, Radoslaw Szkodzinski, Keith Packard, Junio C Hamano,
	cworth, Martin Langhoff, Git Mailing List



On Tue, 31 Jan 2006, Linus Torvalds wrote:
> 
> We still have one unused bit in the cache-entry "ce_flags", so we wouldn't 
> even need to break any existing index files with it.

In case it wasn't clear, the _core_ of this optimization would be as 
simple as something like the appended.

The real meat is just making sure that CE_VALID gets set/cleared properly.

(That's also the most complex part, of course, but this trivial patch 
might help show the basic idea)

		Linus

---
diff --git a/cache.h b/cache.h
index bdbe2d6..7adc2e6 100644
--- a/cache.h
+++ b/cache.h
@@ -91,6 +91,7 @@ struct cache_entry {
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_UPDATE    (0x4000)
+#define CE_VALID     (0x8000)
 #define CE_STAGESHIFT 12
 
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
diff --git a/read-cache.c b/read-cache.c
index c5474d4..738fe78 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -148,7 +148,16 @@ static int ce_match_stat_basic(struct ca
 
 int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
-	unsigned int changed = ce_match_stat_basic(ce, st);
+	unsigned int changed;
+
+	/*
+	 * If it's marked as always valid in the index, it's 
+	 * valid whatever the checked-out copy says
+	 */
+	if (ce->ce_flags & htons(CE_VALID))
+		return 0;
+
+	changed = ce_match_stat_basic(ce, st);
 
 	/*
 	 * Within 1 second of this sequence:

^ permalink raw reply related	[relevance 21%]

* [PATCH 2/2] git-send-email: Add --quiet to reduce some of the chatter when sending emails.
  2006-02-02 16:56 47% ` [PATCH 1/2] Provide a more meaningful initial "From " line when using --compose in git-send-email Ryan Anderson
@ 2006-02-02 16:56 48%   ` Ryan Anderson
  0 siblings, 0 replies; 200+ results
From: Ryan Anderson @ 2006-02-02 16:56 UTC (permalink / raw)
  To: git; +Cc: Ryan Anderson

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 git-send-email.perl |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

3dcbd6298dc6fb4a903404cb9c47e3690bf2e01a
diff --git a/git-send-email.perl b/git-send-email.perl
index 51b7513..ca1fa37 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -34,7 +34,7 @@ my $compose_filename = ".msg.$$";
 my (@to,@cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
 
 # Behavior modification variables
-my ($chain_reply_to, $smtp_server) = (1, "localhost");
+my ($chain_reply_to, $smtp_server, $quiet) = (1, "localhost", 0);
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -51,6 +51,7 @@ my $rc = GetOptions("from=s" => \$from,
 		    "chain-reply-to!" => \$chain_reply_to,
 		    "smtp-server=s" => \$smtp_server,
 		    "compose" => \$compose,
+		    "quiet" => \$quiet,
 	 );
 
 # Now, let's fill any that aren't set in with defaults:
@@ -267,8 +268,10 @@ sub send_message
 
 	sendmail(%mail) or die $Mail::Sendmail::error;
 
-	print "OK. Log says:\n", $Mail::Sendmail::log;
-	print "\n\n"
+	unless ($quiet) {
+		print "OK. Log says:\n", $Mail::Sendmail::log;
+		print "\n\n"
+	}
 }
 
 
-- 
1.1.4.g3dcbd

^ permalink raw reply related	[relevance 48%]

* [PATCH 1/2] Provide a more meaningful initial "From " line when using --compose in git-send-email.
  @ 2006-02-02 16:56 47% ` Ryan Anderson
  2006-02-02 16:56 48%   ` [PATCH 2/2] git-send-email: Add --quiet to reduce some of the chatter when sending emails Ryan Anderson
  0 siblings, 1 reply; 200+ results
From: Ryan Anderson @ 2006-02-02 16:56 UTC (permalink / raw)
  To: git; +Cc: Ryan Anderson

git-send-email, when used with --compose, provided the user with a mbox-format
file to edit.  Some users, however, were confused by the leading, blank, "From
" line, so this change puts the value that will appear on the From: line of the
actual email on this line, along with a note that the line is ignored.

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 git-send-email.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

c6b0c22e482aa6fe314e4be077d705c98fee7bf2
diff --git a/git-send-email.perl b/git-send-email.perl
index ec1428d..51b7513 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -125,7 +125,7 @@ if ($compose) {
 	# effort to have it be unique
 	open(C,">",$compose_filename)
 		or die "Failed to open for writing $compose_filename: $!";
-	print C "From \n";
+	print C "From $from # This line is ignored.\n";
 	printf C "Subject: %s\n\n", $initial_subject;
 	printf C <<EOT;
 GIT: Please enter your email below.
-- 
1.1.4.g3dcbd

^ permalink raw reply related	[relevance 47%]

* Re: [PATCH 3/3] daemon: Support a --user-path option.
  @ 2006-02-04 19:13 10%         ` Mark Wooding
  0 siblings, 0 replies; 200+ results
From: Mark Wooding @ 2006-02-04 19:13 UTC (permalink / raw)
  To: git

Junio C Hamano <junkio@cox.net> wrote:

> In my simplistic view, --base-path serves something like /pub
> hierarchy of an ftp server or /var/www of an http server. 

Yes, that's the way I think of it too.  I'll probably point it at
/var/www/git or something when I finally get my tuits.

> For ~user/ based paths, it is natural to wish to limit the parts of
> home directories but there currently is not a good way to do so.  We
> could probably extend the whitelist to take path glob patterns and say
> "~*/public-git/" or something silly like that, but that still means
> the request must be in the form
> "git://host/~alice/public-git/frotz.git/" (which may not be such a bad
> thing); "git://host/~alice/frotz.git/" might look nicer. 

Putting `public-git' in the URLs seems to exposing an unnecessary
detail.  Or it's saying something utterly obvious -- of course it's a
public GIT -- otherwise you wouldn't be asking for it.

> Your path munging idea is one way to do so.  Another would be for
> alice to have $HOME/frotz.git/git-daemon-export-ok.  Personally I do
> not think either would make too much of a difference from usability
> point of view.

The idea of filling my home directory with all my GIT repositories isn't
one I'm particularly keen on.  For one thing, I can just tell that I'm
going to get confused between ~/src/foo/.git and ~/foo.git some day; and
besides, I like `ls ~' to be nice and short.

> So I am not dismissing what you are trying to achieve here.
> However, I am not happy about having <pwd.h> there and majorly
> duplicating what enter_repo() does in that part of the code.

OK, then: how about putting the user_path logic into enter_repo?  Like
this, perhaps:


 Documentation/git-daemon.txt |   11 +++++++++--
 cache.h                      |    2 +-
 daemon.c                     |   16 +++++++++++-----
 path.c                       |   34 ++++++++++++++++++++++++++++------
 receive-pack.c               |    2 +-
 upload-pack.c                |    2 +-
 6 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index a20e053..2e48a10 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
              [--timeout=n] [--init-timeout=n] [--strict-paths]
-             [--base-path=path] [directory...]
+             [--base-path=path] [--user-path=path] [directory...]
 
 DESCRIPTION
 -----------
@@ -43,7 +43,7 @@ OPTIONS
 	'--base-path=/srv/git' on example.com, then if you later try to pull
 	'git://example.com/hello.git', `git-daemon` will interpret the path
 	as '/srv/git/hello.git'. Home directories (the '~login' notation)
-	access is disabled.
+	access is disabled unless '--user-path' is also given.
 
 --export-all::
 	Allow pulling from all directories that look like GIT repositories
@@ -70,6 +70,13 @@ OPTIONS
 	Log to syslog instead of stderr. Note that this option does not imply
 	--verbose, thus by default only error conditions will be logged.
 
+--user-path::
+	Rewrite a request for "~user/something" to
+	"home/user-path/something".  Useful in conjunction with
+	'--base-path', if you want to restrict the daemon from roaming
+	the entire filesystem without preventing users from publishing
+	their own repositories.
+
 --verbose::
 	Log details about the incoming connections and requested files.
 
diff --git a/cache.h b/cache.h
index bdbe2d6..b6c9cda 100644
--- a/cache.h
+++ b/cache.h
@@ -191,7 +191,7 @@ int git_mkstemp(char *path, size_t n, co
 int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
-char *enter_repo(char *path, int strict);
+char *enter_repo(char *path, const char *u_path, int strict);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
diff --git a/daemon.c b/daemon.c
index bb014fa..22d133d 100644
--- a/daemon.c
+++ b/daemon.c
@@ -17,7 +17,7 @@ static int verbose;
 static const char daemon_usage[] =
 "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
 "           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
-"           [--base-path=path] [directory...]";
+"           [--base-path=path] [--user-path=path] [directory...]";
 
 /* List of acceptable pathname prefixes */
 static char **ok_paths = NULL;
@@ -28,6 +28,7 @@ static int export_all_trees = 0;
 
 /* Take all paths relative to this one if non-NULL */
 static char *base_path = NULL;
+static char *user_path = NULL;
 
 /* Timeout, and initial timeout */
 static unsigned int timeout = 0;
@@ -137,14 +138,16 @@ static int avoid_alias(char *p)
 static char *path_ok(char *dir)
 {
 	char *path;
+	static char rpath[PATH_MAX];
 
 	if (avoid_alias(dir)) {
 		logerror("'%s': aliased", dir);
 		return NULL;
 	}
 
-	if (base_path) {
-		static char rpath[PATH_MAX];
+	if (user_path && dir[0] == '~')
+		/* okay */;
+	else if (base_path) {
 		if (*dir != '/') {
 			/* Forbid possible base-path evasion using ~paths. */
 			logerror("'%s': Non-absolute path denied (base-path active)");
@@ -154,7 +157,7 @@ static char *path_ok(char *dir)
 		dir = rpath;
 	}
 
-	path = enter_repo(dir, strict_paths);
+	path = enter_repo(dir, user_path, strict_paths);
 
 	if (!path) {
 		logerror("'%s': unable to chdir or not a git archive", dir);
@@ -490,7 +493,6 @@ static int socksetup(int port, int **soc
 			/* Note: error is not fatal */
 		}
 #endif
-
 		if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
 			close(sockfd);
 			continue;	/* not fatal */
@@ -659,6 +661,10 @@ int main(int argc, char **argv)
 			base_path = arg+12;
 			continue;
 		}
+		if (!strncmp(arg, "--user-path=", 12)) {
+			user_path = arg+12;
+			continue;
+		}
 		if (!strcmp(arg, "--")) {
 			ok_paths = &argv[i+1];
 			break;
diff --git a/path.c b/path.c
index 334b2bd..596e37e 100644
--- a/path.c
+++ b/path.c
@@ -131,7 +131,17 @@ int validate_symref(const char *path)
 	return -1;
 }
 
-static char *user_path(char *buf, char *path, int sz)
+static void kill_trailing_slashes(char *buf, int *lenp)
+{
+	int len = *lenp;
+	while ((1 < len) && (buf[len-1] == '/')) {
+		buf[len-1] = 0;
+		len--;
+	}
+	*lenp = len;
+}
+
+static char *user_path(char *buf, char *path, const char *u_path, int sz)
 {
 	struct passwd *pw;
 	char *slash;
@@ -157,9 +167,17 @@ static char *user_path(char *buf, char *
 		return NULL;
 	baselen = strlen(pw->pw_dir);
 	memcpy(buf, pw->pw_dir, baselen);
-	while ((1 < baselen) && (buf[baselen-1] == '/')) {
-		buf[baselen-1] = 0;
-		baselen--;
+	kill_trailing_slashes(buf, &baselen);
+	if (u_path) {
+		while (*u_path == '/')
+			u_path++;
+		len = strlen(u_path);
+		if (sz <= baselen + len + 1)
+			return NULL;
+		buf[baselen++] = '/';
+		memcpy(buf + baselen, u_path, len);
+		baselen += len;
+		kill_trailing_slashes(buf, &baselen);
 	}
 	if (slash && slash[1]) {
 		len = strlen(slash);
@@ -184,6 +202,10 @@ static char *user_path(char *buf, char *
  * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
  * what we try.
  *
+ * If "u_path" is given, and the path we're resolving has the form ~/path
+ * or ~user/path, then we resolve to home/u_path/path (where home is the
+ * appropriate user's home directory).
+ *
  * Second, we try chdir() to that.  Upon failure, we return NULL.
  *
  * Then, we try if the current directory is a valid git repository.
@@ -194,7 +216,7 @@ static char *user_path(char *buf, char *
  * links.  User relative paths are also returned as they are given,
  * except DWIM suffixing.
  */
-char *enter_repo(char *path, int strict)
+char *enter_repo(char *path, const char *u_path, int strict)
 {
 	static char used_path[PATH_MAX];
 	static char validated_path[PATH_MAX];
@@ -215,7 +237,7 @@ char *enter_repo(char *path, int strict)
 		if (PATH_MAX <= len)
 			return NULL;
 		if (path[0] == '~') {
-			if (!user_path(used_path, path, PATH_MAX))
+			if (!user_path(used_path, path, u_path, PATH_MAX))
 				return NULL;
 			strcpy(validated_path, path);
 			path = used_path;
diff --git a/receive-pack.c b/receive-pack.c
index eae31e3..d411ab2 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -317,7 +317,7 @@ int main(int argc, char **argv)
 	if (!dir)
 		usage(receive_pack_usage);
 
-	if(!enter_repo(dir, 0))
+	if(!enter_repo(dir, NULL, 0))
 		die("'%s': unable to chdir or not a git archive", dir);
 
 	write_head_info();
diff --git a/upload-pack.c b/upload-pack.c
index d198055..3468de1 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -276,7 +276,7 @@ int main(int argc, char **argv)
 		usage(upload_pack_usage);
 	dir = argv[i];
 
-	if (!enter_repo(dir, strict))
+	if (!enter_repo(dir, NULL, strict))
 		die("'%s': unable to chdir or not a git archive", dir);
 
 	upload_pack();


-- [mdw]

^ permalink raw reply related	[relevance 10%]

* [PATCH] git-send-email: Fully implement --quiet and document it.
@ 2006-02-06  1:13 44% Ryan Anderson
  0 siblings, 0 replies; 200+ results
From: Ryan Anderson @ 2006-02-06  1:13 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Ryan Anderson

Also reorganizes the man page to list options alphabetically.

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 Documentation/git-send-email.txt |   44 +++++++++++++++++++++-----------------
 git-send-email.perl              |   19 +++++++++++-----
 2 files changed, 37 insertions(+), 26 deletions(-)

3b91b8b4e04e5cf42b7e5bd22b1bdda9c50ed781
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index b9bec55..00537d8 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -24,25 +24,23 @@ OPTIONS
 -------
 The options available are:
 
---to::
-	Specify the primary recipient of the emails generated.
-	Generally, this will be the upstream maintainer of the
-	project involved.
+--chain-reply-to, --no-chain-reply-to::
+	If this is set, each email will be sent as a reply to the previous
+	email sent.  If disabled with "--no-chain-reply-to", all emails after
+	the first will be sent as replies to the first email sent.  When using
+	this, it is recommended that the first file given be an overview of the
+	entire patch series.
+	Default is --chain-reply-to
+
+--compose::
+	Use $EDITOR to edit an introductory message for the
+	patch series.
 
 --from::
 	Specify the sender of the emails.  This will default to
 	the value GIT_COMMITTER_IDENT, as returned by "git-var -l".
 	The user will still be prompted to confirm this entry.
 
---compose::
-	Use \$EDITOR to edit an introductory message for the
-	patch series.
-
---subject::
-   	Specify the initial subject of the email thread.
-	Only necessary if --compose is also set.  If --compose
-	is not set, this will be prompted for.
-
 --in-reply-to::
 	Specify the contents of the first In-Reply-To header.
 	Subsequent emails will refer to the previous email 
@@ -50,18 +48,24 @@ The options available are:
 	Only necessary if --compose is also set.  If --compose
 	is not set, this will be prompted for.
 
---chain-reply-to, --no-chain-reply-to::
-	If this is set, each email will be sent as a reply to the previous
-	email sent.  If disabled with "--no-chain-reply-to", all emails after
-	the first will be sent as replies to the first email sent.  When using
-	this, it is recommended that the first file given be an overview of the
-	entire patch series.
-	Default is --chain-reply-to
+--quiet::
+	Make git-send-email less verbose.  One line per email should be
+	all that is output.
 
 --smtp-server::
 	If set, specifies the outgoing SMTP server to use.  Defaults to
 	localhost.
 
+--subject::
+   	Specify the initial subject of the email thread.
+	Only necessary if --compose is also set.  If --compose
+	is not set, this will be prompted for.
+
+--to::
+	Specify the primary recipient of the emails generated.
+	Generally, this will be the upstream maintainer of the
+	project involved.
+
 
 Author
 ------
diff --git a/git-send-email.perl b/git-send-email.perl
index 2977b9a..3f1b3ca 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -186,7 +186,9 @@ for my $f (@ARGV) {
 }
 
 if (@files) {
-	print $_,"\n" for @files;
+	unless ($quiet) {
+		print $_,"\n" for (@files);
+	}
 } else {
 	print <<EOT;
 git-send-email [options] <file | directory> [... file | directory ]
@@ -213,6 +215,10 @@ Options:
    --smtp-server  If set, specifies the outgoing SMTP server to use.
                   Defaults to localhost.
 
+   --quiet	Make git-send-email less verbose.  One line per email should be
+		all that is output.
+
+
 Error: Please specify a file or a directory on the command line.
 EOT
 	exit(1);
@@ -268,7 +274,9 @@ sub send_message
 
 	sendmail(%mail) or die $Mail::Sendmail::error;
 
-	unless ($quiet) {
+	if ($quiet) {
+		printf "Sent %s\n", $subject;
+	} else {
 		print "OK. Log says:\n", $Mail::Sendmail::log;
 		print "\n\n"
 	}
@@ -280,7 +288,6 @@ make_message_id();
 $subject = $initial_subject;
 
 foreach my $t (@files) {
-	my $F = $t;
 	open(F,"<",$t) or die "can't open file $t";
 
 	@cc = ();
@@ -298,7 +305,7 @@ foreach my $t (@files) {
 
 				} elsif (/^(Cc|From):\s+(.*)$/) {
 					printf("(mbox) Adding cc: %s from line '%s'\n",
-						$2, $_);
+						$2, $_) unless $quiet;
 					push @cc, $2;
 				}
 
@@ -310,7 +317,7 @@ foreach my $t (@files) {
 				# So let's support that, too.
 				if (@cc == 0) {
 					printf("(non-mbox) Adding cc: %s from line '%s'\n",
-						$_, $_);
+						$_, $_) unless $quiet;
 
 					push @cc, $_;
 
@@ -330,7 +337,7 @@ foreach my $t (@files) {
 				chomp $c;
 				push @cc, $c;
 				printf("(sob) Adding cc: %s from line '%s'\n",
-					$c, $_);
+					$c, $_) unless $quiet;
 			}
 		}
 	}
-- 
1.1.6.ga5ec-dirty

^ permalink raw reply related	[relevance 44%]

* [PATCH] "Assume unchanged" git
  2006-02-01  2:09 21%                       ` Linus Torvalds
@ 2006-02-09  5:15 10%                         ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-09  5:15 UTC (permalink / raw)
  To: git
  Cc: Alex Riesen, Radoslaw Szkodzinski, Keith Packard, cworth,
	Martin Langhoff, Linus Torvalds

Linus Torvalds <torvalds@osdl.org> writes:

> The real meat is just making sure that CE_VALID gets set/cleared properly.

Setting is easier part.  Deciding when to ignore/clear for the
sake of safety and usability is harder.  I think I got the
basics right but we might want to pass "really" from more places.

This is _not_ 1.2 material, but I think it is ready to be tested
by people who asked for this feature.  It applies on top of the
recent master branch.

-- >8 --
[PATCH] "Assume unchanged" git

This adds "assume unchanged" logic, started by this message in the list
discussion recently:

	<Pine.LNX.4.64.0601311807470.7301@g5.osdl.org>

This is a workaround for filesystems that do not have lstat()
that is quick enough for the index mechanism to take advantage
of.  On the paths marked as "assumed to be unchanged", the user
needs to explicitly use update-index to register the object name
to be in the next commit.

You can use two new options to update-index to set and reset the
CE_VALID bit:

	git-update-index --assume-unchanged path...
	git-update-index --no-assume-unchanged path...

These forms manipulate only the CE_VALID bit; it does not change
the object name recorded in the index file.  Nor they add a new
entry to the index.

When the configuration variable "core.ignorestat = true" is set,
the index entries are marked with CE_VALID bit automatically
after:

 - update-index to explicitly register the current object name to the
   index file.

 - when update-index --refresh finds the path to be up-to-date.

 - when tools like read-tree -u and apply --index update the working
   tree file and register the current object name to the index file.

The flag is dropped upon read-tree that does not check out the index
entry.  This happens regardless of the core.ignorestat settings.

Index entries marked with CE_VALID bit are assumed to be
unchanged most of the time.  However, there are cases that
CE_VALID bit is ignored for the sake of safety and usability:

 - while "git-read-tree -m" or git-apply need to make sure
   that the paths involved in the merge do not have local
   modifications.  This sacrifices performance for safety.

 - when git-checkout-index -f -q -u -a tries to see if it needs
   to checkout the paths.  Otherwise you can never check
   anything out ;-).

 - when git-update-index --really-refresh (a new flag) tries to
   see if the index entry is up to date.  You can start with
   everything marked as CE_VALID and run this once to drop
   CE_VALID bit for paths that are modified.

Most notably, "update-index --refresh" honours CE_VALID and does
not actively stat, so after you modified a file in the working
tree, update-index --refresh would not notice until you tell the
index about it with "git-update-index path" or "git-update-index
--no-assume-unchanged path".

This version is not expected to be perfect.  I think diff
between index and/or tree and working files may need some
adjustment, and there probably needs other cases we should
automatically unmark paths that are marked to be CE_VALID.

But the basics seem to work, and ready to be tested by people
who asked for this feature.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 apply.c          |    2 +-
 cache.h          |    6 +++--
 checkout-index.c |    1 +
 config.c         |    5 ++++
 diff-files.c     |    2 +-
 diff-index.c     |    2 +-
 diff.c           |    2 +-
 entry.c          |    2 +-
 environment.c    |    1 +
 read-cache.c     |   28 +++++++++++++++++++----
 read-tree.c      |    2 +-
 update-index.c   |   65 ++++++++++++++++++++++++++++++++++++++++++++++++------
 write-tree.c     |    2 +-
 13 files changed, 99 insertions(+), 21 deletions(-)

b169290f100cfa67b785c361bcae83f807487f5e
diff --git a/apply.c b/apply.c
index 2ad47fb..35ae48e 100644
--- a/apply.c
+++ b/apply.c
@@ -1309,7 +1309,7 @@ static int check_patch(struct patch *pat
 					return -1;
 			}
 
-			changed = ce_match_stat(active_cache[pos], &st);
+			changed = ce_match_stat(active_cache[pos], &st, 1);
 			if (changed)
 				return error("%s: does not match index",
 					     old_name);
diff --git a/cache.h b/cache.h
index bdbe2d6..cd58fad 100644
--- a/cache.h
+++ b/cache.h
@@ -91,6 +91,7 @@ struct cache_entry {
 #define CE_NAMEMASK  (0x0fff)
 #define CE_STAGEMASK (0x3000)
 #define CE_UPDATE    (0x4000)
+#define CE_VALID     (0x8000)
 #define CE_STAGESHIFT 12
 
 #define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
@@ -144,8 +145,8 @@ extern int add_cache_entry(struct cache_
 extern int remove_cache_entry_at(int pos);
 extern int remove_file_from_cache(const char *path);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
-extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
-extern int ce_modified(struct cache_entry *ce, struct stat *st);
+extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
+extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
 extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
@@ -161,6 +162,7 @@ extern int commit_index_file(struct cach
 extern void rollback_index_file(struct cache_file *);
 
 extern int trust_executable_bit;
+extern int assume_unchanged;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 extern int shared_repository;
diff --git a/checkout-index.c b/checkout-index.c
index 53dd8cb..957b4a8 100644
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -116,6 +116,7 @@ int main(int argc, char **argv)
 	int all = 0;
 
 	prefix = setup_git_directory();
+	git_config(git_default_config);
 	prefix_length = prefix ? strlen(prefix) : 0;
 
 	if (read_cache() < 0) {
diff --git a/config.c b/config.c
index 8355224..7dbdce1 100644
--- a/config.c
+++ b/config.c
@@ -222,6 +222,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "core.ignorestat")) {
+		assume_unchanged = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.symrefsonly")) {
 		only_use_symrefs = git_config_bool(var, value);
 		return 0;
diff --git a/diff-files.c b/diff-files.c
index d24d11c..c96ad35 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -191,7 +191,7 @@ int main(int argc, const char **argv)
 			show_file('-', ce);
 			continue;
 		}
-		changed = ce_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st, 0);
 		if (!changed && !diff_options.find_copies_harder)
 			continue;
 		oldmode = ntohl(ce->ce_mode);
diff --git a/diff-index.c b/diff-index.c
index f8a102e..12a9418 100644
--- a/diff-index.c
+++ b/diff-index.c
@@ -33,7 +33,7 @@ static int get_stat_data(struct cache_en
 			}
 			return -1;
 		}
-		changed = ce_match_stat(ce, &st);
+		changed = ce_match_stat(ce, &st, 0);
 		if (changed) {
 			mode = create_ce_mode(st.st_mode);
 			if (!trust_executable_bit &&
diff --git a/diff.c b/diff.c
index ec51e7d..c72064e 100644
--- a/diff.c
+++ b/diff.c
@@ -311,7 +311,7 @@ static int work_tree_matches(const char 
 	ce = active_cache[pos];
 	if ((lstat(name, &st) < 0) ||
 	    !S_ISREG(st.st_mode) || /* careful! */
-	    ce_match_stat(ce, &st) ||
+	    ce_match_stat(ce, &st, 0) ||
 	    memcmp(sha1, ce->sha1, 20))
 		return 0;
 	/* we return 1 only when we can stat, it is a regular file,
diff --git a/entry.c b/entry.c
index 6c47c3a..8fb99bc 100644
--- a/entry.c
+++ b/entry.c
@@ -123,7 +123,7 @@ int checkout_entry(struct cache_entry *c
 	strcpy(path + len, ce->name);
 
 	if (!lstat(path, &st)) {
-		unsigned changed = ce_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st, 1);
 		if (!changed)
 			return 0;
 		if (!state->force) {
diff --git a/environment.c b/environment.c
index 0596fc6..251e53c 100644
--- a/environment.c
+++ b/environment.c
@@ -12,6 +12,7 @@
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
+int assume_unchanged = 0;
 int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
diff --git a/read-cache.c b/read-cache.c
index c5474d4..efbb1be 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -27,6 +27,9 @@ void fill_stat_cache_info(struct cache_e
 	ce->ce_uid = htonl(st->st_uid);
 	ce->ce_gid = htonl(st->st_gid);
 	ce->ce_size = htonl(st->st_size);
+
+	if (assume_unchanged)
+		ce->ce_flags |= htons(CE_VALID);
 }
 
 static int ce_compare_data(struct cache_entry *ce, struct stat *st)
@@ -146,9 +149,18 @@ static int ce_match_stat_basic(struct ca
 	return changed;
 }
 
-int ce_match_stat(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st, int ignore_valid)
 {
-	unsigned int changed = ce_match_stat_basic(ce, st);
+	unsigned int changed;
+
+	/*
+	 * If it's marked as always valid in the index, it's
+	 * valid whatever the checked-out copy says.
+	 */
+	if (!ignore_valid && (ce->ce_flags & htons(CE_VALID)))
+		return 0;
+
+	changed = ce_match_stat_basic(ce, st);
 
 	/*
 	 * Within 1 second of this sequence:
@@ -164,7 +176,7 @@ int ce_match_stat(struct cache_entry *ce
 	 * effectively mean we can make at most one commit per second,
 	 * which is not acceptable.  Instead, we check cache entries
 	 * whose mtime are the same as the index file timestamp more
-	 * careful than others.
+	 * carefully than others.
 	 */
 	if (!changed &&
 	    index_file_timestamp &&
@@ -174,10 +186,10 @@ int ce_match_stat(struct cache_entry *ce
 	return changed;
 }
 
-int ce_modified(struct cache_entry *ce, struct stat *st)
+int ce_modified(struct cache_entry *ce, struct stat *st, int really)
 {
 	int changed, changed_fs;
-	changed = ce_match_stat(ce, st);
+	changed = ce_match_stat(ce, st, really);
 	if (!changed)
 		return 0;
 	/*
@@ -233,6 +245,11 @@ int cache_name_compare(const char *name1
 		return -1;
 	if (len1 > len2)
 		return 1;
+
+	/* Differences between "assume up-to-date" should not matter. */
+	flags1 &= ~CE_VALID;
+	flags2 &= ~CE_VALID;
+
 	if (flags1 < flags2)
 		return -1;
 	if (flags1 > flags2)
@@ -430,6 +447,7 @@ int add_cache_entry(struct cache_entry *
 	int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
 	int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
 	int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
+
 	pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
 
 	/* existing match? Just replace it. */
diff --git a/read-tree.c b/read-tree.c
index 5580f15..52f06e3 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -349,7 +349,7 @@ static void verify_uptodate(struct cache
 		return;
 
 	if (!lstat(ce->name, &st)) {
-		unsigned changed = ce_match_stat(ce, &st);
+		unsigned changed = ce_match_stat(ce, &st, 1);
 		if (!changed)
 			return;
 		errno = 0;
diff --git a/update-index.c b/update-index.c
index afec98d..767fd49 100644
--- a/update-index.c
+++ b/update-index.c
@@ -23,6 +23,10 @@ static int quiet; /* --refresh needing u
 static int info_only;
 static int force_remove;
 static int verbose;
+static int mark_valid_only = 0;
+#define MARK_VALID 1
+#define UNMARK_VALID 2
+
 
 /* Three functions to allow overloaded pointer return; see linux/err.h */
 static inline void *ERR_PTR(long error)
@@ -53,6 +57,25 @@ static void report(const char *fmt, ...)
 	va_end(vp);
 }
 
+static int mark_valid(const char *path)
+{
+	int namelen = strlen(path);
+	int pos = cache_name_pos(path, namelen);
+	if (0 <= pos) {
+		switch (mark_valid_only) {
+		case MARK_VALID:
+			active_cache[pos]->ce_flags |= htons(CE_VALID);
+			break;
+		case UNMARK_VALID:
+			active_cache[pos]->ce_flags &= ~htons(CE_VALID);
+			break;
+		}
+		active_cache_changed = 1;
+		return 0;
+	}
+	return -1;
+}
+
 static int add_file_to_cache(const char *path)
 {
 	int size, namelen, option, status;
@@ -94,6 +117,7 @@ static int add_file_to_cache(const char 
 	ce = xmalloc(size);
 	memset(ce, 0, size);
 	memcpy(ce->name, path, namelen);
+	ce->ce_flags = htons(namelen);
 	fill_stat_cache_info(ce, &st);
 
 	ce->ce_mode = create_ce_mode(st.st_mode);
@@ -105,7 +129,6 @@ static int add_file_to_cache(const char 
 		if (0 <= pos)
 			ce->ce_mode = active_cache[pos]->ce_mode;
 	}
-	ce->ce_flags = htons(namelen);
 
 	if (index_path(ce->sha1, path, &st, !info_only))
 		return -1;
@@ -128,7 +151,7 @@ static int add_file_to_cache(const char 
  * For example, you'd want to do this after doing a "git-read-tree",
  * to link up the stat cache details with the proper files.
  */
-static struct cache_entry *refresh_entry(struct cache_entry *ce)
+static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
 {
 	struct stat st;
 	struct cache_entry *updated;
@@ -137,21 +160,22 @@ static struct cache_entry *refresh_entry
 	if (lstat(ce->name, &st) < 0)
 		return ERR_PTR(-errno);
 
-	changed = ce_match_stat(ce, &st);
+	changed = ce_match_stat(ce, &st, really);
 	if (!changed)
 		return NULL;
 
-	if (ce_modified(ce, &st))
+	if (ce_modified(ce, &st, really))
 		return ERR_PTR(-EINVAL);
 
 	size = ce_size(ce);
 	updated = xmalloc(size);
 	memcpy(updated, ce, size);
 	fill_stat_cache_info(updated, &st);
+
 	return updated;
 }
 
-static int refresh_cache(void)
+static int refresh_cache(int really)
 {
 	int i;
 	int has_errors = 0;
@@ -171,12 +195,19 @@ static int refresh_cache(void)
 			continue;
 		}
 
-		new = refresh_entry(ce);
+		new = refresh_entry(ce, really);
 		if (!new)
 			continue;
 		if (IS_ERR(new)) {
 			if (not_new && PTR_ERR(new) == -ENOENT)
 				continue;
+			if (really && PTR_ERR(new) == -EINVAL) {
+				/* If we are doing --really-refresh that
+				 * means the index is not valid anymore.
+				 */
+				ce->ce_flags &= ~htons(CE_VALID);
+				active_cache_changed = 1;
+			}
 			if (quiet)
 				continue;
 			printf("%s: needs update\n", ce->name);
@@ -274,6 +305,8 @@ static int add_cacheinfo(unsigned int mo
 	memcpy(ce->name, path, len);
 	ce->ce_flags = create_ce_flags(len, stage);
 	ce->ce_mode = create_ce_mode(mode);
+	if (assume_unchanged)
+		ce->ce_flags |= htons(CE_VALID);
 	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
 	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
 	if (add_cache_entry(ce, option))
@@ -317,6 +350,12 @@ static void update_one(const char *path,
 		fprintf(stderr, "Ignoring path %s\n", path);
 		return;
 	}
+	if (mark_valid_only) {
+		if (mark_valid(p))
+			die("Unable to mark file %s", path);
+		return;
+	}
+
 	if (force_remove) {
 		if (remove_file_from_cache(p))
 			die("git-update-index: unable to remove %s", path);
@@ -467,7 +506,11 @@ int main(int argc, const char **argv)
 				continue;
 			}
 			if (!strcmp(path, "--refresh")) {
-				has_errors |= refresh_cache();
+				has_errors |= refresh_cache(0);
+				continue;
+			}
+			if (!strcmp(path, "--really-refresh")) {
+				has_errors |= refresh_cache(1);
 				continue;
 			}
 			if (!strcmp(path, "--cacheinfo")) {
@@ -493,6 +536,14 @@ int main(int argc, const char **argv)
 					die("git-update-index: %s cannot chmod %s", path, argv[i]);
 				continue;
 			}
+			if (!strcmp(path, "--assume-unchanged")) {
+				mark_valid_only = MARK_VALID;
+				continue;
+			}
+			if (!strcmp(path, "--no-assume-unchanged")) {
+				mark_valid_only = UNMARK_VALID;
+				continue;
+			}
 			if (!strcmp(path, "--info-only")) {
 				info_only = 1;
 				continue;
diff --git a/write-tree.c b/write-tree.c
index f866059..addb5de 100644
--- a/write-tree.c
+++ b/write-tree.c
@@ -111,7 +111,7 @@ int main(int argc, char **argv)
 	funny = 0;
 	for (i = 0; i < entries; i++) {
 		struct cache_entry *ce = active_cache[i];
-		if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
+		if (ce_stage(ce)) {
 			if (10 < ++funny) {
 				fprintf(stderr, "...\n");
 				break;
-- 
1.1.6.gbb042

^ permalink raw reply related	[relevance 10%]

* [PATCH] Don't send copies to the From: address
@ 2006-02-11  2:47 47% Christian Biesinger
  2006-02-11  3:55 44% ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Christian Biesinger @ 2006-02-11  2:47 UTC (permalink / raw)
  To: git

Sending copies to the from address is pointless. Not
sending copies there makes it possible to do:

  git-format-patch --mbox origin
  git-send-email 00*

and get a reasonable result.

Signed-off-by: Christian Biesinger <cbiesinger@web.de>

---

 git-send-email.perl |   16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

486a15e29dff39ff5885d7a1e38d6c5c3b70127b
diff --git a/git-send-email.perl b/git-send-email.perl
index 3f1b3ca..31d23d6 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -304,9 +304,11 @@ foreach my $t (@files) {
 					$subject = $1;
 
 				} elsif (/^(Cc|From):\s+(.*)$/) {
-					printf("(mbox) Adding cc: %s from line '%s'\n",
-						$2, $_) unless $quiet;
-					push @cc, $2;
+					unless ($2 eq $from) {
+						printf("(mbox) Adding cc: %s from line '%s'\n",
+							$2, $_) unless $quiet;
+						push @cc, $2;
+					}
 				}
 
 			} else {
@@ -335,9 +337,11 @@ foreach my $t (@files) {
 			if (/^Signed-off-by: (.*)$/i) {
 				my $c = $1;
 				chomp $c;
-				push @cc, $c;
-				printf("(sob) Adding cc: %s from line '%s'\n",
-					$c, $_) unless $quiet;
+				unless ($c eq $from) {
+					push @cc, $c;
+					printf("(sob) Adding cc: %s from line '%s'\n",
+						$c, $_) unless $quiet;
+				}
 			}
 		}
 	}
-- 
1.1.6.g71f7-dirty

^ permalink raw reply related	[relevance 47%]

* Re: [PATCH] Don't send copies to the From: address
  2006-02-11  2:47 47% [PATCH] Don't send copies to the From: address Christian Biesinger
@ 2006-02-11  3:55 44% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-11  3:55 UTC (permalink / raw)
  To: Christian Biesinger; +Cc: git, Ryan Anderson, Greg Kroah-Hartman

Christian Biesinger <cbiesinger@web.de> writes:

> Sending copies to the from address is pointless.

Ryan, care to defend this part of the code?  This behaviour
might have been inherited from Greg's original version.

I cannot speak for Ryan or Greg, but I think the script
deliberately does this to support this workflow:

 (1) The original author sends in a patch to a subsystem
     maintainer;

 (2) The subsystem maintainer applies the patch to her tree,
     perhaps with her own sign-off and sign-offs by other people
     collected from the list.  She examines it and says this
     patch is good;

 (3) The commit is formatted and sent to higher level of the
     foodchain.  The message is CC'ed to interested parties in
     order to notify that the patch progressed in the
     foodchain.

Me, personally I do not like CC: to people on the signed-off-by
list, but dropping a note to From: person makes perfect sense to
me, if it is to notify the progress of the patch.

What you are after _might_ be not CC'ing it if it was your own
patch.  Maybe something like this would help, but even if that
is the case I suspect many people want to CC herself so it needs
to be an optional feature.

-- >8 --
[PATCH] Do not CC me

---
git diff
diff --git a/git-send-email.perl b/git-send-email.perl
index 3f1b3ca..a02e2f8 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -343,7 +343,7 @@ foreach my $t (@files) {
 	}
 	close F;
 
-	$cc = join(", ", unique_email_list(@cc));
+	$cc = join(", ", unique_email_list(grep { $_ ne $from } @cc));
 
 	send_message();
 

^ permalink raw reply related	[relevance 44%]

* Make "git clone" less of a deathly quiet experience
@ 2006-02-11  4:31 11% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-02-11  4:31 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano, Petr Baudis


I was on IRC today (which is definitely not normal, but hey, I tried it), 
and somebody was complaining about how horribly slow "git clone" was on 
the WineHQ repository.

The WineHQ git repo is actually fairly big: 120+MB packed, 220+ thousand 
objects. So creating the pack is actually a big operation, and yes, it's 
too slow. We should be better at it, and it would be good if the pack-file 
generation were much faster.

However, it turns out that the "slow" git-pack-objects was only using up 
2.3% of CPU time. The fact is, the primary reason it took a long time is 
that even packed, it had to get 120 MB of data. So in this case, it 
appears that the fact that it uses a lot of CPU is actually a good 
trade-off, because the damn thing would have been even slower if it hadn't 
been packed.

(Of course, pre-generated packs would be good regardless)

Anyway, what _really_ made for a pissed-off user was that "git clone" was 
just very very silent all the time. No updates on what the hell it was 
doing. Was it working at all? Was something broken? Is git just a piece of 
cr*p? But "git clone" would not say a peep about it.

It used to be that "git-unpack-objects" would give nice percentages, but 
now that we don't unpack the initial clone pack any more, it doesn't. And 
I'd love to do that nice percentage view in the pack objects downloader 
too, but the thing doesn't even read the pack header, much less know how 
much it's going to get, so I was lazy and didn't.

Instead, it at least prints out how much data it's gotten, and what the 
packign speed is. Which makes the user realize that it's actually doing 
something useful instead of sitting there silently (and if the recipient 
knows how large the final result is, he can at least make a guess about 
when it migt be done).

So with this patch, I get something like this on my DSL line:

	[torvalds@g5 ~]$ time git clone master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 clone-test
	Packing 188543 objects
	  48.398MB  (154 kB/s)

where even the speed approximation seem sto be roughtly correct (even 
though my algorithm is a truly stupid one, and only really gives "speed in 
the last half second or so").

Anyway, _something_ like this is definitely needed. It could certainly be 
better (if it showed the same kind of thing that git-unpack-objects did, 
that would be much nicer, but would require parsing the object stream as 
it comes in). But this is  big step forward, I think.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Comments? Hate-mail? Improvements?

diff --git a/cache.h b/cache.h
index bdbe2d6..c255421 100644
--- a/cache.h
+++ b/cache.h
@@ -348,6 +348,6 @@ extern int copy_fd(int ifd, int ofd);
 
 /* Finish off pack transfer receiving end */
 extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
-extern int receive_keep_pack(int fd[2], const char *me);
+extern int receive_keep_pack(int fd[2], const char *me, int quiet);
 
 #endif /* CACHE_H */
diff --git a/clone-pack.c b/clone-pack.c
index f634431..719e1c4 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -6,6 +6,8 @@ static const char clone_pack_usage[] =
 "git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
 static const char *exec = "git-upload-pack";
 
+static int quiet = 0;
+
 static void clone_handshake(int fd[2], struct ref *ref)
 {
 	unsigned char sha1[20];
@@ -123,7 +125,9 @@ static int clone_pack(int fd[2], int nr_
 	}
 	clone_handshake(fd, refs);
 
-	status = receive_keep_pack(fd, "git-clone-pack");
+	if (!quiet)
+		fprintf(stderr, "Generating pack ...\r");
+	status = receive_keep_pack(fd, "git-clone-pack", quiet);
 
 	if (!status) {
 		if (nr_match == 0)
@@ -154,8 +158,10 @@ int main(int argc, char **argv)
 		char *arg = argv[i];
 
 		if (*arg == '-') {
-			if (!strcmp("-q", arg))
+			if (!strcmp("-q", arg)) {
+				quiet = 1;
 				continue;
+			}
 			if (!strncmp("--exec=", arg, 7)) {
 				exec = arg + 7;
 				continue;
diff --git a/fetch-clone.c b/fetch-clone.c
index 859f400..b67d976 100644
--- a/fetch-clone.c
+++ b/fetch-clone.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include <sys/wait.h>
+#include <sys/time.h>
 
 static int finish_pack(const char *pack_tmp_name, const char *me)
 {
@@ -129,10 +130,12 @@ int receive_unpack_pack(int fd[2], const
 	die("git-unpack-objects died of unnatural causes %d", status);
 }
 
-int receive_keep_pack(int fd[2], const char *me)
+int receive_keep_pack(int fd[2], const char *me, int quiet)
 {
 	char tmpfile[PATH_MAX];
 	int ofd, ifd;
+	unsigned long total;
+	static struct timeval prev_tv;
 
 	ifd = fd[0];
 	snprintf(tmpfile, sizeof(tmpfile),
@@ -141,6 +144,8 @@ int receive_keep_pack(int fd[2], const c
 	if (ofd < 0)
 		return error("unable to create temporary file %s", tmpfile);
 
+	gettimeofday(&prev_tv, NULL);
+	total = 0;
 	while (1) {
 		char buf[8192];
 		ssize_t sz, wsz, pos;
@@ -165,6 +170,27 @@ int receive_keep_pack(int fd[2], const c
 			}
 			pos += wsz;
 		}
+		total += sz;
+		if (!quiet) {
+			static unsigned long last;
+			struct timeval tv;
+			unsigned long diff = total - last;
+			/* not really "msecs", but a power-of-two millisec (1/1024th of a sec) */
+			unsigned long msecs;
+
+			gettimeofday(&tv, NULL);
+			msecs = tv.tv_sec - prev_tv.tv_sec;
+			msecs <<= 10;
+			msecs += (int)(tv.tv_usec - prev_tv.tv_usec) >> 10;
+			if (msecs > 500) {
+				prev_tv = tv;
+				last = total;
+				fprintf(stderr, "%4lu.%03luMB  (%lu kB/s)        \r",
+					total >> 20,
+					1000*((total >> 10) & 1023)>>10,
+					diff / msecs );
+			}
+		}
 	}
 	close(ofd);
 	return finish_pack(tmpfile, me);
diff --git a/fetch-pack.c b/fetch-pack.c
index 27f5d2a..aa6f42a 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -378,7 +378,7 @@ static int fetch_pack(int fd[2], int nr_
 		fprintf(stderr, "warning: no common commits\n");
 
 	if (keep_pack)
-		status = receive_keep_pack(fd, "git-fetch-pack");
+		status = receive_keep_pack(fd, "git-fetch-pack", quiet);
 	else
 		status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
 

^ permalink raw reply related	[relevance 11%]

* [PATCH 2/2] send-email: Add --cc
  2006-02-13  8:22 49% ` [PATCH 1/2] send-email: Add some options for controlling how addresses are automatically Ryan Anderson
@ 2006-02-13  8:22 54%   ` Ryan Anderson
  0 siblings, 0 replies; 200+ results
From: Ryan Anderson @ 2006-02-13  8:22 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Ryan Anderson

Since Junio used this in an example, and I've personally tried to use it, I
suppose the option should actually exist.

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 Documentation/git-send-email.txt |    3 +++
 git-send-email.perl              |    8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

6d18725b9d46259162cfe54c9e0e369558394816
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index c2f52f5..8c58685 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -24,6 +24,9 @@ OPTIONS
 -------
 The options available are:
 
+--cc::
+	Specify a starting "Cc:" value for each email.
+
 --chain-reply-to, --no-chain-reply-to::
 	If this is set, each email will be sent as a reply to the previous
 	email sent.  If disabled with "--no-chain-reply-to", all emails after
diff --git a/git-send-email.perl b/git-send-email.perl
index abffca5..13b85dd 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -31,7 +31,7 @@ sub cleanup_compose_files();
 my $compose_filename = ".msg.$$";
 
 # Variables we fill in automatically, or via prompting:
-my (@to,@cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
+my (@to,@cc,@initial_cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
 
 # Behavior modification variables
 my ($chain_reply_to, $smtp_server, $quiet, $suppress_from, $no_signed_off_cc) = (1, "localhost", 0, 0, 0);
@@ -48,6 +48,7 @@ my $rc = GetOptions("from=s" => \$from,
                     "in-reply-to=s" => \$initial_reply_to,
 		    "subject=s" => \$initial_subject,
 		    "to=s" => \@to,
+		    "cc=s" => \@initial_cc,
 		    "chain-reply-to!" => \$chain_reply_to,
 		    "smtp-server=s" => \$smtp_server,
 		    "compose" => \$compose,
@@ -199,6 +200,9 @@ Options:
 
    --to           Specify the primary "To:" line of the email.
 
+   --cc           Specify an initial "Cc:" list for the entire series
+                  of emails.
+
    --compose      Use \$EDITOR to edit an introductory message for the
                   patch series.
 
@@ -298,7 +302,7 @@ $subject = $initial_subject;
 foreach my $t (@files) {
 	open(F,"<",$t) or die "can't open file $t";
 
-	@cc = ();
+	@cc = @initial_cc;
 	my $found_mbox = 0;
 	my $header_done = 0;
 	$message = "";
-- 
1.2.0.g6d18

^ permalink raw reply related	[relevance 54%]

* [PATCH 1/2] send-email: Add some options for controlling how addresses are automatically
  @ 2006-02-13  8:22 49% ` Ryan Anderson
  2006-02-13  8:22 54%   ` [PATCH 2/2] send-email: Add --cc Ryan Anderson
  0 siblings, 1 reply; 200+ results
From: Ryan Anderson @ 2006-02-13  8:22 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Ryan Anderson

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 Documentation/git-send-email.txt |    7 +++++++
 git-send-email.perl              |   15 ++++++++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

dc4ad3ef1b29ce35dc0ace4d284cfab5e594bfb7
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 00537d8..c2f52f5 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -48,6 +48,9 @@ The options available are:
 	Only necessary if --compose is also set.  If --compose
 	is not set, this will be prompted for.
 
+--no-signed-off-by-cc::
+	Do not add emails foudn in Signed-off-by: lines to the cc list.
+
 --quiet::
 	Make git-send-email less verbose.  One line per email should be
 	all that is output.
@@ -61,6 +64,10 @@ The options available are:
 	Only necessary if --compose is also set.  If --compose
 	is not set, this will be prompted for.
 
+--suppress-from::
+	Do not add the From: address to the cc: list, if it shows up in a From:
+	line.
+
 --to::
 	Specify the primary recipient of the emails generated.
 	Generally, this will be the upstream maintainer of the
diff --git a/git-send-email.perl b/git-send-email.perl
index 3f1b3ca..abffca5 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -34,7 +34,7 @@ my $compose_filename = ".msg.$$";
 my (@to,@cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
 
 # Behavior modification variables
-my ($chain_reply_to, $smtp_server, $quiet) = (1, "localhost", 0);
+my ($chain_reply_to, $smtp_server, $quiet, $suppress_from, $no_signed_off_cc) = (1, "localhost", 0, 0, 0);
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -52,6 +52,8 @@ my $rc = GetOptions("from=s" => \$from,
 		    "smtp-server=s" => \$smtp_server,
 		    "compose" => \$compose,
 		    "quiet" => \$quiet,
+		    "suppress-from" => \$suppress_from,
+		    "no-signed-off-cc" => \$no_signed_off_cc,
 	 );
 
 # Now, let's fill any that aren't set in with defaults:
@@ -212,13 +214,19 @@ Options:
                   email sent, rather than to the first email sent.
                   Defaults to on.
 
+   --no-signed-off-cc Suppress the automatic addition of email addresses
+                 that appear in a Signed-off-by: line, to the cc: list.
+		 Note: Using this option is not recommended.
+
    --smtp-server  If set, specifies the outgoing SMTP server to use.
                   Defaults to localhost.
 
+  --suppress-from Supress sending emails to yourself if your address
+                  appears in a From: line.
+
    --quiet	Make git-send-email less verbose.  One line per email should be
 		all that is output.
 
-
 Error: Please specify a file or a directory on the command line.
 EOT
 	exit(1);
@@ -304,6 +312,7 @@ foreach my $t (@files) {
 					$subject = $1;
 
 				} elsif (/^(Cc|From):\s+(.*)$/) {
+					next if ($2 eq $from && $suppress_from);
 					printf("(mbox) Adding cc: %s from line '%s'\n",
 						$2, $_) unless $quiet;
 					push @cc, $2;
@@ -332,7 +341,7 @@ foreach my $t (@files) {
 			}
 		} else {
 			$message .=  $_;
-			if (/^Signed-off-by: (.*)$/i) {
+			if (/^Signed-off-by: (.*)$/i && !$no_signed_off_cc) {
 				my $c = $1;
 				chomp $c;
 				push @cc, $c;
-- 
1.2.0.g6d18

^ permalink raw reply related	[relevance 49%]

* [PATCH] packed objects: minor cleanup
  @ 2006-02-16  1:45 17%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-16  1:45 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds

The delta depth is unsigned.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * And this is the clean-up patch that comes before the "packed
   representation reuse" patch.

 cache.h      |    2 +-
 pack-check.c |    4 ++--
 sha1_file.c  |    4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

f8f135c9bae74f846a92e1f1f1fea8308802ace5
diff --git a/cache.h b/cache.h
index c255421..b5db01f 100644
--- a/cache.h
+++ b/cache.h
@@ -322,7 +322,7 @@ extern int num_packed_objects(const stru
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
 extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
 extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
-extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, int *, unsigned char *);
+extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
 
 /* Dumb servers support */
 extern int update_server_info(int);
diff --git a/pack-check.c b/pack-check.c
index 67a7ecd..eca32b6 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -84,7 +84,7 @@ static void show_pack_info(struct packed
 		char type[20];
 		unsigned long size;
 		unsigned long store_size;
-		int delta_chain_length;
+		unsigned int delta_chain_length;
 
 		if (nth_packed_object_sha1(p, i, sha1))
 			die("internal error pack-check nth-packed-object");
@@ -98,7 +98,7 @@ static void show_pack_info(struct packed
 		if (!delta_chain_length)
 			printf("%-6s %lu %u\n", type, size, e.offset);
 		else
-			printf("%-6s %lu %u %d %s\n", type, size, e.offset,
+			printf("%-6s %lu %u %u %s\n", type, size, e.offset,
 			       delta_chain_length, sha1_to_hex(base_sha1));
 	}
 
diff --git a/sha1_file.c b/sha1_file.c
index 3d11a9b..64cf245 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -830,7 +830,7 @@ void packed_object_info_detail(struct pa
 			       char *type,
 			       unsigned long *size,
 			       unsigned long *store_size,
-			       int *delta_chain_length,
+			       unsigned int *delta_chain_length,
 			       unsigned char *base_sha1)
 {
 	struct packed_git *p = e->p;
@@ -844,7 +844,7 @@ void packed_object_info_detail(struct pa
 	if (kind != OBJ_DELTA)
 		*delta_chain_length = 0;
 	else {
-		int chain_length = 0;
+		unsigned int chain_length = 0;
 		memcpy(base_sha1, pack, 20);
 		do {
 			struct pack_entry base_ent;
-- 
1.2.0.gcfba7

^ permalink raw reply related	[relevance 17%]

* [PATCH] Delay "empty ident" errors until they really matter.
  @ 2006-02-19  4:56 12%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-19  4:56 UTC (permalink / raw)
  To: git; +Cc: Petr Baudis

Previous one warned people upfront to encourage fixing their
environment early, but some people just use repositories and git
tools read-only without making any changes, and in such a case
there is not much point insisting on them having a usable ident.

This round attempts to move the error until either "git-var"
asks for the ident explicitly or "commit-tree" wants to use it.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---
  Petr Baudis <pasky@suse.cz> writes:

  > One dislike from me - you shouldn't care if you ain't gonna do it - it
  > makes no sense to require valid gecos if you are never committing
  > anything.

  You are absolutely right.  This is to fix the previous one.

 cache.h       |    4 ++--
 commit-tree.c |    4 ++--
 ident.c       |   47 +++++++++++++++++++++++++----------------------
 var.c         |    6 +++---
 4 files changed, 32 insertions(+), 29 deletions(-)

749be728d469e9a0acfdc020feff17c2da510083
diff --git a/cache.h b/cache.h
index b5db01f..da73fb3 100644
--- a/cache.h
+++ b/cache.h
@@ -246,8 +246,8 @@ void datestamp(char *buf, int bufsize);
 unsigned long approxidate(const char *);
 
 extern int setup_ident(void);
-extern const char *git_author_info(void);
-extern const char *git_committer_info(void);
+extern const char *git_author_info(int);
+extern const char *git_committer_info(int);
 
 struct checkout {
 	const char *base_dir;
diff --git a/commit-tree.c b/commit-tree.c
index b1c8dca..88871b0 100644
--- a/commit-tree.c
+++ b/commit-tree.c
@@ -118,8 +118,8 @@ int main(int argc, char **argv)
 		add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
 
 	/* Person/date information */
-	add_buffer(&buffer, &size, "author %s\n", git_author_info());
-	add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info());
+	add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
+	add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info(1));
 
 	/* And add the comment */
 	while (fgets(comment, sizeof(comment), stdin) != NULL)
diff --git a/ident.c b/ident.c
index 09d4d71..7c81fe8 100644
--- a/ident.c
+++ b/ident.c
@@ -46,15 +46,6 @@ static void copy_gecos(struct passwd *w,
 
 }
 
-static const char au_env[] = "GIT_AUTHOR_NAME";
-static const char co_env[] = "GIT_COMMITTER_NAME";
-static const char env_hint[] =
-"\n*** Environment problem:\n"
-"*** Your name cannot be determined from your system services (gecos).\n"
-"*** You would need to set %s and %s\n"
-"*** environment variables; otherwise you won't be able to perform\n"
-"*** certain operations because of \"empty ident\" errors.\n\n";
-
 int setup_ident(void)
 {
 	int len;
@@ -66,11 +57,6 @@ int setup_ident(void)
 	/* Get the name ("gecos") */
 	copy_gecos(pw, git_default_name, sizeof(git_default_name));
 
-	if (!*git_default_name) {
-		if (!getenv(au_env) || !getenv(co_env))
-			fprintf(stderr, env_hint, au_env, co_env);
-	}
-
 	/* Make up a fake email address (name + '@' + hostname [+ '.' + domainname]) */
 	len = strlen(pw->pw_name);
 	if (len > sizeof(git_default_email)/2)
@@ -170,8 +156,18 @@ static int copy(char *buf, int size, int
 	return offset;
 }
 
+static const char au_env[] = "GIT_AUTHOR_NAME";
+static const char co_env[] = "GIT_COMMITTER_NAME";
+static const char *env_hint =
+"\n*** Environment problem:\n"
+"*** Your name cannot be determined from your system services (gecos).\n"
+"*** You would need to set %s and %s\n"
+"*** environment variables; otherwise you won't be able to perform\n"
+"*** certain operations because of \"empty ident\" errors.\n"
+"*** Alternatively, you can use user.name configuration variable.\n\n";
+
 static const char *get_ident(const char *name, const char *email,
-			     const char *date_str)
+			     const char *date_str, int error_on_no_name)
 {
 	static char buffer[1000];
 	char date[50];
@@ -182,9 +178,14 @@ static const char *get_ident(const char 
 	if (!email)
 		email = git_default_email;
 
-	if (!*name || !*email)
-		die("empty ident %s <%s> not allowed",
-		    name, email);
+	if (!*name) {
+		if (name == git_default_name && env_hint) {
+			fprintf(stderr, env_hint, au_env, co_env);
+			env_hint = NULL; /* warn only once, for "git-var -l" */
+		}
+		if (error_on_no_name)
+			die("empty ident %s <%s> not allowed", name, email);
+	}
 
 	strcpy(date, git_default_date);
 	if (date_str)
@@ -201,16 +202,18 @@ static const char *get_ident(const char 
 	return buffer;
 }
 
-const char *git_author_info(void)
+const char *git_author_info(int error_on_no_name)
 {
 	return get_ident(getenv("GIT_AUTHOR_NAME"),
 			 getenv("GIT_AUTHOR_EMAIL"),
-			 getenv("GIT_AUTHOR_DATE"));
+			 getenv("GIT_AUTHOR_DATE"),
+			 error_on_no_name);
 }
 
-const char *git_committer_info(void)
+const char *git_committer_info(int error_on_no_name)
 {
 	return get_ident(getenv("GIT_COMMITTER_NAME"),
 			 getenv("GIT_COMMITTER_EMAIL"),
-			 getenv("GIT_COMMITTER_DATE"));
+			 getenv("GIT_COMMITTER_DATE"),
+			 error_on_no_name);
 }
diff --git a/var.c b/var.c
index 59da56d..a57a33b 100644
--- a/var.c
+++ b/var.c
@@ -12,7 +12,7 @@ static const char var_usage[] = "git-var
 
 struct git_var {
 	const char *name;
-	const char *(*read)(void);
+	const char *(*read)(int);
 };
 static struct git_var git_vars[] = {
 	{ "GIT_COMMITTER_IDENT", git_committer_info },
@@ -24,7 +24,7 @@ static void list_vars(void)
 {
 	struct git_var *ptr;
 	for(ptr = git_vars; ptr->read; ptr++) {
-		printf("%s=%s\n", ptr->name, ptr->read());
+		printf("%s=%s\n", ptr->name, ptr->read(0));
 	}
 }
 
@@ -35,7 +35,7 @@ static const char *read_var(const char *
 	val = NULL;
 	for(ptr = git_vars; ptr->read; ptr++) {
 		if (strcmp(var, ptr->name) == 0) {
-			val = ptr->read();
+			val = ptr->read(1);
 			break;
 		}
 	}
-- 
1.2.1.g2902

^ permalink raw reply related	[relevance 12%]

* [PATCH] send-email: avoid open "-|" list form for Perl 5.6
  @ 2006-02-20 22:12 47%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-20 22:12 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Ryan Anderson


Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 git-send-email.perl |   39 ++++++++++++++++++++++-----------------
 1 files changed, 22 insertions(+), 17 deletions(-)

044ece3bc8bde227babd2f710f8216f2cb631034
diff --git a/git-send-email.perl b/git-send-email.perl
index 13b85dd..b4f04f9 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -59,24 +59,29 @@ my $rc = GetOptions("from=s" => \$from,
 
 # Now, let's fill any that aren't set in with defaults:
 
-open(GITVAR,"-|","git-var","-l")
-	or die "Failed to open pipe from git-var: $!";
-
-my ($author,$committer);
-while(<GITVAR>) {
-	chomp;
-	my ($var,$data) = split /=/,$_,2;
-	my @fields = split /\s+/, $data;
-
-	my $ident = join(" ", @fields[0...(@fields-3)]);
-
-	if ($var eq 'GIT_AUTHOR_IDENT') {
-		$author = $ident;
-	} elsif ($var eq 'GIT_COMMITTER_IDENT') {
-		$committer = $ident;
-	}
+sub gitvar {
+    my ($var) = @_;
+    my $fh;
+    my $pid = open($fh, '-|');
+    die "$!" unless defined $pid;
+    if (!$pid) {
+	exec('git-var', $var) or die "$!";
+    }
+    my ($val) = <$fh>;
+    close $fh or die "$!";
+    chomp($val);
+    return $val;
+}
+
+sub gitvar_ident {
+    my ($name) = @_;
+    my $val = gitvar($name);
+    my @field = split(/\s+/, $val);
+    return join(' ', @field[0...(@field-3)]);
 }
-close(GITVAR);
+
+$author = gitvar_ident('GIT_AUTHOR_IDENT');
+$committer = gitvar_ident('GIT_COMMITTER_IDENT');
 
 my $prompting = 0;
 if (!defined $from) {
-- 
1.2.2.g5be4ea

^ permalink raw reply related	[relevance 47%]

* [PATCH] Convert open("-|") to qx{} calls
@ 2006-02-23 14:33 38% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2006-02-23 14:33 UTC (permalink / raw)
  To: git, junkio


Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	Since of these 4, I only use cvsimport myself, I could only test
	that. Could someone who uses the others give them a hard beating?

 git-cvsimport.perl  |   64 +++++++++++++++++++--------------------------------
 git-rerere.perl     |    9 ++-----
 git-send-email.perl |    9 ++-----
 git-svnimport.perl  |   62 ++++++++++++++-----------------------------------
 4 files changed, 46 insertions(+), 98 deletions(-)

b37d21c223fdc0ef7fc6af889432f6b51ac82992
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index b46469a..da009f2 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -478,9 +478,9 @@ unless(-d $git_dir) {
 		       "Either use the correct '-o branch' option,\n".
 		       "or import to a new repository.\n";
 
-	open(F, "git-symbolic-ref HEAD |") or
-		die "Cannot run git-symbolic-ref: $!\n";
-	chomp ($last_branch = <F>);
+	$last_branch = qx{git-symbolic-ref HEAD};
+	!$? or exit $?;
+	chomp ($last_branch);
 	$last_branch = basename($last_branch);
 	close(F);
 	unless($last_branch) {
@@ -516,13 +516,12 @@ EOM
 			or die "Bad head branch: $head: $!\n";
 		chomp(my $ftag = <F>);
 		close(F);
-		open(F,"git-cat-file commit $ftag |");
-		while(<F>) {
+		foreach (qx{git-cat-file commit $ftag}) {
 			next unless /^author\s.*\s(\d+)\s[-+]\d{4}$/;
 			$branch_date{$head} = $1;
 			last;
 		}
-		close(F);
+		!$? or exit $?;
 	}
 	closedir(D);
 }
@@ -538,24 +537,21 @@ if ($opt_A) {
 	write_author_info("$git_dir/cvs-authors");
 }
 
-my $pid = open(CVS,"-|");
-die "Cannot fork: $!\n" unless defined $pid;
-unless($pid) {
-	my @opt;
-	@opt = split(/,/,$opt_p) if defined $opt_p;
-	unshift @opt, '-z', $opt_z if defined $opt_z;
-	unshift @opt, '-q'         unless defined $opt_v;
-	unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
-		push @opt, '--cvs-direct';
-	}
-	if ($opt_P) {
-	    exec("cat", $opt_P);
-	} else {
-	    exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
-	    die "Could not start cvsps: $!\n";
-	}
+my @opt;
+@opt = split(/,/,$opt_p) if defined $opt_p;
+unshift @opt, '-z', $opt_z if defined $opt_z;
+unshift @opt, '-q'         unless defined $opt_v;
+unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
+	push @opt, '--cvs-direct';
 }
 
+my @input;
+if ($opt_P) {
+    @input = qx{cat $opt_P};
+} else {
+    @input = qx{cvsps --norc opt -u -A --root $opt_d $cvs_tree};
+    !$? or exit $?;
+}
 
 ## cvsps output:
 #---------------------
@@ -603,17 +599,11 @@ my $commit = sub {
 		die "Cannot add files: $?\n" if $?;
 	}
 
-	$pid = open(C,"-|");
-	die "Cannot fork: $!" unless defined $pid;
-	unless($pid) {
-		exec("git-write-tree");
-		die "Cannot exec git-write-tree: $!\n";
-	}
-	chomp(my $tree = <C>);
+	my $tree = qx{git-write-tree};
+	!$? or exit $?;
+	chomp($tree);
 	length($tree) == 40
 		or die "Cannot get tree id ($tree): $!\n";
-	close(C)
-		or die "Error running git-write-tree: $?\n";
 	print "Tree ID $tree\n" if $opt_v;
 
 	my $parent = "";
@@ -734,7 +724,7 @@ my $commit = sub {
 	}
 };
 
-while(<CVS>) {
+foreach (@input) {
 	chomp;
 	if($state == 0 and /^-+$/) {
 		$state = 1;
@@ -846,15 +836,9 @@ while(<CVS>) {
 			print "Drop $fn\n" if $opt_v;
 		} else {
 			print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
-			my $pid = open(my $F, '-|');
-			die $! unless defined $pid;
-			if (!$pid) {
-			    exec("git-hash-object", "-w", $tmpname)
-				or die "Cannot create object: $!\n";
-			}
-			my $sha = <$F>;
+			my $sha = qx{git-hash-object -w $tmpname};
+			!$? or exit $?;
 			chomp $sha;
-			close $F;
 			my $mode = pmode($cvs->{'mode'});
 			push(@new,[$mode, $sha, $fn]); # may be resurrected!
 		}
diff --git a/git-rerere.perl b/git-rerere.perl
index d3664ff..0dd04c5 100755
--- a/git-rerere.perl
+++ b/git-rerere.perl
@@ -131,20 +131,15 @@ sub record_preimage {
 sub find_conflict {
 	my $in;
 	local $/ = "\0";
-	my $pid = open($in, '-|');
-	die "$!" unless defined $pid;
-	if (!$pid) {
-		exec(qw(git ls-files -z -u)) or die "$!: ls-files";
-	}
 	my %path = ();
 	my @path = ();
-	while (<$in>) {
+	foreach (qx{git-ls-files -z -u}) {
 		chomp;
 		my ($mode, $sha1, $stage, $path) =
 		    /^([0-7]+) ([0-9a-f]{40}) ([123])\t(.*)$/s;
 		$path{$path} |= (1 << $stage);
 	}
-	close $in;
+	!$? or exit $?;
 	while (my ($path, $status) = each %path) {
 		if ($status == 14) { push @path, $path; }
 	}
diff --git a/git-send-email.perl b/git-send-email.perl
index b0d095b..bd8fae6 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -62,13 +62,8 @@ my $rc = GetOptions("from=s" => \$from,
 sub gitvar {
     my ($var) = @_;
     my $fh;
-    my $pid = open($fh, '-|');
-    die "$!" unless defined $pid;
-    if (!$pid) {
-	exec('git-var', $var) or die "$!";
-    }
-    my ($val) = <$fh>;
-    close $fh or die "$!";
+    my ($val) = qx{git-var $var};
+    !$? or exit $?;
     chomp($val);
     return $val;
 }
diff --git a/git-svnimport.perl b/git-svnimport.perl
index ee2940f..6094a11 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -218,11 +218,10 @@ unless(-d $git_dir) {
 	-f "$git_dir/svn2git"
 		or die "'$git_dir/svn2git' does not exist.\n".
 		       "You need that file for incremental imports.\n";
-	open(F, "git-symbolic-ref HEAD |") or
-		die "Cannot run git-symbolic-ref: $!\n";
-	chomp ($last_branch = <F>);
+	$last_brach = qx{git-symbolic-ref HEAD};
+	!$? or exit $?;
+	chomp $last_branch;
 	$last_branch = basename($last_branch);
-	close(F);
 	unless($last_branch) {
 		warn "Cannot read the last branch name: $! -- assuming 'master'\n";
 		$last_branch = "master";
@@ -321,15 +320,9 @@ sub get_file($$$) {
 		return undef unless defined $name;
 	}
 
-	my $pid = open(my $F, '-|');
-	die $! unless defined $pid;
-	if (!$pid) {
-	    exec("git-hash-object", "-w", $name)
-		or die "Cannot create object: $!\n";
-	}
-	my $sha = <$F>;
+	my $sha = qx{git-hash-object -w $name};
+	!$? or exit $?;
 	chomp $sha;
-	close $F;
 	unlink $name;
 	my $mode = "0644"; # SV does not seem to store any file modes
 	return [$mode, $sha, $path];
@@ -401,14 +394,8 @@ sub copy_path($$$$$$$$) {
 			$srcpath =~ s#/*$#/#;
 	}
 	
-	my $pid = open my $f,'-|';
-	die $! unless defined $pid;
-	if (!$pid) {
-		exec("git-ls-tree","-r","-z",$gitrev,$srcpath)
-			or die $!;
-	}
 	local $/ = "\0";
-	while(<$f>) {
+	foreach (qx{git-ls-tree -r -z $gitrev $srcpath}) {
 		chomp;
 		my($m,$p) = split(/\t/,$_,2);
 		my($mode,$type,$sha1) = split(/ /,$m);
@@ -420,8 +407,7 @@ sub copy_path($$$$$$$$) {
 		}
 		push(@$new,[$mode,$sha1,$p]);	
 	}
-	close($f) or
-		print STDERR "$newrev:$newbranch: could not list files in $oldpath \@ $rev\n";
+	!$? or exit $?;
 }
 
 sub commit {
@@ -472,9 +458,8 @@ sub commit {
 
 	my $rev;
 	if($revision > $opt_s and defined $parent) {
-		open(H,"git-rev-parse --verify $parent |");
-		$rev = <H>;
-		close(H) or do {
+		$rev = qx{git-rev-parse --verify $parent};
+		!$? or do {
 			print STDERR "$revision: cannot find commit '$parent'!\n";
 			return;
 		};
@@ -555,25 +540,20 @@ sub commit {
 		}
 
 		while(@old) {
-			my @o1;
+			my @o2;
 			if(@old > 55) {
-				@o1 = splice(@old,0,50);
+				@o2 = splice(@old,0,50);
 			} else {
-				@o1 = @old;
+				@o2 = @old;
 				@old = ();
 			}
-			my $pid = open my $F, "-|";
-			die "$!" unless defined $pid;
-			if (!$pid) {
-				exec("git-ls-files", "-z", @o1) or die $!;
-			}
-			@o1 = ();
+			my @o1 = ();
 			local $/ = "\0";
-			while(<$F>) {
+			foreach (qx{git-ls-files -z @o1}) {
 				chomp;
 				push(@o1,$_);
 			}
-			close($F);
+			!$? or exit $?;
 
 			while(@o1) {
 				my @o2;
@@ -600,17 +580,11 @@ sub commit {
 			die "Cannot add files: $?\n" if $?;
 		}
 
-		my $pid = open(C,"-|");
-		die "Cannot fork: $!" unless defined $pid;
-		unless($pid) {
-			exec("git-write-tree");
-			die "Cannot exec git-write-tree: $!\n";
-		}
-		chomp(my $tree = <C>);
+		my $tree = qx{git-write-tree};
+		!$? or exit $?;
+		chomp($tree);
 		length($tree) == 40
 			or die "Cannot get tree id ($tree): $!\n";
-		close(C)
-			or die "Error running git-write-tree: $?\n";
 		print "Tree ID $tree\n" if $opt_v;
 
 		my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n";
-- 
1.2.3.gb37d

^ permalink raw reply related	[relevance 38%]

* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
  @ 2006-02-24  6:43  6%                             ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-02-24  6:43 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Junio C Hamano, git



On Fri, 24 Feb 2006, Sam Vilain wrote:
> 
> I like the term "Domain Specific Language" to refer to this sort of thing.  It
> even hints at using the right kind of tools to achieve it, too :)

Just for fun, I wrote a first cut at a script engine for passing pipes 
around.

It's designed so that the "fork+exec with a pipe" should be easily 
replaced by "spawn with a socket" if that's what the target wants, but 
it also has some rather strange syntax, so I'm in no way claiming that 
this is a sane approach.

It was fun to write, though. You can already do some strange things with 
it, like writing a script like this

	set @ --since=2.months.ago Makefile
	exec git-rev-parse --default HEAD $@
		stdout arguments
	exec git-rev-list $arguments
		stdout revlist
	exec git-diff-tree --pretty --stdin
		stdin revlist
		stdout diff-tree-output
	exec less -S
		stdin diff-tree-output

which kind of shows the idea (it sets the "@" variable by hand, because 
the silly "git-script" thing doesn't set it itself).

I'm not sure this is worth pursuing (it really is a very strange kind of 
script syntax), but it was amusing to do. 

No docs - if you want to know how it works, you'll just have to read the 
equally strange sources.

		Linus

----
diff-tree 3e7dbcaae63278ccd413d93ecf9cba65a0d07021 (from d27d5b3c5b97ca30dfc5c448dc8cdae914131051)
Author: Linus Torvalds <torvalds@osdl.org>
Date:   Thu Feb 23 22:06:12 2006 -0800

    Add really strange script engine

diff --git a/Makefile b/Makefile
index 0c04882..247030b 100644
--- a/Makefile
+++ b/Makefile
@@ -164,7 +164,7 @@ PROGRAMS = \
 	git-upload-pack$X git-verify-pack$X git-write-tree$X \
 	git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
-	git-describe$X git-merge-tree$X
+	git-describe$X git-merge-tree$X git-script$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -204,7 +204,7 @@ LIB_OBJS = \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
-	fetch-clone.o \
+	fetch-clone.o execute.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/cache.h b/cache.h
index 5020f07..e4e66ce 100644
--- a/cache.h
+++ b/cache.h
@@ -352,4 +352,7 @@ extern int copy_fd(int ifd, int ofd);
 extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
 extern int receive_keep_pack(int fd[2], const char *me, int quiet);
 
+/* script execution engine.. */
+extern int execute(const char *name, char *buf, unsigned int size);
+
 #endif /* CACHE_H */
diff --git a/execute.c b/execute.c
new file mode 100644
index 0000000..abb6801
--- /dev/null
+++ b/execute.c
@@ -0,0 +1,622 @@
+/*
+ * Stupid git script execution engine
+ *
+ * Copyrigt (C) 2006, Linus Torvalds
+ *
+ * There's one rule here: only ever expand a single level of variables.
+ * In particular - we never expand as a string, and keep everything as
+ * a list of entries. Always.
+ *
+ * This avoids all issues with quoting etc, since it's never an issue.
+ * When we execute a program, we have a list of arguments, no quoting
+ * or string parsing involved.
+ */
+#include "cache.h"
+#include <sys/wait.h>
+
+enum vartype {
+	var_none,
+	var_fd,
+	var_array
+};
+
+struct argument {
+	enum vartype type;
+	int fd, members, allocs, error;
+	const char **array;
+};
+
+struct variable {
+	const char *name;
+	struct variable *next;
+	struct argument value;
+};
+
+struct cmd_struct {
+	const char *line;
+	unsigned int len;
+	struct cmd_struct *subcmd;
+	struct cmd_struct *next;
+};
+
+struct parse_buf {
+	const char *name;
+	const char *error;
+	char *prog;
+	unsigned int size;
+	unsigned int offset;
+	unsigned int line;
+	unsigned int linestart;
+};
+
+static struct variable *vars = NULL;
+static void run_program(struct cmd_struct *cmd);
+
+static int countline(struct parse_buf *buf)
+{
+	int count = 0;
+	unsigned offset;
+
+	for (offset = buf->offset; offset < buf->size; offset++) {
+		unsigned char c = buf->prog[offset];
+		switch (c) {
+		case '\n':
+			buf->line++;
+		/* fallthrough */
+		case '\r':
+			count = 0;
+			buf->offset = offset + 1;
+			buf->prog[offset] = 0;
+			continue;
+		case ' ':
+			count++;
+			continue;
+		case '\t':
+			count = (count + 8) & ~7;
+			continue;
+		default:
+			buf->linestart = offset;
+			return count;
+		}
+	}
+	buf->offset = offset;
+	return -2;
+}
+
+/*
+ * When this is called, we've already done the indentation check,
+ * and "buf->linestart" points to the actual start of the command.
+ */
+static struct cmd_struct *parse_one_line(struct parse_buf *buf)
+{
+	unsigned int offset;
+	struct cmd_struct *cmd = xmalloc(sizeof(*cmd));
+	memset(cmd, 0, sizeof(*cmd));
+
+	offset = buf->linestart;
+	cmd->line = buf->prog + offset;
+	for ( ; offset < buf->size; offset++) {
+		unsigned char c = buf->prog[offset];
+		switch (c) {
+		case '\n':
+			buf->prog[offset++] = 0;
+			buf->line++;
+			break;
+		default:
+			continue;
+		}
+		break;
+	}
+	buf->offset = offset;
+	return cmd;
+}
+
+static struct cmd_struct *parse(struct parse_buf *buf, int indent)
+{
+	struct cmd_struct *first = NULL, *last = NULL;
+
+	for (;;) {
+		struct cmd_struct *now;
+		int newindent = countline(buf);
+
+		if (newindent < indent)
+			break;
+		if (!first)
+			indent = newindent;
+		if (newindent > indent) {
+			struct cmd_struct *subcmd;
+			if (last->subcmd) {
+				buf->error = "bad indentation";
+				return NULL;
+			}
+			subcmd = parse(buf, newindent);
+			if (!subcmd)
+				return NULL;
+			last->subcmd = subcmd;
+			continue;
+		}
+		now = parse_one_line(buf);
+		if (!now)
+			return NULL;
+		if (last)
+			last->next = now;
+		else
+			first = now;
+		last = now;
+	}
+	return first;
+}
+
+static struct cmd_struct *exec_bad(struct cmd_struct *cmd, struct argument *arg)
+{
+	printf("unrecognized command: '%s'\n", cmd->line);
+	return NULL;
+}
+
+static struct cmd_struct *exec_echo(struct cmd_struct *cmd, struct argument *arg)
+{
+	int i;
+	for (i = 0; i < arg->members; i++)
+		printf("%s%c", arg->array[i], i == arg->members-1 ? '\n': ' ');
+	return cmd->next;
+}
+
+static struct variable *find_variable(const char *name)
+{
+	struct variable *var = vars;
+	while (var) {
+		if (!strcmp(var->name, name))
+			return var;
+		var = var->next;
+	}
+	return NULL;
+}
+
+static struct variable *create_variable(const char *name)
+{
+	struct variable *var = find_variable(name);
+
+	if (!var) {
+		var = xmalloc(sizeof(*var));
+		memset(var, 0, sizeof(*var));
+		var->name = name;
+		var->next = vars;
+		vars = var;
+	}
+	return var;
+}
+
+static struct cmd_struct *exec_set(struct cmd_struct *cmd, struct argument *arg)
+{
+	int count = arg->members;
+	struct variable *var;
+	const char *name;
+	unsigned size;
+
+	if (!count)
+		return cmd->next;
+	name = arg->array[0];
+	var = create_variable(arg->array[0]);
+
+	var->value.members = count-1;
+	size = count * sizeof(var->value.array[0]);
+	var->value.array = xmalloc(size);
+	memcpy(var->value.array, arg->array+1, size);
+
+	return cmd->next;
+}
+
+static void free_arg_list(struct argument *arg)
+{
+	/*
+	 * We can't free the actual entries, since we re-use them
+	 * on expansion. Right or wrong, that's how it is...
+	 */
+	free(arg->array);
+}
+
+static void drop_variable(struct variable *var)
+{
+	free_arg_list(&var->value);
+	free(var);
+}
+
+static struct cmd_struct *exec_unset(struct cmd_struct *cmd, struct argument *arg)
+{
+	int i;
+
+	for (i = 0; i < arg->members; i++) {
+		const char *name = arg->array[i];
+		struct variable *var, **p = &vars;
+
+		while ((var = *p) != NULL) {
+			if (!strcmp(var->name, name)) {
+				*p = var->next;
+				drop_variable(var);
+				break;
+			}
+			p = &var->next;
+		}
+	}
+	return cmd->next;
+}
+
+static struct cmd_struct *exec_exit(struct cmd_struct *cmd, struct argument *arg)
+{
+	int value = 0;
+	if (arg->members)
+		value = atoi(arg->array[0]);
+	exit(value);
+}
+
+static struct cmd_struct *exec_else(struct cmd_struct *cmd, struct argument *arg)
+{
+	return cmd->next;
+}
+
+static struct cmd_struct *exec_if(struct cmd_struct *cmd, struct argument *arg)
+{
+	struct cmd_struct *pos, *neg;
+
+	pos = cmd->subcmd;
+	neg = cmd->next;
+	if (neg) {
+		if (!strncmp(neg->line, "else", 4))
+			neg = neg->subcmd;
+		else
+			neg = NULL;
+	}
+	if (!arg->members)
+		pos = neg;
+	run_program(pos);
+	return cmd->next;
+}
+
+static int match_cmd(const char *match, struct cmd_struct *cmd)
+{
+	int len = strlen(match), cmdlen = strlen(cmd->line);
+	if (cmdlen < len)
+		return 0;
+	if (cmdlen > len && !isspace(cmd->line[len]))
+		return 0;
+	return !memcmp(match, cmd->line, len);
+}
+
+static int set_input(int *redirect, const char *val)
+{
+	struct variable *var;
+
+	while (isspace(*val))
+		val++;
+	var = find_variable(val);
+	if (!var || var->value.type != var_fd)
+		die("bad 'fd' variable %s", val);
+
+	*redirect = var->value.fd;
+	var->value.fd = -1;
+	return 0;
+}
+
+static int set_output(int *redirect, const char *val)
+{
+	int fd[2];
+	struct variable *var;
+
+	while (isspace(*val))
+		val++;
+	var = create_variable(val);
+
+	if (pipe(fd) < 0)
+		die("unable to pipe");
+	var->value.type = var_fd;
+	var->value.fd = fd[0];
+	*redirect = fd[1];
+	return 0;
+}
+
+/*
+ * Only these routines should need to be ported to a "spawn()" interface
+ */
+static struct cmd_struct *exec_exec(struct cmd_struct *cmd, struct argument *arg)
+{
+	int redirect[3];
+	pid_t pid;
+	int nr = arg->members;
+	struct cmd_struct *io;
+
+	if (!nr) {
+		run_program(cmd->subcmd);
+		return cmd->next;
+	}
+
+	memset(redirect, 0, sizeof(redirect));
+	for (io = cmd->subcmd; io ; io = io->next) {
+		if (match_cmd("stdin", io)) {
+			set_input(redirect+0, io->line + 5);
+			continue;
+		}
+		if (match_cmd("stdout", io)) {
+			set_output(redirect+1, io->line + 6);
+			continue;
+		}
+		if (match_cmd("stderr", io)) {
+			set_output(redirect+2, io->line + 6);
+			continue;
+		}
+	}
+
+	/*
+	 * HERE! Use spawn if necessary - the fd redirect table has been set up
+	 */
+	pid = vfork();
+	if (pid < 0) {
+		error("vfork failed (%s)", strerror(errno));
+		return NULL;
+	}
+
+	if (!pid) {
+		int retval;
+		if (redirect[0]) {
+			dup2(redirect[0], 0);
+			close(redirect[0]);
+		}
+		if (redirect[1]) {
+			dup2(redirect[1], 1);
+			close(redirect[1]);
+		}
+		if (redirect[2]) {
+			dup2(redirect[2], 2);
+			close(redirect[2]);
+		}
+		retval = execvp(arg->array[0], (char *const*) arg->array);
+		exit(255);
+	}
+
+	if (redirect[0])
+		close(redirect[0]);
+	if (redirect[1])
+		close(redirect[1]);
+	if (redirect[2])
+		close(redirect[2]);
+
+	/*
+	 * If we don't have anybody waiting for output,
+	 * wait for it
+	 */
+	if (!redirect[1]) {
+		int status;
+		while (waitpid(pid, &status, 0) < 0) {
+			if (errno == EINTR)
+				continue;
+			error("unable to wait for child (%s)", strerror(errno));
+			return NULL;
+		}
+		/* FIXME! Put exit status in a variable! */
+	}
+	run_program(cmd->subcmd);
+	return cmd->next;
+}
+
+static struct cmd_struct *exec_nop(struct cmd_struct *cmd, struct argument *arg)
+{
+	return cmd->next;
+}
+
+static const struct cmd_def {
+	const char *n;
+	int len;
+	struct cmd_struct *(*exec)(struct cmd_struct *, struct argument *);
+} cmds[] = {
+	{ "bad", 0, exec_bad },
+	{ "set", 3, exec_set },
+	{ "unset", 5, exec_unset },
+	{ "echo", 4, exec_echo },
+	{ "exit", 4, exec_exit },
+	{ "if", 2, exec_if },
+	{ "else", 4, exec_else },
+	{ "exec", 4, exec_exec },
+	{ "stdin", 5, exec_nop },
+	{ "stdout", 6, exec_nop },
+	{ "stderr", 6, exec_nop },
+};
+
+static void add_argument(struct argument *arg, const char *n)
+{
+	int allocs = arg->allocs, members = arg->members;
+
+	if (members+1 >= allocs) {
+		allocs = (allocs * 3) / 2 + 32;
+		arg->array = xrealloc(arg->array, allocs*sizeof(arg->array[0]));
+		arg->allocs = allocs;
+	}
+	arg->array[members++] = n;
+	arg->array[members] = NULL;
+	arg->members = members;
+}
+
+static int get_word(const char *line, const char **res)
+{
+	int quoted = 0;
+	int offset = 0;
+	int stop = 0;
+	char *buf;
+
+	for (;;) {
+		unsigned char c = line[offset];
+		if (!c)
+			break;
+		offset++;
+		if (c == '\\') {
+			quoted ^= 1;
+			continue;
+		}
+		if (quoted) {
+			quoted = 0;
+			continue;
+		}
+		if (stop) {
+			if (c == stop)
+				stop = 0;
+			continue;
+		}
+		if (c == '\'' || c == '"') {
+			stop = c;
+			continue;
+		}
+		if (!isspace(c)) {
+			continue;
+		}
+		offset--;
+		break;
+	}
+	if (quoted || stop)
+		return -1;
+	buf = xmalloc(offset+1);
+	memcpy(buf, line, offset);
+	buf[offset] = 0;
+	*res = buf;
+	return offset;
+}
+
+static int expand_word(const char *line, struct argument *arg)
+{
+	const char *word;
+	int offset = get_word(line, &word);
+
+	if (offset > 0)
+		add_argument(arg, word);
+	return offset;
+}
+
+static void convert_fd_into_array(struct variable *var)
+{
+	int fd = var->value.fd;
+	char buffer[8192];
+	int len, offset, last;
+
+	var->value.fd = -1;
+	var->value.type = var_array;
+	len = 0;
+	for (;;) {
+		int ret = read(fd, buffer + len, sizeof(buffer) - len);
+		if (!ret)
+			break;
+		if (ret < 0) {
+			if (errno == EINTR)
+				continue;
+			break;
+		}
+		len += ret;
+		if (len >= sizeof(buffer))
+			break;
+	}
+
+	last = 0;
+	for (offset = 0; offset < len; offset++) {
+		unsigned char c = buffer[offset];
+		if (c == '\n') {
+			buffer[offset] = 0;
+			add_argument(&var->value, buffer+last);
+			last = offset+1;
+			continue;
+		}
+	}		
+}
+
+static int expand_variable(const char *line, struct argument *arg)
+{
+	const char *word;
+	int offset = get_word(line+1, &word);
+
+	if (offset > 0) {
+		struct variable *var = find_variable(word);
+		offset++;	/* The '$' character itself */
+		if (var) {
+			int i;
+			if (var->value.type == var_fd)
+				convert_fd_into_array(var);
+			for (i = 0; i < var->value.members; i++)
+				add_argument(arg, var->value.array[i]);
+		}
+	}
+	return offset;
+}
+
+static int expand_value(const char *line, struct argument *arg)
+{
+	unsigned char c = *line;
+
+	switch (c) {
+	case '$':
+		return expand_variable(line, arg);
+	default:
+		return expand_word(line, arg);
+	}
+}
+
+static struct argument *expand_line(const char *line)
+{
+	struct argument *arg;
+
+	arg = xmalloc(sizeof(*arg));
+	memset(arg, 0, sizeof(*arg));
+	arg->type = var_array;
+	for (;;) {
+		int n;
+		while (isspace(*line)) {
+			line++;
+		}
+		if (!*line)
+			break;
+		n = expand_value(line, arg);
+		if (n <= 0)
+			break;
+		line += n;
+	}
+	return arg;
+}
+
+static void run_program(struct cmd_struct *cmd)
+{
+	while (cmd) {
+		int i;
+		const struct cmd_def *run = cmds+0;
+		struct argument *arg = NULL;
+		int cmdlen = strlen(cmd->line);
+
+		for (i = 1; i < sizeof(cmds)/sizeof(cmds[0]); i++) {
+			const struct cmd_def *def = cmds + i;
+			int len = def->len;
+			if (len > cmdlen)
+				continue;
+			if (len < cmdlen && !isspace(cmd->line[len]))
+				continue;
+			if (memcmp(cmd->line, def->n, len))
+				continue;
+			run = def;
+			arg = expand_line(cmd->line + len);
+			break;
+		}
+		cmd = run->exec(cmd, arg);
+	}
+}
+
+int execute(const char *name, char *buf, unsigned int size)
+{
+	struct parse_buf p;
+	struct cmd_struct *program;
+
+	p.name = name;
+	p.prog = buf;
+	p.size = size;
+	p.offset = 0;
+	p.line = 1;
+	p.error = "empty program";
+
+	program = parse(&p, -1);
+	if (!program || p.offset != p.size)
+		die("parse error at %s:%d: %s", p.name, p.line, p.error);
+
+	run_program(program);
+	return 0;
+}
diff --git a/script.c b/script.c
new file mode 100644
index 0000000..ae85598
--- /dev/null
+++ b/script.c
@@ -0,0 +1,58 @@
+/*
+ * Silly git script language
+ *
+ * Copyright (C) 2006, Linus Torvalds
+ */
+#include "cache.h"
+
+static const char script_usage[] = "git-script <scriptfile>";
+
+int main(int argc, char **argv)
+{
+	int fd;
+	char *buf;
+	const char *filename;
+	unsigned int size, alloc;
+
+	fd = 0;
+	switch (argc) {
+	case 1:
+		filename = "stdin";
+		fd = dup(0);
+		close(0);
+		open("/dev/null", O_RDONLY);
+		break;
+	case 2:
+		filename = argv[1];
+		fd = open(filename, O_RDONLY);
+		if (fd < 0)
+			die("unable to open '%s': %s", filename, strerror(errno));
+		break;
+	default:
+		usage(script_usage);
+	}
+
+	buf = NULL;
+	alloc = 0;
+	size = 0;
+	for (;;) {
+		int nr;
+		if (size >= alloc) {
+			alloc = (alloc * 3) / 2 + 8192;
+			buf = xrealloc(buf, alloc);
+		}
+		nr = read(fd, buf + size, alloc - size);
+		if (!nr)
+			break;
+		if (nr < 0) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			die("script read failed (%s)", strerror(errno));
+		}
+		size += nr;
+	}
+	close(fd);
+
+	execute(filename, buf, size);
+	return 0;
+}

^ permalink raw reply related	[relevance 6%]

* [PATCH] Use setenv(), fix warnings
@ 2006-02-26 15:13 15% Timo Hirvonen
  0 siblings, 0 replies; 200+ results
From: Timo Hirvonen @ 2006-02-26 15:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


  - Use setenv() instead of putenv()
  - Fix -Wundef -Wold-style-definition warnings
  - Make pll_free() static

Signed-off-by: Timo Hirvonen <tihirvon@gmail.com>

---

 cache.h          |    2 +-
 exec_cmd.c       |    2 +-
 fetch-pack.c     |    2 +-
 fsck-objects.c   |    4 ++--
 pack-objects.c   |    2 +-
 pack-redundant.c |    4 ++--
 path.c           |    2 +-
 7 files changed, 9 insertions(+), 9 deletions(-)

4001390d41ffd2c816cead47c256e598bedff452
diff --git a/cache.h b/cache.h
index 5020f07..58eec00 100644
--- a/cache.h
+++ b/cache.h
@@ -10,7 +10,7 @@
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
-#if defined(DT_UNKNOWN) && !NO_D_TYPE_IN_DIRENT
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
 #define DTYPE(de)	((de)->d_type)
 #else
 #undef DT_UNKNOWN
diff --git a/exec_cmd.c b/exec_cmd.c
index 55af33b..b5e59a9 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -13,7 +13,7 @@ void git_set_exec_path(const char *exec_
 
 
 /* Returns the highest-priority, location to look for git programs. */
-const char *git_exec_path()
+const char *git_exec_path(void)
 {
 	const char *env;
 
diff --git a/fetch-pack.c b/fetch-pack.c
index 09738fe..535de10 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -82,7 +82,7 @@ static void mark_common(struct commit *c
   Get the next rev to send, ignoring the common.
 */
 
-static const unsigned char* get_rev()
+static const unsigned char* get_rev(void)
 {
 	struct commit *commit = NULL;
 
diff --git a/fsck-objects.c b/fsck-objects.c
index 6439d55..f9c69f5 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -20,7 +20,7 @@ static int check_strict = 0;
 static int keep_cache_objects = 0; 
 static unsigned char head_sha1[20];
 
-#if NO_D_INO_IN_DIRENT
+#ifdef NO_D_INO_IN_DIRENT
 #define SORT_DIRENT 0
 #define DIRENT_SORT_HINT(de) 0
 #else
@@ -483,7 +483,7 @@ int main(int argc, char **argv)
 	if (standalone && check_full)
 		die("Only one of --standalone or --full can be used.");
 	if (standalone)
-		putenv("GIT_ALTERNATE_OBJECT_DIRECTORIES=");
+		setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", "", 1);
 
 	fsck_head_link();
 	fsck_object_dir(get_object_directory());
diff --git a/pack-objects.c b/pack-objects.c
index 0287449..21ee572 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -768,7 +768,7 @@ static int sha1_sort(const struct object
 	return memcmp(a->sha1, b->sha1, 20);
 }
 
-static struct object_entry **create_final_object_list()
+static struct object_entry **create_final_object_list(void)
 {
 	struct object_entry **list;
 	int i, j;
diff --git a/pack-redundant.c b/pack-redundant.c
index 1869b38..cd81f5a 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -45,7 +45,7 @@ static inline void llist_item_put(struct
 	free_nodes = item;
 }
 
-static inline struct llist_item *llist_item_get()
+static inline struct llist_item *llist_item_get(void)
 {
 	struct llist_item *new;
 	if ( free_nodes ) {
@@ -275,7 +275,7 @@ static void cmp_two_packs(struct pack_li
 	}
 }
 
-void pll_free(struct pll *l)
+static void pll_free(struct pll *l)
 {
 	struct pll *old;
 	struct pack_list *opl;
diff --git a/path.c b/path.c
index 334b2bd..6500a40 100644
--- a/path.c
+++ b/path.c
@@ -243,7 +243,7 @@ char *enter_repo(char *path, int strict)
 
 	if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
 	    validate_symref("HEAD") == 0) {
-		putenv("GIT_DIR=.");
+		setenv("GIT_DIR", ".", 1);
 		check_repository_format();
 		return path;
 	}
-- 
1.2.1

^ permalink raw reply related	[relevance 15%]

* [PATCH 2/3] apply --whitespace: configuration option.
  @ 2006-02-28  1:13 14%                     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-28  1:13 UTC (permalink / raw)
  To: git; +Cc: Andrew Morton

The new configuration option apply.whitespace can take one of
"warn", "error", "error-all", or "strip".  When git-apply is run
to apply the patch to the index, they are used as the default
value if there is no command line --whitespace option.

Andrew can now tell people who feed him git trees to update to
this version and say:

	git repo-config apply.whitespace error

Signed-off-by: Junio C Hamano <junkio@cox.net>

---
 * Already in "next".

 apply.c       |   72 ++++++++++++++++++++++++++++++++++++++-------------------
 cache.h       |    2 ++
 environment.c |    1 +
 3 files changed, 51 insertions(+), 24 deletions(-)

2ae1c53b51ff78b13cc8abf8e9798a12140b7638
diff --git a/apply.c b/apply.c
index 8139d83..a5cdd8e 100644
--- a/apply.c
+++ b/apply.c
@@ -35,16 +35,42 @@ static const char apply_usage[] =
 "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] <patch>...";
 
 static enum whitespace_eol {
-	nowarn,
+	nowarn_whitespace,
 	warn_on_whitespace,
 	error_on_whitespace,
-	strip_and_apply,
-} new_whitespace = nowarn;
+	strip_whitespace,
+} new_whitespace = nowarn_whitespace;
 static int whitespace_error = 0;
 static int squelch_whitespace_errors = 5;
 static int applied_after_stripping = 0;
 static const char *patch_input_file = NULL;
 
+static void parse_whitespace_option(const char *option)
+{
+	if (!option) {
+		new_whitespace = nowarn_whitespace;
+		return;
+	}
+	if (!strcmp(option, "warn")) {
+		new_whitespace = warn_on_whitespace;
+		return;
+	}
+	if (!strcmp(option, "error")) {
+		new_whitespace = error_on_whitespace;
+		return;
+	}
+	if (!strcmp(option, "error-all")) {
+		new_whitespace = error_on_whitespace;
+		squelch_whitespace_errors = 0;
+		return;
+	}
+	if (!strcmp(option, "strip")) {
+		new_whitespace = strip_whitespace;
+		return;
+	}
+	die("unrecognized whitespace option '%s'", option);
+}
+
 /*
  * For "diff-stat" like behaviour, we keep track of the biggest change
  * we've seen, and the longest filename. That allows us to do simple
@@ -832,7 +858,7 @@ static int parse_fragment(char *line, un
 			 * That is, an addition of an empty line would check
 			 * the '+' here.  Sneaky...
 			 */
-			if ((new_whitespace != nowarn) &&
+			if ((new_whitespace != nowarn_whitespace) &&
 			    isspace(line[len-2])) {
 				whitespace_error++;
 				if (squelch_whitespace_errors &&
@@ -1129,7 +1155,7 @@ static int apply_line(char *output, cons
 	 * patch[plen] is '\n'.
 	 */
 	int add_nl_to_tail = 0;
-	if ((new_whitespace == strip_and_apply) &&
+	if ((new_whitespace == strip_whitespace) &&
 	    1 < plen && isspace(patch[plen-1])) {
 		if (patch[plen] == '\n')
 			add_nl_to_tail = 1;
@@ -1824,10 +1850,21 @@ static int apply_patch(int fd, const cha
 	return 0;
 }
 
+static int git_apply_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "apply.whitespace")) {
+		apply_default_whitespace = strdup(value);
+		return 0;
+	}
+	return git_default_config(var, value);
+}
+
+
 int main(int argc, char **argv)
 {
 	int i;
 	int read_stdin = 1;
+	const char *whitespace_option = NULL;
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
@@ -1895,30 +1932,17 @@ int main(int argc, char **argv)
 			continue;
 		}
 		if (!strncmp(arg, "--whitespace=", 13)) {
-			if (!strcmp(arg+13, "warn")) {
-				new_whitespace = warn_on_whitespace;
-				continue;
-			}
-			if (!strcmp(arg+13, "error")) {
-				new_whitespace = error_on_whitespace;
-				continue;
-			}
-			if (!strcmp(arg+13, "error-all")) {
-				new_whitespace = error_on_whitespace;
-				squelch_whitespace_errors = 0;
-				continue;
-			}
-			if (!strcmp(arg+13, "strip")) {
-				new_whitespace = strip_and_apply;
-				continue;
-			}
-			die("unrecognized whitespace option '%s'", arg+13);
+			whitespace_option = arg + 13;
+			parse_whitespace_option(arg + 13);
+			continue;
 		}
 
 		if (check_index && prefix_length < 0) {
 			prefix = setup_git_directory();
 			prefix_length = prefix ? strlen(prefix) : 0;
-			git_config(git_default_config);
+			git_config(git_apply_config);
+			if (!whitespace_option && apply_default_whitespace)
+				parse_whitespace_option(apply_default_whitespace);
 		}
 		if (0 < prefix_length)
 			arg = prefix_filename(prefix, prefix_length, arg);
diff --git a/cache.h b/cache.h
index 58eec00..0d3b244 100644
--- a/cache.h
+++ b/cache.h
@@ -161,11 +161,13 @@ extern int hold_index_file_for_update(st
 extern int commit_index_file(struct cache_file *);
 extern void rollback_index_file(struct cache_file *);
 
+/* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
 extern int assume_unchanged;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 extern int shared_repository;
+extern const char *apply_default_whitespace;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
diff --git a/environment.c b/environment.c
index 251e53c..16c08f0 100644
--- a/environment.c
+++ b/environment.c
@@ -17,6 +17,7 @@ int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 int shared_repository = 0;
+const char *apply_default_whitespace = NULL;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
-- 
1.2.3.gbfea

^ permalink raw reply related	[relevance 14%]

* [PATCH 2/3] Introduce trivial new pager.c helper infrastructure
  @ 2006-02-28 19:26 16% ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-02-28 19:26 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This introduces the new function

	void setup_pager(void);

to set up output to be written through a pager applocation.

All in preparation for doing the simple scripts in C.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Ok, this should be pretty obvious, which is not to say that it shouldn't 
be improved (ie it only handles trivial definitions of PAGER). Any obvious 
improvements are left as an exercise for the reader, as not important for 
my current goal of actually having something working.


diff --git a/Makefile b/Makefile
index 3575489..0b1a998 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ LIB_OBJS = \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
-	fetch-clone.o revision.o \
+	fetch-clone.o revision.o pager.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/cache.h b/cache.h
index 58eec00..3af6b86 100644
--- a/cache.h
+++ b/cache.h
@@ -352,4 +352,7 @@ extern int copy_fd(int ifd, int ofd);
 extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
 extern int receive_keep_pack(int fd[2], const char *me, int quiet);
 
+/* pager.c */
+extern void setup_pager(void);
+
 #endif /* CACHE_H */
diff --git a/pager.c b/pager.c
new file mode 100644
index 0000000..1364e15
--- /dev/null
+++ b/pager.c
@@ -0,0 +1,48 @@
+#include "cache.h"
+
+/*
+ * This is split up from the rest of git so that we might do
+ * something different on Windows, for example.
+ */
+
+static void run_pager(void)
+{
+	const char *prog = getenv("PAGER");
+	if (!prog)
+		prog = "less";
+	setenv("LESS", "-S", 0);
+	execlp(prog, prog, NULL);
+}
+
+void setup_pager(void)
+{
+	pid_t pid;
+	int fd[2];
+
+	if (!isatty(1))
+		return;
+	if (pipe(fd) < 0)
+		return;
+	pid = fork();
+	if (pid < 0) {
+		close(fd[0]);
+		close(fd[1]);
+		return;
+	}
+
+	/* return in the child */
+	if (!pid) {
+		dup2(fd[1], 1);
+		close(fd[0]);
+		close(fd[1]);
+		return;
+	}
+
+	/* The original process turns into the PAGER */
+	dup2(fd[0], 0);
+	close(fd[0]);
+	close(fd[1]);
+
+	run_pager();
+	exit(255);
+}

^ permalink raw reply related	[relevance 16%]

* [PATCH] Teach git-checkout-index to use file suffixes.
@ 2006-03-01  4:41 12% Shawn Pearce
  0 siblings, 0 replies; 200+ results
From: Shawn Pearce @ 2006-03-01  4:41 UTC (permalink / raw)
  To: git

Sometimes it is useful to unpack the unmerged stage entries
to the same directory as the tracked file itself, but with
a suffix indicating which stage that version came from.
In many user interface level scripts this is being done
by git-unpack-file followed by creating the necessary
directory structure and then moving the file into the
directory with the requested name.  It is now possible to
perform the same action for a larger set of files directly
through git-checkout-index.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

---
 I think this completes the two features I've found missing from
 git-checkout-index:  --stdin and --suffix.  These two options
 should make writing a working directory based merge strategy
 a little easier.

 FYI: I built this on top of my immediately prior patch ('Teach
 git-checkout-index to read filenames from stdin.') so this one
 may not apply cleanly without that patch being applied first.

 Documentation/git-checkout-index.txt |   29 ++++++++++++++++++++++++++++-
 apply.c                              |    2 ++
 cache.h                              |    2 ++
 checkout-index.c                     |   14 ++++++++++++--
 entry.c                              |   10 +++++++---
 read-tree.c                          |    1 +
 6 files changed, 52 insertions(+), 6 deletions(-)

base df23c1119d0af1fbac6b8afd296113e155d9a878
last e1674dc0b01de5c34fada13f7cf5fcbb3be82d09
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index b0b6588..f0be2a0 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -9,7 +9,8 @@ git-checkout-index - Copy files from the
 SYNOPSIS
 --------
 [verse]
-'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
+'git-checkout-index' [-u] [-q] [-a] [-f] [-n]
+		   [--prefix=<string>] [--suffix=<string>]
 		   [--stage=<number>]
 		   [-z] [--stdin]
 		   [--] [<file>]\*
@@ -43,6 +44,10 @@ OPTIONS
 	When creating files, prepend <string> (usually a directory
 	including a trailing /)
 
+--suffix=<string>::
+	When creating files, append <string> to the name.  The value
+	of <string> must not contain a directory separator (/).
+
 --stage=<number>::
 	Instead of checking out unmerged entries, copy out the
 	files from named stage.  <number> must be between 1 and 3.
@@ -120,6 +125,28 @@ $ git-checkout-index --prefix=.merged- M
 This will check out the currently cached copy of `Makefile`
 into the file `.merged-Makefile`.
 
+Export files with a suffix::
++
+----------------
+$ git-checkout-index --suffix=\#2 --stage=2 Makefile
+----------------
++
+If `Makefile` is unmerged and has a stage 2 entry in the index
+this will check out that version into the file `Makefile#2`.
+
+A suffix may be preferred over a prefix when checking out all
+unmerged entries:
++
+----------------
+$ git-checkout-index --suffix=\#1 --stage=1 --all
+$ git-checkout-index --suffix=\#2 --stage=2 --all
+$ git-checkout-index --suffix=\#3 --stage=3 --all
+----------------
++
+would unpack all unmerged stages into the same directory as the
+tracked file.  (Compare with --prefix=.stage1/ which would have
+created a partial directory tree within `.stage1/`.)
+
 
 Author
 ------
diff --git a/apply.c b/apply.c
index 244718c..1ec8473 100644
--- a/apply.c
+++ b/apply.c
@@ -1307,6 +1307,8 @@ static int check_patch(struct patch *pat
 				/* checkout */
 				costate.base_dir = "";
 				costate.base_dir_len = 0;
+				costate.name_suffix = "";
+				costate.name_suffix_len = 0;
 				costate.force = 0;
 				costate.quiet = 0;
 				costate.not_new = 0;
diff --git a/cache.h b/cache.h
index 58eec00..055e213 100644
--- a/cache.h
+++ b/cache.h
@@ -254,6 +254,8 @@ extern const char *git_committer_info(in
 struct checkout {
 	const char *base_dir;
 	int base_dir_len;
+	const char *name_suffix;
+	int name_suffix_len;
 	unsigned force:1,
 		 quiet:1,
 		 not_new:1,
diff --git a/checkout-index.c b/checkout-index.c
index f54c606..af7b230 100644
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -47,6 +47,8 @@ static int checkout_stage; /* default to
 static struct checkout state = {
 	.base_dir = "",
 	.base_dir_len = 0,
+	.name_suffix = "",
+	.name_suffix_len = 0,
 	.force = 0,
 	.quiet = 0,
 	.not_new = 0,
@@ -180,6 +182,14 @@ int main(int argc, char **argv)
 			state.base_dir_len = strlen(state.base_dir);
 			continue;
 		}
+		if (!strncmp(arg, "--suffix=", 9)) {
+			if (strchr(arg+9, '/')) {
+				die("--suffix cannot contain /");
+			}
+			state.name_suffix = arg+9;
+			state.name_suffix_len = strlen(state.name_suffix);
+			continue;
+		}
 		if (!strncmp(arg, "--stage=", 8)) {
 			int ch = arg[8];
 			if ('1' <= ch && ch <= '3')
@@ -193,8 +203,8 @@ int main(int argc, char **argv)
 		break;
 	}
 
-	if (state.base_dir_len) {
-		/* when --prefix is specified we do not
+	if (state.base_dir_len || state.name_suffix_len) {
+		/* when --prefix or --suffix is specified we do not
 		 * want to update cache.
 		 */
 		if (state.refresh_cache) {
diff --git a/entry.c b/entry.c
index 8fb99bc..dc35a07 100644
--- a/entry.c
+++ b/entry.c
@@ -117,10 +117,14 @@ int checkout_entry(struct cache_entry *c
 {
 	struct stat st;
 	static char path[MAXPATHLEN+1];
-	int len = state->base_dir_len;
+	int len1 = state->base_dir_len;
+	int len2 = strlen(ce->name);
+	int len3 = state->name_suffix_len;
+	char *path_len1 = path + len1;
 
-	memcpy(path, state->base_dir, len);
-	strcpy(path + len, ce->name);
+	memcpy(path, state->base_dir, len1);
+	memcpy(path_len1, ce->name, len2 + 1);
+	memcpy(path_len1 + len2, state->name_suffix, len3 + 1);
 
 	if (!lstat(path, &st)) {
 		unsigned changed = ce_match_stat(ce, &st, 1);
diff --git a/read-tree.c b/read-tree.c
index f39fe5c..f223a0d 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -281,6 +281,7 @@ static void check_updates(struct cache_e
 {
 	static struct checkout state = {
 		.base_dir = "",
+		.name_suffix = "",
 		.force = 1,
 		.quiet = 1,
 		.refresh_cache = 1,
-- 
1.2.3.gdf23c-dirty

^ permalink raw reply related	[relevance 12%]

* [PATCH] Add --temp and --stage=all options to checkout-index.
@ 2006-03-03  1:20  8% Shawn Pearce
    0 siblings, 1 reply; 200+ results
From: Shawn Pearce @ 2006-03-03  1:20 UTC (permalink / raw)
  To: git

Sometimes it is convient for a Porcelain to be able to checkout all
unmerged files in all stages so that an external merge tool can be
executed by the Porcelain or the end-user.  Using git-unpack-file
on each stage individually incurs a rather high penalty due to the
need to fork for each file version obtained.  git-checkout-index -a
--stage=all will now do the same thing, but faster.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

---
 This spawned out of the discussion of my prior --suffix patch
 and replaces it entirely.

 The output format is Junio's idea, which I happened to like a lot.
 I think I have faithfully implemented it here, but added a case
 where you can obtain temporary files for only a specific stage
 without needing to read the 'wider' 3-stage format.

 Unfortunately this change lead me down a path which changed the core
 checkout code also used by apply and read-tree.  So those commands
 could now checkout to temporary files if they wanted to.  :-)

 It currently passes all test cases, including the new one provided
 by this patch.

 Documentation/git-checkout-index.txt |   51 ++++++++
 apply.c                              |    3 
 cache.h                              |    5 -
 checkout-index.c                     |   84 ++++++++++++-
 entry.c                              |   92 +++++++++------
 read-tree.c                          |    3 
 t/t2004-checkout-cache-temp.sh       |  212 ++++++++++++++++++++++++++++++++++
 7 files changed, 396 insertions(+), 54 deletions(-)
 create mode 100755 t/t2004-checkout-cache-temp.sh

base c6b84bc40310f8e0cf2fe290b5f291e31cf688ef
last 022659f9b239fd5513a883e09ac0e0688b69dbe1
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index b0b6588..09bd6a5 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -10,7 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
-		   [--stage=<number>]
+		   [--stage=<number>|all]
+		   [--temp]
 		   [-z] [--stdin]
 		   [--] [<file>]\*
 
@@ -43,9 +44,15 @@ OPTIONS
 	When creating files, prepend <string> (usually a directory
 	including a trailing /)
 
---stage=<number>::
+--stage=<number>|all::
 	Instead of checking out unmerged entries, copy out the
 	files from named stage.  <number> must be between 1 and 3.
+	Note: --stage=all automatically implies --temp.
+
+--temp::
+	Instead of copying the files to the working directory
+	write the content to temporary files.  The temporary name
+	associations will be written to stdout.
 
 --stdin::
 	Instead of taking list of paths from the command line,
@@ -87,6 +94,46 @@ it will prevent problems with a filename
 Using `--` is probably a good policy in scripts.
 
 
+Using --temp or --stage=all
+---------------------------
+When `--temp` is used (or implied by `--stage=all`)
+`git-checkout-index` will create a temporary file for each index
+entry being checked out.  The index will not be updated with stat
+information.  These options can be useful if the caller needs all
+stages of all unmerged entries so that the unmerged files can be
+processed by an external merge tool.
+
+A listing will be written to stdout providing the association of
+temporary file names to tracked path names.  The listing format
+has two variations:
+
+    . tempname TAB path RS
++
+The first format is what gets used when `--stage` is omitted or
+is not `--stage=all`. The field tempname is the temporary file
+name holding the file content and path is the tracked path name in
+the index.  Only the requested entries are output.
+
+    . stage1temp SP stage2temp SP stage3tmp TAB path RS
++
+The second format is what gets used when `--stage=all`.  The three
+stage temporary fields (stage1temp, stage2temp, stage3temp) list the
+name of the temporary file if there is a stage entry in the index
+or `.` if there is no stage entry.  Paths which only have a stage 0
+entry will always be omitted from the output.
+
+In both formats RS (the record separator) is newline by default
+but will be the null byte if -z was passed on the command line.
+The temporary file names are always safe strings; they will never
+contain directory separators or whitespace characters.  The path
+field is always relative to the current directory and the temporary
+file names are always relative to the top level directory.
+
+If the object being copied out to a temporary file is a symbolic
+link the content of the link will be written to a normal file.  It is
+up to the end-user or the Porcelain to make use of this information.
+
+
 EXAMPLES
 --------
 To update and refresh only the files already checked out::
diff --git a/apply.c b/apply.c
index c369966..5583a80 100644
--- a/apply.c
+++ b/apply.c
@@ -1376,6 +1376,7 @@ static int apply_data(struct patch *patc
 static int check_patch(struct patch *patch)
 {
 	struct stat st;
+	static char topath[MAXPATHLEN+1];
 	const char *old_name = patch->old_name;
 	const char *new_name = patch->new_name;
 	const char *name = old_name ? old_name : new_name;
@@ -1402,7 +1403,7 @@ static int check_patch(struct patch *pat
 				costate.not_new = 0;
 				costate.refresh_cache = 1;
 				if (checkout_entry(active_cache[pos],
-						   &costate) ||
+						   &costate, topath) ||
 				    lstat(old_name, &st))
 					return -1;
 			}
diff --git a/cache.h b/cache.h
index 0d3b244..f87744c 100644
--- a/cache.h
+++ b/cache.h
@@ -259,10 +259,11 @@ struct checkout {
 	unsigned force:1,
 		 quiet:1,
 		 not_new:1,
-		 refresh_cache:1;
+		 refresh_cache:1,
+		 to_tempfile:1;
 };
 
-extern int checkout_entry(struct cache_entry *ce, struct checkout *state);
+extern int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath);
 
 extern struct alternate_object_database {
 	struct alternate_object_database *next;
diff --git a/checkout-index.c b/checkout-index.c
index f54c606..24845c3 100644
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -40,9 +40,12 @@
 #include "strbuf.h"
 #include "quote.h"
 
+#define CHECKOUT_ALL 4
 static const char *prefix;
 static int prefix_length;
+static int line_termination = '\n';
 static int checkout_stage; /* default to checkout stage0 */
+static char topath[4][MAXPATHLEN+1];
 
 static struct checkout state = {
 	.base_dir = "",
@@ -51,13 +54,42 @@ static struct checkout state = {
 	.quiet = 0,
 	.not_new = 0,
 	.refresh_cache = 0,
+	.to_tempfile = 0,
 };
 
+static void write_tempfile_record (const char *name)
+{
+	int i;
+
+	if (CHECKOUT_ALL == checkout_stage) {
+		for (i = 1; i < 4; i++) {
+			if (i > 1)
+				putchar(' ');
+			if (topath[i][0])
+				fputs(topath[i], stdout);
+			else
+				putchar('.');
+		}
+	} else
+		fputs(topath[checkout_stage], stdout);
+
+	putchar('\t');
+	write_name_quoted("", 0, name + prefix_length,
+		line_termination, stdout);
+	putchar(line_termination);
+
+	for (i = 0; i < 4; i++) {
+		topath[i][0] = 0;
+	}
+}
+
 static int checkout_file(const char *name)
 {
 	int namelen = strlen(name);
 	int pos = cache_name_pos(name, namelen);
 	int has_same_name = 0;
+	int did_checkout = 0;
+	int errs = 0;
 
 	if (pos < 0)
 		pos = -pos - 1;
@@ -68,9 +100,19 @@ static int checkout_file(const char *nam
 		    memcmp(ce->name, name, namelen))
 			break;
 		has_same_name = 1;
-		if (checkout_stage == ce_stage(ce))
-			return checkout_entry(ce, &state);
 		pos++;
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
+			continue;
+		did_checkout = 1;
+		if (checkout_entry(ce, &state, topath[ce_stage(ce)]) < 0)
+			errs++;
+	}
+
+	if (did_checkout) {
+		if (state.to_tempfile)
+			write_tempfile_record(name);
+		return errs > 0 ? -1 : 0;
 	}
 
 	if (!state.quiet) {
@@ -90,18 +132,28 @@ static int checkout_file(const char *nam
 static int checkout_all(void)
 {
 	int i, errs = 0;
+	struct cache_entry* last_ce = 0;
 
 	for (i = 0; i < active_nr ; i++) {
 		struct cache_entry *ce = active_cache[i];
-		if (ce_stage(ce) != checkout_stage)
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
 			continue;
 		if (prefix && *prefix &&
 		    (ce_namelen(ce) <= prefix_length ||
 		     memcmp(prefix, ce->name, prefix_length)))
 			continue;
-		if (checkout_entry(ce, &state) < 0)
+		if (last_ce && state.to_tempfile) {
+			if (ce_namelen(last_ce) != ce_namelen(ce)
+			    || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
+				write_tempfile_record(last_ce->name);
+		}
+		if (checkout_entry(ce, &state, topath[ce_stage(ce)]) < 0)
 			errs++;
+		last_ce = ce;
 	}
+	if (last_ce && state.to_tempfile)
+		write_tempfile_record(last_ce->name);
 	if (errs)
 		/* we have already done our error reporting.
 		 * exit with the same code as die().
@@ -111,7 +163,7 @@ static int checkout_all(void)
 }
 
 static const char checkout_cache_usage[] =
-"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]] [--prefix=<string>] [--] <file>...";
+"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=<string>] [--temp] [--] <file>...";
 
 static struct cache_file cache_file;
 
@@ -121,7 +173,6 @@ int main(int argc, char **argv)
 	int newfd = -1;
 	int all = 0;
 	int read_from_stdin = 0;
-	int line_termination = '\n';
 
 	prefix = setup_git_directory();
 	git_config(git_default_config);
@@ -175,17 +226,26 @@ int main(int argc, char **argv)
 			i++; /* do not consider arg as a file name */
 			break;
 		}
+		if (!strcmp(arg, "--temp")) {
+			state.to_tempfile = 1;
+			continue;
+		}
 		if (!strncmp(arg, "--prefix=", 9)) {
 			state.base_dir = arg+9;
 			state.base_dir_len = strlen(state.base_dir);
 			continue;
 		}
 		if (!strncmp(arg, "--stage=", 8)) {
-			int ch = arg[8];
-			if ('1' <= ch && ch <= '3')
-				checkout_stage = arg[8] - '0';
-			else
-				die("stage should be between 1 and 3");
+			if (!strcmp(arg + 8, "all")) {
+				state.to_tempfile = 1;
+				checkout_stage = CHECKOUT_ALL;
+			} else {
+				int ch = arg[8];
+				if ('1' <= ch && ch <= '3')
+					checkout_stage = arg[8] - '0';
+				else
+					die("stage should be between 1 and 3 or all");
+			}
 			continue;
 		}
 		if (arg[0] == '-')
@@ -193,7 +253,7 @@ int main(int argc, char **argv)
 		break;
 	}
 
-	if (state.base_dir_len) {
+	if (state.base_dir_len || state.to_tempfile) {
 		/* when --prefix is specified we do not
 		 * want to update cache.
 		 */
diff --git a/entry.c b/entry.c
index 8fb99bc..c33a35d 100644
--- a/entry.c
+++ b/entry.c
@@ -63,7 +63,7 @@ static int create_file(const char *path,
 	return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
 }
 
-static int write_entry(struct cache_entry *ce, const char *path, struct checkout *state)
+static int write_entry(struct cache_entry *ce, char *path, struct checkout *state)
 {
 	int fd;
 	void *new;
@@ -80,7 +80,11 @@ static int write_entry(struct cache_entr
 	}
 	switch (ntohl(ce->ce_mode) & S_IFMT) {
 	case S_IFREG:
-		fd = create_file(path, ntohl(ce->ce_mode));
+		if (state->to_tempfile) {
+			strcpy(path, ".merge_file_XXXXXX");
+			fd = mkstemp(path);
+		} else 
+			fd = create_file(path, ntohl(ce->ce_mode));
 		if (fd < 0) {
 			free(new);
 			return error("git-checkout-index: unable to create file %s (%s)",
@@ -93,12 +97,27 @@ static int write_entry(struct cache_entr
 			return error("git-checkout-index: unable to write file %s", path);
 		break;
 	case S_IFLNK:
-		if (symlink(new, path)) {
+		if (state->to_tempfile) {
+			strcpy(path, ".merge_link_XXXXXX");
+			fd = mkstemp(path);
+			if (fd < 0) {
+				free(new);
+				return error("git-checkout-index: unable to create "
+						 "file %s (%s)", path, strerror(errno));
+			}
+			wrote = write(fd, new, size);
+			close(fd);
 			free(new);
-			return error("git-checkout-index: unable to create "
-				     "symlink %s (%s)", path, strerror(errno));
+			if (wrote != size)
+				return error("git-checkout-index: unable to write file %s",
+					path);
+		} else {
+			wrote = symlink(new, path);
+			free(new);
+			if (wrote)
+				return error("git-checkout-index: unable to create "
+						 "symlink %s (%s)", path, strerror(errno));
 		}
-		free(new);
 		break;
 	default:
 		free(new);
@@ -113,41 +132,42 @@ static int write_entry(struct cache_entr
 	return 0;
 }
 
-int checkout_entry(struct cache_entry *ce, struct checkout *state)
+int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
 {
 	struct stat st;
-	static char path[MAXPATHLEN+1];
 	int len = state->base_dir_len;
 
-	memcpy(path, state->base_dir, len);
-	strcpy(path + len, ce->name);
-
-	if (!lstat(path, &st)) {
-		unsigned changed = ce_match_stat(ce, &st, 1);
-		if (!changed)
+	if (!state->to_tempfile) {
+		memcpy(topath, state->base_dir, len);
+		strcpy(topath + len, ce->name);
+
+		if (!lstat(topath, &st)) {
+			unsigned changed = ce_match_stat(ce, &st, 1);
+			if (!changed)
+				return 0;
+			if (!state->force) {
+				if (!state->quiet)
+					fprintf(stderr, "git-checkout-index: %s already exists\n", topath);
+				return -1;
+			}
+
+			/*
+			 * We unlink the old file, to get the new one with the
+			 * right permissions (including umask, which is nasty
+			 * to emulate by hand - much easier to let the system
+			 * just do the right thing)
+			 */
+			unlink(topath);
+			if (S_ISDIR(st.st_mode)) {
+				if (!state->force)
+					return error("%s is a directory", topath);
+				remove_subtree(topath);
+			}
+		} else if (state->not_new) 
 			return 0;
-		if (!state->force) {
-			if (!state->quiet)
-				fprintf(stderr, "git-checkout-index: %s already exists\n", path);
-			return -1;
-		}
-
-		/*
-		 * We unlink the old file, to get the new one with the
-		 * right permissions (including umask, which is nasty
-		 * to emulate by hand - much easier to let the system
-		 * just do the right thing)
-		 */
-		unlink(path);
-		if (S_ISDIR(st.st_mode)) {
-			if (!state->force)
-				return error("%s is a directory", path);
-			remove_subtree(path);
-		}
-	} else if (state->not_new) 
-		return 0;
-	create_directories(path, state);
-	return write_entry(ce, path, state);
+		create_directories(topath, state);
+	}
+	return write_entry(ce, topath, state);
 }
 
 
diff --git a/read-tree.c b/read-tree.c
index be29b3f..e88d69e 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -279,6 +279,7 @@ static void progress_interval(int signum
 
 static void check_updates(struct cache_entry **src, int nr)
 {
+	static char topath[MAXPATHLEN+1];
 	static struct checkout state = {
 		.base_dir = "",
 		.force = 1,
@@ -337,7 +338,7 @@ static void check_updates(struct cache_e
 		if (ce->ce_flags & mask) {
 			ce->ce_flags &= ~mask;
 			if (update)
-				checkout_entry(ce, &state);
+				checkout_entry(ce, &state, topath);
 		}
 	}
 	if (total) {
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
new file mode 100755
index 0000000..c100959
--- /dev/null
+++ b/t/t2004-checkout-cache-temp.sh
@@ -0,0 +1,212 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Shawn Pearce
+#
+
+test_description='git-checkout-index --temp test.
+
+With --temp flag, git-checkout-index writes to temporary merge files
+rather than the tracked path.'
+
+. ./test-lib.sh
+
+test_expect_success \
+'preparation' '
+mkdir asubdir &&
+echo tree1path0 >path0 &&
+echo tree1path1 >path1 &&
+echo tree1path3 >path3 &&
+echo tree1path4 >path4 &&
+echo tree1asubdir/path5 >asubdir/path5 &&
+git-update-index --add path0 path1 path3 path4 asubdir/path5 &&
+t1=$(git-write-tree) &&
+rm -f path* .merge_* out .git/index &&
+echo tree2path0 >path0 &&
+echo tree2path1 >path1 &&
+echo tree2path2 >path2 &&
+echo tree2path4 >path4 &&
+git-update-index --add path0 path1 path2 path4 &&
+t2=$(git-write-tree) &&
+rm -f path* .merge_* out .git/index &&
+echo tree2path0 >path0 &&
+echo tree3path1 >path1 &&
+echo tree3path2 >path2 &&
+echo tree3path3 >path3 &&
+git-update-index --add path0 path1 path2 path3 &&
+t3=$(git-write-tree)'
+
+test_expect_success \
+'checkout one stage 0 to temporary file' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree $t1 &&
+git-checkout-index --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = tree1path1'
+
+test_expect_success \
+'checkout all stage 0 to temporary files' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree $t1 &&
+git-checkout-index -a --temp >out &&
+test $(wc -l <out) = 5 &&
+for f in path0 path1 path3 path4 asubdir/path5
+do
+	test $(grep $f out | cut "-d	" -f2) = $f &&
+	p=$(grep $f out | cut "-d	" -f1) &&
+	test -f $p &&
+	test $(cat $p) = tree1$f
+done'
+
+test_expect_success \
+'prepare 3-way merge' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree -m $t1 $t2 $t3'
+
+test_expect_success \
+'checkout one stage 2 to temporary file' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=2 --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = tree2path1'
+
+test_expect_success \
+'checkout all stage 2 to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --all --stage=2 --temp >out &&
+test $(wc -l <out) = 3 &&
+for f in path1 path2 path4
+do
+	test $(grep $f out | cut "-d	" -f2) = $f &&
+	p=$(grep $f out | cut "-d	" -f1) &&
+	test -f $p &&
+	test $(cat $p) = tree2$f
+done'
+
+test_expect_success \
+'checkout all stages/one file to nothing' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path0 >out &&
+test $(wc -l <out) = 0'
+
+test_expect_success \
+'checkout all stages/one file to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+cut "-d	" -f1 out | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s1) = tree1path1 &&
+test $(cat $s2) = tree2path1 &&
+test $(cat $s3) = tree3path1)'
+
+test_expect_success \
+'checkout some stages/one file to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path2 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path2 &&
+cut "-d	" -f1 out | (read s1 s2 s3 &&
+test $s1 = . &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s2) = tree2path2 &&
+test $(cat $s3) = tree3path2)'
+
+test_expect_success \
+'checkout all stages/all files to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index -a --stage=all --temp >out &&
+test $(wc -l <out) = 5'
+
+test_expect_success \
+'-- path0: no entry' '
+test x$(grep path0 out | cut "-d	" -f2) = x'
+
+test_expect_success \
+'-- path1: all 3 stages' '
+test $(grep path1 out | cut "-d	" -f2) = path1 &&
+grep path1 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s1) = tree1path1 &&
+test $(cat $s2) = tree2path1 &&
+test $(cat $s3) = tree3path1)'
+
+test_expect_success \
+'-- path2: no stage 1, have stage 2 and 3' '
+test $(grep path2 out | cut "-d	" -f2) = path2 &&
+grep path2 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test $s1 = . &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s2) = tree2path2 &&
+test $(cat $s3) = tree3path2)'
+
+test_expect_success \
+'-- path3: no stage 2, have stage 1 and 3' '
+test $(grep path3 out | cut "-d	" -f2) = path3 &&
+grep path3 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test $s2 = . &&
+test -f $s3 &&
+test $(cat $s1) = tree1path3 &&
+test $(cat $s3) = tree3path3)'
+
+test_expect_success \
+'-- path4: no stage 3, have stage 1 and 3' '
+test $(grep path4 out | cut "-d	" -f2) = path4 &&
+grep path4 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test $s3 = . &&
+test $(cat $s1) = tree1path4 &&
+test $(cat $s2) = tree2path4)'
+
+test_expect_success \
+'-- asubdir/path5: no stage 2 and 3 have stage 1' '
+test $(grep asubdir/path5 out | cut "-d	" -f2) = asubdir/path5 &&
+grep asubdir/path5 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test $s2 = . &&
+test $s3 = . &&
+test $(cat $s1) = tree1asubdir/path5)'
+
+test_expect_success \
+'checkout --temp within subdir' '
+(cd asubdir &&
+ git-checkout-index -a --stage=all >out &&
+ test $(wc -l <out) = 1 &&
+ test $(grep path5 out | cut "-d	" -f2) = path5 &&
+ grep path5 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+ test -f ../$s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat ../$s1) = tree1asubdir/path5)
+)'
+
+test_expect_success \
+'checkout --temp symlink' '
+rm -f path* .merge_* out .git/index &&
+ln -s b a &&
+git-update-index --add a &&
+t4=$(git-write-tree) &&
+rm -f .git/index &&
+git-read-tree $t4 &&
+git-checkout-index --temp -a >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = a &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = b'
+
+test_done
-- 
1.2.3.g5f0e

^ permalink raw reply related	[relevance 8%]

* [PATCH] send-email: accept --no-signed-off-by-cc as the documentation states
@ 2006-03-03  9:28 49% Eric Wong
  0 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-03  9:28 UTC (permalink / raw)
  To: junkio, ryan; +Cc: git, Eric Wong

--no-signed-off-cc is still supported, for backwards compatibility

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

374f3e5c7fd49c4949df9b29ed03287e6ceb2e2c
diff --git a/git-send-email.perl b/git-send-email.perl
index b0d095b..7c8d512 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -54,7 +54,7 @@ my $rc = GetOptions("from=s" => \$from,
 		    "compose" => \$compose,
 		    "quiet" => \$quiet,
 		    "suppress-from" => \$suppress_from,
-		    "no-signed-off-cc" => \$no_signed_off_cc,
+		    "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
 	 );
 
 # Now, let's fill any that aren't set in with defaults:
-- 
1.2.3.g4676

^ permalink raw reply related	[relevance 49%]

* Re: [PATCH] Add --temp and --stage=all options to checkout-index.
  @ 2006-03-05  8:24  8%       ` Shawn Pearce
  0 siblings, 0 replies; 200+ results
From: Shawn Pearce @ 2006-03-05  8:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Sometimes it is convient for a Porcelain to be able to checkout all
unmerged files in all stages so that an external merge tool can be
executed by the Porcelain or the end-user.  Using git-unpack-file
on each stage individually incurs a rather high penalty due to the
need to fork for each file version obtained.  git-checkout-index -a
--stage=all will now do the same thing, but faster.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

---
This replaces my prior patch.  It looks a heck of a lot cleaner too
due to less indentation changes.  :-)

Junio C Hamano <junkio@cox.net> wrote:
> Shawn Pearce <spearce@spearce.org> writes:
> 
> > Junio C Hamano <junkio@cox.net> wrote:
> >> Shawn Pearce <spearce@spearce.org> writes:
> >> 
> >> >  Unfortunately this change lead me down a path which changed the core
> >> >  checkout code also used by apply and read-tree.
> >> 
> 
> I would have preferred not to add to_tempfile member to the
> checkout struct.  Instead, if checkout_entry has non NULL
> topath, check out to a temporary location and return the path;
> otherwise behave the way it did before.

Good idea.

> I am unsure about what the tempfile option should do when asked
> to checkout a symbolic link.  Creating a temporary regular file
> that has the readlink result does not sound very useful to me.

I couldn't decide either here; but there's no `mkstemplink'
or some-such function to generate a temporary symbolic link.
With the target in a temp file a Porcelain can at least generate
a true symbolic link with the correct target or present it the
different versions to the user for resolution.  Symlinks are
definately difficult.

> BTW, in any case, I think there is one breakage that needs to be
> fixed with something like this...

That should be fixed with this version of the patch.  Good catch.

 Documentation/git-checkout-index.txt |   51 ++++++++
 apply.c                              |    3 
 cache.h                              |    2 
 checkout-index.c                     |   86 ++++++++++++--
 entry.c                              |   40 +++++-
 read-tree.c                          |    2 
 t/t2004-checkout-cache-temp.sh       |  212 ++++++++++++++++++++++++++++++++++
 7 files changed, 370 insertions(+), 26 deletions(-)
 create mode 100755 t/t2004-checkout-cache-temp.sh

base 1c7fee5d0857d809fe5d93a1d56968e44296ce55
last aa1305c3181ac1a3a493765bf41c2d59f8b8ce3e
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index b0b6588..09bd6a5 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -10,7 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
-		   [--stage=<number>]
+		   [--stage=<number>|all]
+		   [--temp]
 		   [-z] [--stdin]
 		   [--] [<file>]\*
 
@@ -43,9 +44,15 @@ OPTIONS
 	When creating files, prepend <string> (usually a directory
 	including a trailing /)
 
---stage=<number>::
+--stage=<number>|all::
 	Instead of checking out unmerged entries, copy out the
 	files from named stage.  <number> must be between 1 and 3.
+	Note: --stage=all automatically implies --temp.
+
+--temp::
+	Instead of copying the files to the working directory
+	write the content to temporary files.  The temporary name
+	associations will be written to stdout.
 
 --stdin::
 	Instead of taking list of paths from the command line,
@@ -87,6 +94,46 @@ it will prevent problems with a filename
 Using `--` is probably a good policy in scripts.
 
 
+Using --temp or --stage=all
+---------------------------
+When `--temp` is used (or implied by `--stage=all`)
+`git-checkout-index` will create a temporary file for each index
+entry being checked out.  The index will not be updated with stat
+information.  These options can be useful if the caller needs all
+stages of all unmerged entries so that the unmerged files can be
+processed by an external merge tool.
+
+A listing will be written to stdout providing the association of
+temporary file names to tracked path names.  The listing format
+has two variations:
+
+    . tempname TAB path RS
++
+The first format is what gets used when `--stage` is omitted or
+is not `--stage=all`. The field tempname is the temporary file
+name holding the file content and path is the tracked path name in
+the index.  Only the requested entries are output.
+
+    . stage1temp SP stage2temp SP stage3tmp TAB path RS
++
+The second format is what gets used when `--stage=all`.  The three
+stage temporary fields (stage1temp, stage2temp, stage3temp) list the
+name of the temporary file if there is a stage entry in the index
+or `.` if there is no stage entry.  Paths which only have a stage 0
+entry will always be omitted from the output.
+
+In both formats RS (the record separator) is newline by default
+but will be the null byte if -z was passed on the command line.
+The temporary file names are always safe strings; they will never
+contain directory separators or whitespace characters.  The path
+field is always relative to the current directory and the temporary
+file names are always relative to the top level directory.
+
+If the object being copied out to a temporary file is a symbolic
+link the content of the link will be written to a normal file.  It is
+up to the end-user or the Porcelain to make use of this information.
+
+
 EXAMPLES
 --------
 To update and refresh only the files already checked out::
diff --git a/apply.c b/apply.c
index c369966..849a8b4 100644
--- a/apply.c
+++ b/apply.c
@@ -1402,7 +1402,8 @@ static int check_patch(struct patch *pat
 				costate.not_new = 0;
 				costate.refresh_cache = 1;
 				if (checkout_entry(active_cache[pos],
-						   &costate) ||
+						   &costate,
+						   NULL) ||
 				    lstat(old_name, &st))
 					return -1;
 			}
diff --git a/cache.h b/cache.h
index 8dc1de1..1f96280 100644
--- a/cache.h
+++ b/cache.h
@@ -262,7 +262,7 @@ struct checkout {
 		 refresh_cache:1;
 };
 
-extern int checkout_entry(struct cache_entry *ce, struct checkout *state);
+extern int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath);
 
 extern struct alternate_object_database {
 	struct alternate_object_database *next;
diff --git a/checkout-index.c b/checkout-index.c
index f54c606..7b78715 100644
--- a/checkout-index.c
+++ b/checkout-index.c
@@ -40,9 +40,13 @@
 #include "strbuf.h"
 #include "quote.h"
 
+#define CHECKOUT_ALL 4
 static const char *prefix;
 static int prefix_length;
+static int line_termination = '\n';
 static int checkout_stage; /* default to checkout stage0 */
+static int to_tempfile;
+static char topath[4][MAXPATHLEN+1];
 
 static struct checkout state = {
 	.base_dir = "",
@@ -53,11 +57,39 @@ static struct checkout state = {
 	.refresh_cache = 0,
 };
 
+static void write_tempfile_record (const char *name)
+{
+	int i;
+
+	if (CHECKOUT_ALL == checkout_stage) {
+		for (i = 1; i < 4; i++) {
+			if (i > 1)
+				putchar(' ');
+			if (topath[i][0])
+				fputs(topath[i], stdout);
+			else
+				putchar('.');
+		}
+	} else
+		fputs(topath[checkout_stage], stdout);
+
+	putchar('\t');
+	write_name_quoted("", 0, name + prefix_length,
+		line_termination, stdout);
+	putchar(line_termination);
+
+	for (i = 0; i < 4; i++) {
+		topath[i][0] = 0;
+	}
+}
+
 static int checkout_file(const char *name)
 {
 	int namelen = strlen(name);
 	int pos = cache_name_pos(name, namelen);
 	int has_same_name = 0;
+	int did_checkout = 0;
+	int errs = 0;
 
 	if (pos < 0)
 		pos = -pos - 1;
@@ -68,9 +100,20 @@ static int checkout_file(const char *nam
 		    memcmp(ce->name, name, namelen))
 			break;
 		has_same_name = 1;
-		if (checkout_stage == ce_stage(ce))
-			return checkout_entry(ce, &state);
 		pos++;
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
+			continue;
+		did_checkout = 1;
+		if (checkout_entry(ce, &state,
+		    to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
+			errs++;
+	}
+
+	if (did_checkout) {
+		if (to_tempfile)
+			write_tempfile_record(name);
+		return errs > 0 ? -1 : 0;
 	}
 
 	if (!state.quiet) {
@@ -90,18 +133,29 @@ static int checkout_file(const char *nam
 static int checkout_all(void)
 {
 	int i, errs = 0;
+	struct cache_entry* last_ce = 0;
 
 	for (i = 0; i < active_nr ; i++) {
 		struct cache_entry *ce = active_cache[i];
-		if (ce_stage(ce) != checkout_stage)
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
 			continue;
 		if (prefix && *prefix &&
 		    (ce_namelen(ce) <= prefix_length ||
 		     memcmp(prefix, ce->name, prefix_length)))
 			continue;
-		if (checkout_entry(ce, &state) < 0)
+		if (last_ce && to_tempfile) {
+			if (ce_namelen(last_ce) != ce_namelen(ce)
+			    || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
+				write_tempfile_record(last_ce->name);
+		}
+		if (checkout_entry(ce, &state,
+		    to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
 			errs++;
+		last_ce = ce;
 	}
+	if (last_ce && to_tempfile)
+		write_tempfile_record(last_ce->name);
 	if (errs)
 		/* we have already done our error reporting.
 		 * exit with the same code as die().
@@ -111,7 +165,7 @@ static int checkout_all(void)
 }
 
 static const char checkout_cache_usage[] =
-"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]] [--prefix=<string>] [--] <file>...";
+"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=<string>] [--temp] [--] <file>...";
 
 static struct cache_file cache_file;
 
@@ -121,7 +175,6 @@ int main(int argc, char **argv)
 	int newfd = -1;
 	int all = 0;
 	int read_from_stdin = 0;
-	int line_termination = '\n';
 
 	prefix = setup_git_directory();
 	git_config(git_default_config);
@@ -175,17 +228,26 @@ int main(int argc, char **argv)
 			i++; /* do not consider arg as a file name */
 			break;
 		}
+		if (!strcmp(arg, "--temp")) {
+			to_tempfile = 1;
+			continue;
+		}
 		if (!strncmp(arg, "--prefix=", 9)) {
 			state.base_dir = arg+9;
 			state.base_dir_len = strlen(state.base_dir);
 			continue;
 		}
 		if (!strncmp(arg, "--stage=", 8)) {
-			int ch = arg[8];
-			if ('1' <= ch && ch <= '3')
-				checkout_stage = arg[8] - '0';
-			else
-				die("stage should be between 1 and 3");
+			if (!strcmp(arg + 8, "all")) {
+				to_tempfile = 1;
+				checkout_stage = CHECKOUT_ALL;
+			} else {
+				int ch = arg[8];
+				if ('1' <= ch && ch <= '3')
+					checkout_stage = arg[8] - '0';
+				else
+					die("stage should be between 1 and 3 or all");
+			}
 			continue;
 		}
 		if (arg[0] == '-')
@@ -193,7 +255,7 @@ int main(int argc, char **argv)
 		break;
 	}
 
-	if (state.base_dir_len) {
+	if (state.base_dir_len || to_tempfile) {
 		/* when --prefix is specified we do not
 		 * want to update cache.
 		 */
diff --git a/entry.c b/entry.c
index 8fb99bc..38b5241 100644
--- a/entry.c
+++ b/entry.c
@@ -63,7 +63,7 @@ static int create_file(const char *path,
 	return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
 }
 
-static int write_entry(struct cache_entry *ce, const char *path, struct checkout *state)
+static int write_entry(struct cache_entry *ce, char *path, struct checkout *state, int to_tempfile)
 {
 	int fd;
 	void *new;
@@ -80,7 +80,11 @@ static int write_entry(struct cache_entr
 	}
 	switch (ntohl(ce->ce_mode) & S_IFMT) {
 	case S_IFREG:
-		fd = create_file(path, ntohl(ce->ce_mode));
+		if (to_tempfile) {
+			strcpy(path, ".merge_file_XXXXXX");
+			fd = mkstemp(path);
+		} else 
+			fd = create_file(path, ntohl(ce->ce_mode));
 		if (fd < 0) {
 			free(new);
 			return error("git-checkout-index: unable to create file %s (%s)",
@@ -93,12 +97,27 @@ static int write_entry(struct cache_entr
 			return error("git-checkout-index: unable to write file %s", path);
 		break;
 	case S_IFLNK:
-		if (symlink(new, path)) {
+		if (to_tempfile) {
+			strcpy(path, ".merge_link_XXXXXX");
+			fd = mkstemp(path);
+			if (fd < 0) {
+				free(new);
+				return error("git-checkout-index: unable to create "
+						 "file %s (%s)", path, strerror(errno));
+			}
+			wrote = write(fd, new, size);
+			close(fd);
 			free(new);
-			return error("git-checkout-index: unable to create "
-				     "symlink %s (%s)", path, strerror(errno));
+			if (wrote != size)
+				return error("git-checkout-index: unable to write file %s",
+					path);
+		} else {
+			wrote = symlink(new, path);
+			free(new);
+			if (wrote)
+				return error("git-checkout-index: unable to create "
+						 "symlink %s (%s)", path, strerror(errno));
 		}
-		free(new);
 		break;
 	default:
 		free(new);
@@ -113,12 +132,15 @@ static int write_entry(struct cache_entr
 	return 0;
 }
 
-int checkout_entry(struct cache_entry *ce, struct checkout *state)
+int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
 {
-	struct stat st;
 	static char path[MAXPATHLEN+1];
+	struct stat st;
 	int len = state->base_dir_len;
 
+	if (topath)
+		return write_entry(ce, topath, state, 1);
+
 	memcpy(path, state->base_dir, len);
 	strcpy(path + len, ce->name);
 
@@ -147,7 +169,7 @@ int checkout_entry(struct cache_entry *c
 	} else if (state->not_new) 
 		return 0;
 	create_directories(path, state);
-	return write_entry(ce, path, state);
+	return write_entry(ce, path, state, 0);
 }
 
 
diff --git a/read-tree.c b/read-tree.c
index be29b3f..1c3b09b 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -337,7 +337,7 @@ static void check_updates(struct cache_e
 		if (ce->ce_flags & mask) {
 			ce->ce_flags &= ~mask;
 			if (update)
-				checkout_entry(ce, &state);
+				checkout_entry(ce, &state, NULL);
 		}
 	}
 	if (total) {
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
new file mode 100755
index 0000000..c100959
--- /dev/null
+++ b/t/t2004-checkout-cache-temp.sh
@@ -0,0 +1,212 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Shawn Pearce
+#
+
+test_description='git-checkout-index --temp test.
+
+With --temp flag, git-checkout-index writes to temporary merge files
+rather than the tracked path.'
+
+. ./test-lib.sh
+
+test_expect_success \
+'preparation' '
+mkdir asubdir &&
+echo tree1path0 >path0 &&
+echo tree1path1 >path1 &&
+echo tree1path3 >path3 &&
+echo tree1path4 >path4 &&
+echo tree1asubdir/path5 >asubdir/path5 &&
+git-update-index --add path0 path1 path3 path4 asubdir/path5 &&
+t1=$(git-write-tree) &&
+rm -f path* .merge_* out .git/index &&
+echo tree2path0 >path0 &&
+echo tree2path1 >path1 &&
+echo tree2path2 >path2 &&
+echo tree2path4 >path4 &&
+git-update-index --add path0 path1 path2 path4 &&
+t2=$(git-write-tree) &&
+rm -f path* .merge_* out .git/index &&
+echo tree2path0 >path0 &&
+echo tree3path1 >path1 &&
+echo tree3path2 >path2 &&
+echo tree3path3 >path3 &&
+git-update-index --add path0 path1 path2 path3 &&
+t3=$(git-write-tree)'
+
+test_expect_success \
+'checkout one stage 0 to temporary file' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree $t1 &&
+git-checkout-index --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = tree1path1'
+
+test_expect_success \
+'checkout all stage 0 to temporary files' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree $t1 &&
+git-checkout-index -a --temp >out &&
+test $(wc -l <out) = 5 &&
+for f in path0 path1 path3 path4 asubdir/path5
+do
+	test $(grep $f out | cut "-d	" -f2) = $f &&
+	p=$(grep $f out | cut "-d	" -f1) &&
+	test -f $p &&
+	test $(cat $p) = tree1$f
+done'
+
+test_expect_success \
+'prepare 3-way merge' '
+rm -f path* .merge_* out .git/index &&
+git-read-tree -m $t1 $t2 $t3'
+
+test_expect_success \
+'checkout one stage 2 to temporary file' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=2 --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = tree2path1'
+
+test_expect_success \
+'checkout all stage 2 to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --all --stage=2 --temp >out &&
+test $(wc -l <out) = 3 &&
+for f in path1 path2 path4
+do
+	test $(grep $f out | cut "-d	" -f2) = $f &&
+	p=$(grep $f out | cut "-d	" -f1) &&
+	test -f $p &&
+	test $(cat $p) = tree2$f
+done'
+
+test_expect_success \
+'checkout all stages/one file to nothing' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path0 >out &&
+test $(wc -l <out) = 0'
+
+test_expect_success \
+'checkout all stages/one file to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path1 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path1 &&
+cut "-d	" -f1 out | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s1) = tree1path1 &&
+test $(cat $s2) = tree2path1 &&
+test $(cat $s3) = tree3path1)'
+
+test_expect_success \
+'checkout some stages/one file to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index --stage=all --temp -- path2 >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = path2 &&
+cut "-d	" -f1 out | (read s1 s2 s3 &&
+test $s1 = . &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s2) = tree2path2 &&
+test $(cat $s3) = tree3path2)'
+
+test_expect_success \
+'checkout all stages/all files to temporary files' '
+rm -f path* .merge_* out &&
+git-checkout-index -a --stage=all --temp >out &&
+test $(wc -l <out) = 5'
+
+test_expect_success \
+'-- path0: no entry' '
+test x$(grep path0 out | cut "-d	" -f2) = x'
+
+test_expect_success \
+'-- path1: all 3 stages' '
+test $(grep path1 out | cut "-d	" -f2) = path1 &&
+grep path1 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s1) = tree1path1 &&
+test $(cat $s2) = tree2path1 &&
+test $(cat $s3) = tree3path1)'
+
+test_expect_success \
+'-- path2: no stage 1, have stage 2 and 3' '
+test $(grep path2 out | cut "-d	" -f2) = path2 &&
+grep path2 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test $s1 = . &&
+test -f $s2 &&
+test -f $s3 &&
+test $(cat $s2) = tree2path2 &&
+test $(cat $s3) = tree3path2)'
+
+test_expect_success \
+'-- path3: no stage 2, have stage 1 and 3' '
+test $(grep path3 out | cut "-d	" -f2) = path3 &&
+grep path3 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test $s2 = . &&
+test -f $s3 &&
+test $(cat $s1) = tree1path3 &&
+test $(cat $s3) = tree3path3)'
+
+test_expect_success \
+'-- path4: no stage 3, have stage 1 and 3' '
+test $(grep path4 out | cut "-d	" -f2) = path4 &&
+grep path4 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test -f $s2 &&
+test $s3 = . &&
+test $(cat $s1) = tree1path4 &&
+test $(cat $s2) = tree2path4)'
+
+test_expect_success \
+'-- asubdir/path5: no stage 2 and 3 have stage 1' '
+test $(grep asubdir/path5 out | cut "-d	" -f2) = asubdir/path5 &&
+grep asubdir/path5 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+test -f $s1 &&
+test $s2 = . &&
+test $s3 = . &&
+test $(cat $s1) = tree1asubdir/path5)'
+
+test_expect_success \
+'checkout --temp within subdir' '
+(cd asubdir &&
+ git-checkout-index -a --stage=all >out &&
+ test $(wc -l <out) = 1 &&
+ test $(grep path5 out | cut "-d	" -f2) = path5 &&
+ grep path5 out | cut "-d	" -f1 | (read s1 s2 s3 &&
+ test -f ../$s1 &&
+ test $s2 = . &&
+ test $s3 = . &&
+ test $(cat ../$s1) = tree1asubdir/path5)
+)'
+
+test_expect_success \
+'checkout --temp symlink' '
+rm -f path* .merge_* out .git/index &&
+ln -s b a &&
+git-update-index --add a &&
+t4=$(git-write-tree) &&
+rm -f .git/index &&
+git-read-tree $t4 &&
+git-checkout-index --temp -a >out &&
+test $(wc -l <out) = 1 &&
+test $(cut "-d	" -f2 out) = a &&
+p=$(cut "-d	" -f1 out) &&
+test -f $p &&
+test $(cat $p) = b'
+
+test_done
-- 
1.2.4.g0226

^ permalink raw reply related	[relevance 8%]

* Re: Fw: [PATCH 31/49] PCI: PCI/Cardbus cards hidden, needs pci=assign-busses to fix
  @ 2006-03-24  2:27 46%           ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-03-24  2:27 UTC (permalink / raw)
  To: greg; +Cc: git, Andrew Morton

Andrew Morton <akpm@osdl.org> writes:

> We wouldn't want to attempt to mix this concept up with email envelopes or
> email headers or anything like that.  The authorship is an attribute of the
> patch, and has nothing to do with how it was transported, stored or
> anything like that.

Fair enough.  This is the approach I called "the second best" in
my message but I am inclined to agree with you.

This was tested once by sending myself two patches.

-- >8 --
[PATCH] send-email: Identify author at the top when sending e-mail

git-send-email was not checking if the sender is the same as the
patch author.  Follow the "From: at the beginning" convention to
propagate the patch author correctly.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/git-send-email.perl b/git-send-email.perl
index 7c8d512..b220d11 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -307,6 +307,7 @@ $subject = $initial_subject;
 foreach my $t (@files) {
 	open(F,"<",$t) or die "can't open file $t";
 
+	my $author_not_sender = undef;
 	@cc = @initial_cc;
 	my $found_mbox = 0;
 	my $header_done = 0;
@@ -321,7 +322,12 @@ foreach my $t (@files) {
 					$subject = $1;
 
 				} elsif (/^(Cc|From):\s+(.*)$/) {
-					next if ($2 eq $from && $suppress_from);
+					if ($2 eq $from) {
+						next if ($suppress_from);
+					}
+					else {
+						$author_not_sender = $2;
+					}
 					printf("(mbox) Adding cc: %s from line '%s'\n",
 						$2, $_) unless $quiet;
 					push @cc, $2;
@@ -360,6 +366,9 @@ foreach my $t (@files) {
 		}
 	}
 	close F;
+	if (defined $author_not_sender) {
+		$message = "From: $author_not_sender\n\n$message";
+	}
 
 	$cc = join(", ", unique_email_list(@cc));
 

^ permalink raw reply related	[relevance 46%]

* [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP
  @ 2006-03-25 10:43 40% ` Eric Wong
  2006-03-25 10:43 49% ` [PATCH 2/4] send-email: use built-in time() instead of /bin/date '+%s' Eric Wong
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-25 10:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ryan Anderson, Greg KH, Eric Wong

Net::SMTP is in the base Perl distribution, so users are more
likely to have it.  Net::SMTP also allows reusing the SMTP
connection, so sending multiple emails is faster.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |   66 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 41 insertions(+), 25 deletions(-)

7155ae6e5f94a8fdf55f50029af27279dd36fd0a
diff --git a/git-send-email.perl b/git-send-email.perl
index b220d11..efaf457 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -19,11 +19,17 @@
 use strict;
 use warnings;
 use Term::ReadLine;
-use Mail::Sendmail qw(sendmail %mailcfg);
 use Getopt::Long;
 use Data::Dumper;
+use Net::SMTP;
 use Email::Valid;
 
+# most mail servers generate the Date: header, but not all...
+$ENV{LC_ALL} = 'C';
+use POSIX qw/strftime/;
+
+my $smtp;
+
 sub unique_email_list(@);
 sub cleanup_compose_files();
 
@@ -271,35 +277,45 @@ $cc = "";
 
 sub send_message
 {
-	my $to = join (", ", unique_email_list(@to));
-
-	%mail = (	To	=>	$to,
-			From	=>	$from,
-			CC	=>	$cc,
-			Subject	=>	$subject,
-			Message	=>	$message,
-			'Reply-to'	=>	$from,
-			'In-Reply-To'	=>	$reply_to,
-			'Message-ID'	=>	$message_id,
-			'X-Mailer'	=>	"git-send-email",
-		);
-
-	$mail{smtp} = $smtp_server;
-	$mailcfg{mime} = 0;
-
-	#print Data::Dumper->Dump([\%mail],[qw(*mail)]);
-
-	sendmail(%mail) or die $Mail::Sendmail::error;
+	my @recipients = unique_email_list(@to);
+	my $to = join (",\n\t", @recipients);
+	@recipients = unique_email_list(@recipients,@cc);
+	my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time));
+
+	my $header = "From: $from
+To: $to
+Cc: $cc
+Subject: $subject
+Reply-To: $from
+Date: $date
+Message-Id: $message_id
+X-Mailer: git-send-email
+";
+	$header .= "In-Reply-To: $reply_to\n" if $reply_to;
+
+	$smtp ||= Net::SMTP->new( $smtp_server );
+	$smtp->mail( $from ) or die $smtp->message;
+	$smtp->to( @recipients ) or die $smtp->message;
+	$smtp->data or die $smtp->message;
+	$smtp->datasend("$header\n$message") or die $smtp->message;
+	$smtp->dataend() or die $smtp->message;
+	$smtp->ok or die "Failed to send $subject\n".$smtp->message;
 
 	if ($quiet) {
-		printf "Sent %s\n", $subject;
+		print "Sent $subject\n";
 	} else {
-		print "OK. Log says:\n", $Mail::Sendmail::log;
-		print "\n\n"
+		print "OK. Log says:
+Date: $date
+Server: $smtp_server Port: 25
+From: $from
+Subject: $subject
+Cc: $cc
+To: $to
+
+Result: ", $smtp->code, ' ', ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
 	}
 }
 
-
 $reply_to = $initial_reply_to;
 make_message_id();
 $subject = $initial_subject;
@@ -390,7 +406,7 @@ sub cleanup_compose_files() {
 
 }
 
-
+$smtp->quit if $smtp;
 
 sub unique_email_list(@) {
 	my %seen;
-- 
1.2.4.gb622a

^ permalink raw reply related	[relevance 40%]

* [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional
                     ` (2 preceding siblings ...)
  2006-03-25 10:43 43% ` [PATCH 4/4] send-email: add support for mutt aliases files Eric Wong
@ 2006-03-25 10:43 43% ` Eric Wong
  3 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-25 10:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ryan Anderson, Greg KH, Eric Wong

It's not installed on enough machines, and is overkill most of
the time.  We'll fallback to a very basic regexp (that is a
looser variant of what Email::Valid allows) just in case, but
nothing like the monster regexp Email::Valid has to offer :)

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

140eaf9b9d438ea489e6c72e2148feb3e355aea8
diff --git a/git-send-email.perl b/git-send-email.perl
index 5e08817..73bba19 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -22,12 +22,12 @@ use Term::ReadLine;
 use Getopt::Long;
 use Data::Dumper;
 use Net::SMTP;
-use Email::Valid;
 
 # most mail servers generate the Date: header, but not all...
 $ENV{LC_ALL} = 'C';
 use POSIX qw/strftime/;
 
+my $have_email_valid = eval { require Email::Valid or undef };
 my $smtp;
 
 sub unique_email_list(@);
@@ -250,6 +250,16 @@ EOT
 # Variables we set as part of the loop over files
 our ($message_id, $cc, %mail, $subject, $reply_to, $message);
 
+sub extract_valid_address {
+	my $address = shift;
+	if ($have_email_valid) {
+		return Email::Valid->address($address);
+	} else {
+		# less robust/correct than the monster regexp in Email::Valid,
+		# but still does a 99% job, and one less dependency
+		return ($address =~ /([^\"<>\s]+@[^<>\s]+)/);
+	}
+}
 
 # Usually don't need to change anything below here.
 
@@ -259,7 +269,7 @@ our ($message_id, $cc, %mail, $subject, 
 # 1 second since the last time we were called.
 
 # We'll setup a template for the message id, using the "from" address:
-my $message_id_from = Email::Valid->address($from);
+my $message_id_from = extract_valid_address($from);
 my $message_id_template = "<%s-git-send-email-$message_id_from>";
 
 sub make_message_id
@@ -412,7 +422,7 @@ sub unique_email_list(@) {
 	my @emails;
 
 	foreach my $entry (@_) {
-		my $clean = Email::Valid->address($entry);
+		my $clean = extract_valid_address($entry);
 		next if $seen{$clean}++;
 		push @emails, $entry;
 	}
-- 
1.2.4.gb622a

^ permalink raw reply related	[relevance 43%]

* [PATCH 2/4] send-email: use built-in time() instead of /bin/date '+%s'
    2006-03-25 10:43 40% ` [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP Eric Wong
@ 2006-03-25 10:43 49% ` Eric Wong
  2006-03-25 10:43 43% ` [PATCH 4/4] send-email: add support for mutt aliases files Eric Wong
  2006-03-25 10:43 43% ` [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional Eric Wong
  3 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-25 10:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ryan Anderson, Greg KH, Eric Wong

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

079ce058710240643369589448660620cd925f5c
diff --git a/git-send-email.perl b/git-send-email.perl
index efaf457..5e08817 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -264,8 +264,7 @@ my $message_id_template = "<%s-git-send-
 
 sub make_message_id
 {
-	my $date = `date "+\%s"`;
-	chomp($date);
+	my $date = time;
 	my $pseudo_rand = int (rand(4200));
 	$message_id = sprintf $message_id_template, "$date$pseudo_rand";
 	#print "new message id = $message_id\n"; # Was useful for debugging
-- 
1.2.4.gb622a

^ permalink raw reply related	[relevance 49%]

* [PATCH 4/4] send-email: add support for mutt aliases files
    2006-03-25 10:43 40% ` [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP Eric Wong
  2006-03-25 10:43 49% ` [PATCH 2/4] send-email: use built-in time() instead of /bin/date '+%s' Eric Wong
@ 2006-03-25 10:43 43% ` Eric Wong
  2006-03-25 10:43 43% ` [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional Eric Wong
  3 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-25 10:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ryan Anderson, Greg KH, Eric Wong

I got rid of the Email::Valid dependency since writing
RFC-correct email addresses is probably not a problem for most
users.

In my experience, misspelled usernames are a much bigger
problem.  I am prone to doing things like leaving out the 'k' in
Junio's email address and other things that Email::Valid can't
catch.

Since I use mutt and the aliases file is pretty simple, I've
added basic support for mutt alias files.

To setup git-send-email to use a mutt aliases file for a repo,
do this:

  git-repo-config sendemail.muttaliases <mutt_alias_file_path>

More email clients/address book formats can easily be supported
in the future.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

8bc65d178dd755ecd1f3c038b975b9bbe58c1015
diff --git a/git-send-email.perl b/git-send-email.perl
index 73bba19..207b1fb 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -89,6 +89,15 @@ sub gitvar_ident {
 my ($author) = gitvar_ident('GIT_AUTHOR_IDENT');
 my ($committer) = gitvar_ident('GIT_COMMITTER_IDENT');
 
+my %aliases;
+if (my $mutt_aliases = `git-repo-config sendemail.muttaliases`) {
+    chomp $mutt_aliases;
+    open my $ma, '<', $mutt_aliases or die "opening $mutt_aliases: $!\n";
+    while (<$ma>) { if (/^alias\s+(\S+)\s+(.*)/) { $aliases{$1} = $2 } }
+    close $ma;
+}
+# aliases for more mail clients can be supported here:
+
 my $prompting = 0;
 if (!defined $from) {
 	$from = $author || $committer;
@@ -112,6 +121,9 @@ if (!@to) {
 	$prompting++;
 }
 
+@to = map { $aliases{$_} || $_ } @to;
+@initial_cc = map { $aliases{$_} || $_ } @initial_cc;
+
 if (!defined $initial_subject && $compose) {
 	do {
 		$_ = $term->readline("What subject should the emails start with? ",
-- 
1.2.4.gb622a

^ permalink raw reply related	[relevance 43%]

* [PATCH] send-email: try to order messages in email clients more correctly
@ 2006-03-25 11:01 45% Eric Wong
  0 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-03-25 11:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Greg KH, Ryan Anderson, Eric Wong

If --no-chain-reply-to is set, patches may not always be ordered
correctly in email clients.  This patch makes sure each email
sent from a different second.

I chose to start with a time (slightly) in the past because
those are probably more likely in real-world usage and spam
filters might be more tolerant of them.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

695849a185ee8cfc8f3df0c737ff16a04cc84a5b
diff --git a/git-send-email.perl b/git-send-email.perl
index 207b1fb..de635ed 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -37,7 +37,7 @@ sub cleanup_compose_files();
 my $compose_filename = ".msg.$$";
 
 # Variables we fill in automatically, or via prompting:
-my (@to,@cc,@initial_cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
+my (@to,@cc,@initial_cc,$initial_reply_to,$initial_subject,@files,$from,$compose,$time);
 
 # Behavior modification variables
 my ($chain_reply_to, $smtp_server, $quiet, $suppress_from, $no_signed_off_cc) = (1, "localhost", 0, 0, 0);
@@ -295,13 +295,14 @@ sub make_message_id
 
 
 $cc = "";
+$time = time - scalar $#files;
 
 sub send_message
 {
 	my @recipients = unique_email_list(@to);
 	my $to = join (",\n\t", @recipients);
 	@recipients = unique_email_list(@recipients,@cc);
-	my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time));
+	my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime($time++));
 
 	my $header = "From: $from
 To: $to
-- 
1.2.4.gb622a

^ permalink raw reply related	[relevance 45%]

Results 1-200 of ~7000   | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2005-04-13 21:55     [PATCH] Clean up Makefile Daniel Barkalow
2005-04-13 22:00 13% ` [PATCH] Reorganize common code Daniel Barkalow
2005-04-14  0:19     [ANNOUNCE] git-pasky-0.4 Petr Baudis
2005-04-14 10:33 18% ` Russell King
2005-04-14  8:39     Merge with git-pasky II Junio C Hamano
2005-04-14  9:10     ` Linus Torvalds
2005-04-14 11:14       ` Junio C Hamano
2005-04-14 12:16         ` Petr Baudis
2005-04-14 18:12           ` Junio C Hamano
2005-04-14 18:36             ` Linus Torvalds
2005-04-14 19:59               ` Junio C Hamano
2005-04-15  0:42                 ` Linus Torvalds
2005-04-15 10:02                   ` David Woodhouse
2005-04-15 15:32                     ` Linus Torvalds
2005-04-16  1:44 10%                   ` Simon Fowler
2005-04-14 19:35             ` Petr Baudis
2005-04-14 23:12               ` Junio C Hamano
2005-04-14 23:31                 ` Petr Baudis
2005-04-15  0:58                   ` Junio C Hamano
2005-04-14 22:30                     ` Christopher Li
2005-04-15  7:43                       ` Junio C Hamano
2005-04-15  6:28                         ` Christopher Li
2005-04-15 11:11                           ` Junio C Hamano
     [not found]                             ` <7vaco0i3t9.fsf_-_@assigned-by-dhcp.cox.net>
2005-04-15 18:44                               ` write-tree is pasky-0.4 Linus Torvalds
2005-04-15 20:10                                 ` Junio C Hamano
2005-04-15 21:48                                   ` [PATCH 1/2] merge-trees script for Linus git Junio C Hamano
2005-04-15 23:33                                     ` [PATCH 3/2] " Junio C Hamano
2005-04-16  1:02                                       ` Linus Torvalds
2005-04-16  4:10                                         ` Junio C Hamano
2005-04-16  5:02                                           ` Linus Torvalds
2005-04-16  8:12                                             ` Junio C Hamano
2005-04-16  9:27 19%                                           ` [PATCH] Byteorder fix for read-tree, new -m semantics version Junio C Hamano
2005-04-17  7:07 20% active_cache leaks Brad Roberts
2005-04-17 10:52 19% [PATCH] use gcrypt instead of libssl for hash Junichi Uekawa
2005-04-17 17:52     ` Linus Torvalds
2005-04-18  3:58 19%   ` Edgar Toernig
2005-04-19  9:09 24% [PATCH 4/8] init-db.c: add INDEX_FILE_DIRECTORY support Zach Welch
2005-04-19 16:50     [PATCH] write-tree performance problems Chris Mason
2005-04-20  0:49     ` Chris Mason
2005-04-20  6:43       ` Linus Torvalds
2005-04-20 15:22 20%     ` Chris Mason
2005-04-20  4:32 18% [PATCH 1/3] add GIT_CACHE_DIRECTORY support Zach Welch
2005-04-20  4:32 22% [PATCH 2/3] rename object directory symbols Zach Welch
2005-04-20  4:32 19% [PATCH 3/3] rename SHA1_FILE_DIRECTORY Zach Welch
2005-04-20  6:08 19% [PATCH 1/4] Accept commit in some places when tree is needed Junio C Hamano
2005-04-20  6:35 19% ` (fixed) " Junio C Hamano
2005-04-20 15:32     ` Linus Torvalds
2005-04-21  0:19 12%   ` (rework) [PATCH 1/5] " Junio C Hamano
2005-04-21  5:06     Performance of various compressors Mike Taht
2005-04-21  5:14     ` Mike Taht
2005-04-21  5:22 22%   ` [PATCH] experimental - " Mike Taht
2005-04-21 15:13 22% [PATCH] multi item packed files Chris Mason
2005-04-22 20:32     ` Chris Mason
2005-04-22 23:55       ` Chris Mason
2005-04-25 22:20 16%     ` Chris Mason
2005-04-21 18:34 26% [PATCH 01/19] write_cache api signature change, isolate active_cache and active_nr inside read-cache.c Brad Roberts
2005-04-21 18:34 26% [PATCH 02/19] Add new api's to front the active_cache and active_nr cache internals Brad Roberts
2005-04-21 18:36 26% [PATCH 08/19] rename remove_entry_at to remove_cache_entry_at and expose as a public api Brad Roberts
2005-04-21 18:37 26% [PATCH 13/19] Remove active_cache, active_nr, and active_alloc from public view Brad Roberts
2005-04-21 18:38 26% [PATCH 14/19] move cache_header out of the " Brad Roberts
2005-04-21 18:38 20% [PATCH 15/19] introduce a cache struct and move the various cache globals into it Brad Roberts
2005-04-21 18:39 26% [PATCH 18/19] rename cache_match_stat to ce_match_stat to match other cache_entry related functions/macros Brad Roberts
2005-04-21 18:39 17% [PATCH 19/19] the end goal of the last dozen or so commits, there's no longer a global cache variable Brad Roberts
2005-04-21 18:39 15% [PATCH 01-19/19] All of the above combined Brad Roberts
2005-04-22  5:52 20% [PATCH] optimized SHA1 for powerpc Paul Mackerras
2005-04-23 18:27 13% [resend#2] [PATCH] Add -i option to cat-file to allow operation on displaced git object files Jon Seymour
2005-04-23 18:27 13% Jon Seymour
2005-04-23 18:48 17% ` [resend] " Jon Seymour
2005-04-24  0:03     [PATCH 0/5] Better merge-base, alternative transport programs Daniel Barkalow
2005-04-24  0:15 21% ` [PATCH 3/5] Additional functions for the objects database Daniel Barkalow
2005-04-26 15:12     [PATCH] check for malloc Christopher Li
2005-04-26 18:25     ` Linus Torvalds
2005-04-26 15:42 23%   ` [PATCH] introduce xmalloc and xrealloc Christopher Li
2005-04-28 19:15 16% [PATCH] Rename and extend read_tree_with_tree_or_commit_sha1 Junio C Hamano
2005-04-29 13:19 12% [PATCH]: first take at cleanup of #include, xmalloc / xrealloc, git status report usage Robert Sütterlin
2005-04-30  3:44     Trying to use AUTHOR_DATE Luck, Tony
2005-04-30  3:49     ` H. Peter Anvin
2005-04-30  4:02       ` Linus Torvalds
2005-04-30  4:22         ` Linus Torvalds
2005-04-30 10:53 12%       ` Edgar Toernig
2005-04-30 11:13             ` David Woodhouse
2005-04-30 12:49 11%           ` Edgar Toernig
2005-04-30 11:40 17% git compatibility patches Edgar Toernig
2005-05-01 21:49     [0/2] Complete http-pull Daniel Barkalow
2005-05-01 21:52 20% ` [1/2] Library support for refs/ Daniel Barkalow
2005-05-03  1:30 17% [PATCH] delta compressed git Chris Mason
2005-05-03  3:57     RFC: adding xdelta compression to git Alon Ziv
2005-05-03  4:52     ` Linus Torvalds
2005-05-03  8:06       ` [PATCH] add the ability to create and retrieve delta objects Nicolas Pitre
2005-05-04 15:56 17%     ` Chris Mason
2005-05-03 18:33     git and symlinks as tracked content Kay Sievers
2005-05-03 19:02     ` Linus Torvalds
2005-05-04 22:35       ` Kay Sievers
2005-05-04 23:16         ` Junio C Hamano
2005-05-05  1:20 19%       ` Kay Sievers
2005-05-05  2:13             ` Junio C Hamano
2005-05-05 12:38 19%           ` Kay Sievers
2005-05-03 19:15     Careful object writing Linus Torvalds
2005-05-04  4:07 18% ` [PATCH] Careful object pulling Daniel Barkalow
2005-05-06 23:33 19% [PATCH] Remove unused sha1_file_directory variable Junio C Hamano
2005-05-06 23:35 13% [PATCH] Introduce SHA1_FILE_DIRECTORIES Junio C Hamano
2005-05-07  0:20     ` Sean
2005-05-07  0:24       ` Junio C Hamano
2005-05-07  0:32         ` Sean
2005-05-07  6:31           ` Junio C Hamano
2005-05-07 19:51 16%         ` Junio C Hamano
2005-05-09 13:33               ` H. Peter Anvin
2005-05-09 16:38                 ` Junio C Hamano
2005-05-09 16:41                   ` Sean
2005-05-09 18:03                     ` H. Peter Anvin
2005-05-09 18:50                       ` Junio C Hamano
2005-05-09 20:05  9%                     ` [RFC] Renaming environment variables Junio C Hamano
2005-05-10  0:38     Daniel Barkalow
2005-05-10  5:45     ` Junio C Hamano
2005-05-10  6:25 11%   ` Introducing GIT_DIR environment variable Junio C Hamano
2005-05-12  7:48 16% [PATCH] Support symlinks in git-ls-files --others Junio C Hamano
2005-05-13  0:16 18% [PATCH 2/3] " Junio C Hamano
2005-05-13  6:49     [PATCH 0/4] Pulling refs files Daniel Barkalow
2005-05-13  6:53 19% ` [PATCH 1/4] Support for refs directory Daniel Barkalow
2005-05-14  6:19     speeding up cg-log -u Zack Brown
2005-05-14  8:13 15% ` Junio C Hamano
2005-05-14 21:44 13% git-rev-list in local commit order Sean
2005-05-15  8:36 19% [PATCH] Implement git-checkout-cache -u to update stat information in the cache Junio C Hamano
     [not found]     <Pine.LNX.4.44.0505141851340.2136-200000@bellevue.puremagic.com>
2005-05-15  9:11  9% ` Darcs-git: a few notes for Git hackers Brad Roberts
2005-05-15 21:23 19% [PATCH 3/4] Implement git-checkout-cache -u to update stat information in the cache Junio C Hamano
2005-05-17 22:57 11% [PATCH] packed delta git Chris Mason
2005-05-18 12:14 19% [PATCH] Kill a bunch of pointer sign warnings for gcc4 Brian Gerst
2005-05-19 22:01 19% [PATCH] Remove gitenv macro hack Dan Weber
2005-05-21  9:13 19% [PATCH] Adding limits.h to cache.h in order to compile under Solaris Thomas Glanzmann
     [not found]     <7vy89ums2l.fsf@assigned-by-dhcp.cox.net>
2005-06-01 18:38     ` [PATCH] diff: mode bits fixes Junio C Hamano
2005-06-02 16:46 13%   ` [PATCH] Handle deltified object correctly in git-*-pull family Junio C Hamano
2005-06-02 17:03         ` Linus Torvalds
2005-06-02 18:55 12%       ` Junio C Hamano
2005-06-02 21:31             ` Nicolas Pitre
2005-06-02 21:36               ` Nicolas Pitre
2005-06-02 22:19 13%             ` [PATCH 1/2] " Junio C Hamano
2005-06-02 22:20 14%             ` [PATCH 2/2] Find size of SHA1 object without inflating everything Junio C Hamano
2005-06-02 18:57 14%       ` [PATCH] " Junio C Hamano
2005-06-02 16:49 14%   ` Junio C Hamano
2005-06-03 15:05 17% [PATCH] Anal retentive 'const unsigned char *sha1' Jason McMullan
2005-06-03 15:08 15% [PATCH] Expose more sha1_file.c interfaces Jason McMullan
2005-06-06 20:27     [PATCH 0/4] Writing refs in git-ssh-push Daniel Barkalow
2005-06-06 20:31 18% ` [PATCH 1/4] Operations on refs Daniel Barkalow
2005-06-23 23:20     [PATCH 0/2] D/F conflicts fixes Junio C Hamano
2005-06-24 23:40 13% ` [PATCH 2/2] Fix oversimplified optimization for add_cache_entry() Junio C Hamano
2005-06-25  0:57       ` Linus Torvalds
2005-06-25  2:40         ` Junio C Hamano
2005-06-25  9:16           ` [PATCH 0/9] " Junio C Hamano
2005-06-25  9:25 15%         ` [PATCH 7/9] " Junio C Hamano
2005-06-25  4:20     kernel.org and GIT tree rebuilding David S. Miller
2005-06-25  4:40     ` Jeff Garzik
2005-06-25  5:23       ` Linus Torvalds
2005-06-25  5:48         ` Jeff Garzik
2005-06-25  6:16           ` Linus Torvalds
2005-06-26 16:41             ` Linus Torvalds
2005-06-28 18:06               ` Nicolas Pitre
2005-06-28 19:28                 ` Linus Torvalds
2005-06-28 21:08                   ` Nicolas Pitre
2005-06-28 21:27                     ` Linus Torvalds
2005-06-29  3:55                       ` Nicolas Pitre
2005-06-29  5:16                         ` Nicolas Pitre
2005-06-29  5:43                           ` Linus Torvalds
2005-06-29  5:54                             ` Linus Torvalds
2005-06-29  7:16                               ` Last mile for 1.0 again Junio C Hamano
2005-06-29  9:51 12%                             ` [PATCH] Add git-verify-pack command Junio C Hamano
2005-06-28  1:14     CAREFUL! No more delta object support! Linus Torvalds
2005-06-28  2:01     ` Junio C Hamano
2005-06-28  2:03 17%   ` [PATCH] Skip writing out sha1 files for objects in packed git Junio C Hamano
2005-06-28  8:49     ` [PATCH] Adjust fsck-cache to packed GIT and alternate object pool Junio C Hamano
2005-06-28 21:56 14%   ` [PATCH] Expose packed_git and alt_odb Junio C Hamano
2005-07-01  0:15 13% [PATCH 1/2] verify-pack updates Junio C Hamano
2005-07-01  0:17 14% [PATCH 2/2] Show more details of packfile with verify-pack -v Junio C Hamano
2005-07-03 23:46     [ANNOUNCE] Cogito-0.12 Petr Baudis
2005-07-06 12:01     ` Brian Gerst
2005-07-07 14:45       ` Petr Baudis
2005-07-07 17:21         ` Junio C Hamano
2005-07-07 19:04           ` Linus Torvalds
2005-07-07 22:14             ` Petr Baudis
2005-07-07 22:52               ` Linus Torvalds
2005-07-07 23:16  9%             ` [PATCH] Pull efficiently from a dumb git store Junio C Hamano
2005-07-06  6:52     [PATCH] sha1_file.c;prepare_packed_git_one() - fix DIR leak Junio C Hamano
2005-07-06  8:11 17% ` [PATCH] clone-pack.c:write_one_ref() - Create leading directories Junio C Hamano
2005-07-08 10:37     patches to support working without the object database Bryan Larsen
2005-07-08 18:36 14% ` Junio C Hamano
2005-07-08 10:54 18% [PATCH] 2/7 Prepare for the next two patches Bryan Larsen
2005-07-10 19:53     [PATCH 0/2] Support for packs in HTTP Daniel Barkalow
2005-07-10 19:55 19% ` [PATCH 1/2] Management of packs not yet installed Daniel Barkalow
2005-07-10 22:22     [PATCH 0/2] Handing sending objects from packs Daniel Barkalow
2005-07-10 22:25 20% ` [PATCH 1/2] write_sha1_to_fd() Daniel Barkalow
2005-07-10 22:27 22% ` [PATCH 2/2] Remove map_sha1_file Daniel Barkalow
2005-07-11  1:18     Trial git RPM's Linus Torvalds
2005-07-11 15:24     ` Eric W. Biederman
2005-07-11 17:06       ` Linus Torvalds
2005-07-12  0:55         ` Eric W. Biederman
2005-07-12  1:15           ` Linus Torvalds
2005-07-12  4:39  8%         ` [PATCH] tagger id Eric W. Biederman
2005-07-15  0:50 18% [PATCH 1/6] Move git_author_info and git_commiter_info to ident.c Eric W. Biederman
2005-07-24  0:54 12% [PATCH 4/6] Add update-server-info Junio C Hamano
2005-07-26 18:57     Linux BKCVS kernel history git import Linus Torvalds
2005-07-27  9:40     ` David Woodhouse
2005-07-27 15:29       ` Linus Torvalds
2005-07-27 15:41         ` David Woodhouse
2005-07-27 15:50           ` Linus Torvalds
2005-07-30  8:00 13%         ` [PATCH] Teach parse_commit_buffer about grafting Junio C Hamano
2005-07-31 20:09     [PATCH 0/2] Support pack files in http-pull barkalow
2005-07-31 20:10 12% ` [PATCH 1/2] Functions for managing the set of packs the library is using barkalow
2005-08-01  0:53 12% ` [PATCH 1/2] Functions for managing the set of packs the library is using (whitespace fixed) barkalow
2005-08-02 23:10     Users of git-check-files? Johannes Schindelin
2005-08-03 16:45     ` Linus Torvalds
2005-08-03 16:50       ` Johannes Schindelin
2005-08-03 17:08         ` Josef Weidendorfer
2005-08-03 18:08           ` Linus Torvalds
2005-08-03 23:25  8%         ` [PATCH] (preview) Renaming push Junio C Hamano
2005-08-02 23:45     [PATCH 0/3] Parallel pull for SSH barkalow
2005-08-02 23:46 14% ` [PATCH 3/3] Parallelize pulling by ssh barkalow
2005-08-03  6:23 11% [PATCH] Install sample hooks Junio C Hamano
2005-08-04 20:43 18% [PATCH 1/1] git: add git_mkstemp() Holger Eitzenberger
2005-08-09 15:30 21% [PATCH] -Werror fixes Timo Sirainen
2005-08-13  9:09 14% [PATCH] Alternate object pool mechanism updates Junio C Hamano
2005-08-16  4:09     [PATCH 0/2] Fix local-pull on packed repository Daniel Barkalow
2005-08-16  4:10 18% ` [PATCH] Add function to read an index file from an arbitrary filename Daniel Barkalow
2005-08-16 22:45 15% [RFC PATCH] Add support for figuring out where in the git archive we are Linus Torvalds
2005-08-16 23:40     ` Junio C Hamano
2005-08-17  0:01       ` Linus Torvalds
2005-08-17  0:16         ` Junio C Hamano
2005-08-17  1:06 13%       ` Linus Torvalds
2005-08-17 20:31 19% [PATCH 1/2] Export relative path handling "prefix_path()" function Linus Torvalds
2005-08-19  4:10 19% [PATCH] Spell __attribute__ correctly in cache.h Jason Riedy
2005-08-19  9:04 19% ` Junio C Hamano
2005-09-02 12:17 17% [PATCH] Possible cleanups for local-pull.c Peter Hagervall
2005-09-12 14:55     [PATCH 00/22] cache cursors: an introduction Chuck Lever
2005-09-12 14:55 16% ` [PATCH 01/22] introduce facility to walk through the active cache Chuck Lever
2005-09-12 14:56 18% ` [PATCH 12/22] simplify write_cache() calling sequence Chuck Lever
2005-09-12 14:56 20% ` [PATCH 13/22] move purge_cache() to read-cache.c Chuck Lever
2005-09-12 14:56 20% ` [PATCH 14/22] move read_cache_unmerged into read-cache.c Chuck Lever
2005-09-12 14:56 19% ` [PATCH 15/22] replace cache_name_pos Chuck Lever
2005-09-12 14:56 13% ` [PATCH 22/22] teach read-cache.c to use cache_find_name() Chuck Lever
2005-09-12 18:23 18% Add note about IANA confirmation Linus Torvalds
2005-09-13 21:07     dumb transports not being welcomed Junio C Hamano
2005-09-13 21:14     ` Sam Ravnborg
2005-09-13 21:30       ` Junio C Hamano
2005-09-13 22:11         ` Junio C Hamano
2005-09-14 10:45 19%       ` Sven Verdoolaege
2005-09-16 12:37  9% [PATCH/RFC] Build a shared / renamed / "stable" version of the library? Matthias Urlichs
2005-09-19 22:53 16% Return proper error valud from "parse_date()" Linus Torvalds
2005-09-23 13:33     git 0.99.7b doesn't build on Cygwin Peter TB Brett
2005-09-23 13:44     ` Johannes Schindelin
2005-09-24  0:09       ` Linus Torvalds
2005-09-24  1:13         ` Johannes Schindelin
2005-09-24  2:46           ` Linus Torvalds
2005-09-24  5:26             ` Davide Libenzi
2005-09-24 18:10               ` Linus Torvalds
2005-09-24 19:12                 ` Davide Libenzi
2005-09-24 20:31                   ` Junio C Hamano
2005-09-24 21:28                     ` Davide Libenzi
2005-09-24 22:26                       ` Linus Torvalds
2005-09-24 22:27                         ` Linus Torvalds
2005-09-25 16:59 11%                       ` Linus Torvalds
2005-09-29  4:24  7% [PATCH] Add git-symbolic-ref Junio C Hamano
2005-10-01 18:39 11% [PATCH] Fix git+ssh's indefinite halts during long fetches Dan Aloni
2005-10-05  0:46     [PATCH] Fall back to three-way merge when applying a patch Junio C Hamano
2005-10-05  4:56     ` Linus Torvalds
2005-10-05  6:58       ` Junio C Hamano
2005-10-05 14:30         ` Linus Torvalds
2005-10-06  0:03           ` Junio C Hamano
2005-10-06  1:59             ` Eric W. Biederman
2005-10-06  2:18               ` Linus Torvalds
2005-10-06  5:25                 ` Eric W. Biederman
2005-10-06 14:35                   ` Linus Torvalds
2005-10-06 14:52                     ` Eric W. Biederman
2005-10-06 14:59                       ` Linus Torvalds
2005-10-07  2:33  7%                     ` [PATCH] Show original and resulting blob object info in diff output Junio C Hamano
2005-10-05 15:54     First cut at git port to Cygwin Christopher Faylor
2005-10-05 19:17     ` Alex Riesen
2005-10-05 20:29       ` Christopher Faylor
2005-10-06  9:05         ` Alex Riesen
2005-10-06 10:07           ` Alex Riesen
2005-10-07 12:44             ` Alex Riesen
2005-10-07 15:34               ` Linus Torvalds
2005-10-07 20:54                 ` Alex Riesen
2005-10-07 21:22                   ` Alex Riesen
2005-10-07 21:29                     ` Chuck Lever
2005-10-07 21:39                       ` Alex Riesen
2005-10-08 16:11                         ` Linus Torvalds
2005-10-08 18:27                           ` Johannes Schindelin
2005-10-08 18:44                             ` Junio C Hamano
2005-10-08 19:04                               ` Johannes Schindelin
2005-10-08 21:10                                 ` Junio C Hamano
2005-10-08 22:06 15%                               ` Johannes Schindelin
2005-10-06 23:23     Create object subdirectories on demand Linus Torvalds
2005-10-08  1:45     ` Daniel Barkalow
2005-10-09 10:42 14%   ` Use the same move_temp_to_file in git-http-fetch Junio C Hamano
2005-10-07 22:55 14% [PATCH] If NO_MMAP is defined, fake mmap() and munmap() Johannes Schindelin
2005-10-08 18:00     Seeing various mode changes on cygwin Jonas Fonseca
2005-10-08 18:51     ` Junio C Hamano
2005-10-08 21:36       ` Alex Riesen
2005-10-08 23:36         ` Junio C Hamano
2005-10-09  2:19           ` Linus Torvalds
2005-10-10  6:48             ` Daniel Barkalow
2005-10-10  7:38               ` Junio C Hamano
2005-10-10 17:59                 ` Daniel Barkalow
2005-10-10 18:22                   ` Linus Torvalds
2005-10-10 21:35 13%                 ` Add ".git/config" file parser Linus Torvalds
2005-10-12  0:54 12% Use git config file for committer name and email info Linus Torvalds
2005-10-12  1:40     Usage of isspace and friends Morten Welinder
2005-10-13  6:49     ` Junio C Hamano
2005-10-13 15:04       ` Linus Torvalds
2005-10-13 15:46 12%     ` Linus Torvalds
2005-10-13 21:26 16% [PATCH 1/3] Keep track of whether a pack is local or not Linus Torvalds
2005-10-14  6:03 15% [PATCH] Ignore funny refname sent from remote Junio C Hamano
2005-10-22  9:00 10% [PATCH] Allow caching of generated pack for full cloning Junio C Hamano
2005-10-22 22:22     Server side programs Andreas Ericsson
2005-10-23  0:30     ` Junio C Hamano
2005-10-23  9:41       ` User-relative paths (was: Server side programs) Andreas Ericsson
2005-10-23 19:56         ` User-relative paths Junio C Hamano
2005-10-25  9:11 18%       ` [PATCH] git_progname (was: Re: User-relative paths) Andreas Ericsson
2005-10-24  4:06     daemon.c broken on OpenBSD Randal L. Schwartz
2005-10-24  5:20  7% ` Junio C Hamano
2005-10-25 23:39     [PATCH 1/4] git-init-db should error out with a message Johannes Schindelin
2005-10-26 19:45 16% ` Alex Riesen
2005-10-27  0:16     [RFC] multi_ack protocol v2 Johannes Schindelin
2005-10-27  7:13     ` Junio C Hamano
2005-10-27 10:16       ` Sergey Vlasov
2005-10-27 10:47         ` Johannes Schindelin
2005-10-27 17:45 12%       ` Junio C Hamano
2005-10-28  2:48 17% [PATCH 6/8] Support receiving server capabilities Johannes Schindelin
2005-11-01 22:59 15% [PATCH 2/4] Library code for user-relative paths Andreas Ericsson
2005-11-14 23:02     git's rev-parse.c function show_datestring presumes gnu date Randal L. Schwartz
2005-11-14 23:08     ` Linus Torvalds
2005-11-15  3:29 10%   ` Linus Torvalds
2005-11-15 18:24 22% [PATCH] Add config variable core.symrefsonly Johannes Schindelin
2005-11-15 21:36 14% [PATCH 1/3] Add function git_config_set() Johannes Schindelin
2005-11-17 19:37 15% [PATCH 1/5] Library code for user-relative paths, take three Andreas Ericsson
2005-11-17 21:32 10% [PATCH] Add functions git_config_set() and git_config_set_multivar() Johannes Schindelin
2005-11-20  5:52  7% [PATCH] git-config-set: add more options Johannes Schindelin
2005-11-20 17:00     Get rid of .git/branches/ and .git/remotes/? Johannes Schindelin
2005-11-20 18:09     ` Linus Torvalds
2005-11-20 23:26       ` Josef Weidendorfer
2005-11-22 17:31         ` Josef Weidendorfer
2005-11-22 17:56           ` Johannes Schindelin
2005-11-22 19:30             ` Andreas Ericsson
2005-11-23 15:08               ` Johannes Schindelin
2005-11-23 23:21                 ` Junio C Hamano
2005-11-23 23:29                   ` Andreas Ericsson
2005-11-23 23:42                     ` Johannes Schindelin
2005-11-24  8:05                       ` Andreas Ericsson
2005-11-24  8:33                         ` Junio C Hamano
2005-11-24 10:36                           ` [PATCH] Rename git-config-set to git-repo-config Johannes Schindelin
2005-11-24 11:33                             ` Junio C Hamano
2005-11-24 13:28                               ` Johannes Schindelin
2005-11-24 21:24                                 ` Junio C Hamano
2005-11-26  9:56 15%                               ` [PATCH 1/8] git-apply: work from subdirectory Junio C Hamano
2005-11-26  9:56 17%                               ` [PATCH 2/8] peek-remote: honor proxy config even " Junio C Hamano
2005-11-21  0:52 11% [PATCH] Fix sparse warnings Timo Hirvonen
2005-11-21  8:14 19% [PATCH] enter_repo missing its prototype Alex Riesen
2005-11-22  0:28     Git Future Proofing Martin Atukunda
2005-11-22  0:28 19% ` [PATCH 3/6] Make get_git_dir take a flag that makes it re-read the env. variables Martin Atukunda
2005-11-22  0:28 19% ` [PATCH 1/6] Add GIT_REPO_VERSION, and repository_format_version Martin Atukunda
2005-11-22  0:28 18% ` [PATCH 5/6] Allow Specification of the conf file to read for git_config operations Martin Atukunda
2005-11-24  3:36 12% [RFC/PATCH 1/3] git-find-git: a new helper Junio C Hamano
2005-11-24  3:36 19% [RFC/PATCH 2/3] Add GIT_REPO_VERSION, and repository_format_version Junio C Hamano
2005-11-24  3:36 14% [RFC/PATCH 3/3] Check repository format version Junio C Hamano
2005-11-26  1:15 18% [PATCH 1/4] Repository format version check Junio C Hamano
2005-11-26  1:15 12% [PATCH 3/4] init-db: check template and repository format Junio C Hamano
2005-11-28  0:39 17% [PATCH 1/3] Introduce i18n.commitencoding Junio C Hamano
2005-12-05 13:19 17% make gitfakemmap standalone to fix linking error in git.c Alex Riesen
2005-12-05 13:24     ` Alex Riesen
2005-12-05 17:40       ` Junio C Hamano
2005-12-05 20:22 10%     ` [PATCH] Clean up compatibility definitions Junio C Hamano
2005-12-10  6:57 12% [PATCH] Allow updating the index from a pipe Daniel Barkalow
2005-12-10 19:37     [PATCH 0/25] Usage message clean-up freku045
2005-12-10 19:37 39% ` [PATCH 21/25] git-send-email: " freku045
2005-12-10 22:25 15% [PATCH] Allow saving an object from a pipe Daniel Barkalow
2005-12-15  0:44     How to clone-pack the HEAD? Petr Baudis
2005-12-15  1:20     ` Junio C Hamano
2005-12-15  1:32       ` Petr Baudis
2005-12-15  1:45         ` Junio C Hamano
2005-12-15  1:53           ` Junio C Hamano
2005-12-15  5:29             ` Junio C Hamano
2005-12-15  6:21  7%           ` Junio C Hamano
2005-12-22 22:13 16% [PATCH] Introduce core.sharedrepository Johannes Schindelin
2005-12-22 22:19 14% [PATCH] git-init-db: initialize shared repositories with --shared Johannes Schindelin
2005-12-24 12:10     [PATCH 0/4] dietlibc compatibility Eric Wong
2005-12-24 12:13 15% ` [PATCH 3/4] add xmktime() function that always accounts for the TZ env Eric Wong
2005-12-24 12:20 15% [PATCH] add strcpy_user_path() and use it in init-db.c and git.c Eric Wong
2006-01-03 11:38     Howto send many commits as mail-patches? Sam Ravnborg
2006-01-03 17:24 48% ` Ryan Anderson
2006-01-07  7:01     [ANNOUNCE] GIT 1.0.7 Junio C Hamano
2006-01-07  8:16     ` YOSHIFUJI Hideaki / 吉藤英明
2006-01-07  8:43       ` Junio C Hamano
2006-01-07  9:56 17%     ` Junio C Hamano
2006-01-09 23:34     [PATCH 0/2] Remember and use GIT_EXEC_PATH on exec()'s Michal Ostrowski
2006-01-09 23:35 16% ` [PATCH 1/2] " Michal Ostrowski
2006-01-18 13:47 15% cygwin-latest: compile errors related to sockaddr_storage, dirent->d_type and dirent->d_ino Alex Riesen
2006-01-20  1:13 17% ` [PATCH] DT_UNKNOWN: do not fully trust existence of DT_UNKNOWN Junio C Hamano
2006-01-20 15:01       ` Alex Riesen
2006-01-20 19:10 19%     ` Junio C Hamano
2006-01-19  3:43     /etc in git? Adam Hunt
2006-01-19  4:35     ` Junio C Hamano
2006-01-19  4:40       ` Adam Hunt
2006-01-19  5:05         ` Junio C Hamano
2006-01-19  6:23           ` Ryan Anderson
2006-01-19  7:50             ` Junio C Hamano
2006-01-19  9:41 18%           ` [PATCH] Support precise tracking of file modes Petr Baudis
2006-01-25  7:47     git describe fails without tags Uwe Zeisberger
2006-01-25  9:52     ` Junio C Hamano
2006-01-26  8:41 16%   ` Uwe Zeisberger
2006-01-26  2:10     LCA06 Cogito/GIT workshop - (Re: git-whatchanged: exit out early on errors) Martin Langhoff
2006-01-28  4:47     ` Linus Torvalds
2006-01-28  5:33       ` Martin Langhoff
2006-01-28 11:00         ` Keith Packard
2006-01-28 21:08           ` [Census] So who uses git? Junio C Hamano
2006-01-29 10:09             ` Keith Packard
2006-01-29 11:18               ` Radoslaw Szkodzinski
2006-01-30 22:51                 ` Alex Riesen
2006-01-31 21:25                   ` Linus Torvalds
2006-01-31 22:01                     ` Alex Riesen
     [not found]                       ` <20060201013901.GA16832@mail.com>
2006-02-01  2:04                         ` Linus Torvalds
2006-02-01  2:09 21%                       ` Linus Torvalds
2006-02-09  5:15 10%                         ` [PATCH] "Assume unchanged" git Junio C Hamano
2006-01-26  6:13 15% [PATCH] Only use a single parser for tree objects Daniel Barkalow
2006-01-30  7:18     [RFC] shallow clone Junio C Hamano
2006-01-30 11:39     ` Johannes Schindelin
2006-01-30 18:46       ` Junio C Hamano
2006-01-31 11:02 10%     ` [PATCH] Shallow clone: low level machinery Junio C Hamano
2006-02-02 16:56     [PATCH 0/2] Small updates to git-send-email Ryan Anderson
2006-02-02 16:56 47% ` [PATCH 1/2] Provide a more meaningful initial "From " line when using --compose in git-send-email Ryan Anderson
2006-02-02 16:56 48%   ` [PATCH 2/2] git-send-email: Add --quiet to reduce some of the chatter when sending emails Ryan Anderson
2006-02-03 20:23     [PATCH 0/3] git-daemon hacking Mark Wooding
2006-02-03 20:27     ` [PATCH 3/3] daemon: Support a --user-path option Mark Wooding
2006-02-03 20:52       ` Junio C Hamano
2006-02-04 10:02         ` Mark Wooding
2006-02-04 12:40           ` Junio C Hamano
2006-02-04 19:13 10%         ` Mark Wooding
2006-02-06  1:13 44% [PATCH] git-send-email: Fully implement --quiet and document it Ryan Anderson
2006-02-11  2:47 47% [PATCH] Don't send copies to the From: address Christian Biesinger
2006-02-11  3:55 44% ` Junio C Hamano
2006-02-11  4:31 11% Make "git clone" less of a deathly quiet experience Linus Torvalds
2006-02-13  8:22     [PATCH 0/2] More git-send-email updates Ryan Anderson
2006-02-13  8:22 49% ` [PATCH 1/2] send-email: Add some options for controlling how addresses are automatically Ryan Anderson
2006-02-13  8:22 54%   ` [PATCH 2/2] send-email: Add --cc Ryan Anderson
2006-02-15  8:39     [FYI] pack idx format Junio C Hamano
2006-02-16  1:43     ` [PATCH] pack-objects: reuse data from existing pack Junio C Hamano
2006-02-16  1:45 17%   ` [PATCH] packed objects: minor cleanup Junio C Hamano
2006-02-18  8:44     [RFC] empty ident? Junio C Hamano
2006-02-18 17:27     ` [PATCH] Nice error message for empty idents Petr Baudis
2006-02-19  4:56 12%   ` [PATCH] Delay "empty ident" errors until they really matter Junio C Hamano
2006-02-20 18:37     Should we support Perl 5.6? Johannes Schindelin
2006-02-20 19:10     ` Eric Wong
2006-02-20 22:05       ` [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6 Junio C Hamano
2006-02-20 22:12 47%     ` [PATCH] send-email: " Junio C Hamano
2006-02-22 16:35     ` [PATCH] fmt-merge-msg: " Alex Riesen
2006-02-22 22:00       ` Johannes Schindelin
2006-02-23  8:00         ` Alex Riesen
2006-02-23  8:45           ` Junio C Hamano
2006-02-23  9:35             ` Alex Riesen
2006-02-23  9:41               ` Alex Riesen
2006-02-23  9:48                 ` Andreas Ericsson
2006-02-23 10:10                   ` Alex Riesen
2006-02-23 13:29                     ` Andreas Ericsson
2006-02-23 14:07                       ` Alex Riesen
2006-02-23 17:13                         ` Linus Torvalds
2006-02-23 19:32                           ` Junio C Hamano
2006-02-23 19:51                             ` Linus Torvalds
2006-02-23 20:31                               ` Sam Vilain
2006-02-24  6:43  6%                             ` Linus Torvalds
2006-02-23 14:33 38% [PATCH] Convert open("-|") to qx{} calls Johannes Schindelin
2006-02-26  1:40     the war on trailing whitespace Andrew Morton
2006-02-26  3:38     ` Junio C Hamano
2006-02-26  5:07       ` Andrew Morton
2006-02-26 17:29         ` Linus Torvalds
2006-02-26 18:36           ` Andrew Morton
2006-02-26 20:16             ` Linus Torvalds
2006-02-26 20:26               ` Dave Jones
2006-02-27  2:50                 ` MIke Galbraith
2006-02-27  9:07                   ` Johannes Schindelin
2006-02-27  9:18                     ` Andrew Morton
2006-02-27 23:18                       ` Junio C Hamano
2006-02-28  1:13 14%                     ` [PATCH 2/3] apply --whitespace: configuration option Junio C Hamano
2006-02-26 15:13 15% [PATCH] Use setenv(), fix warnings Timo Hirvonen
2006-02-28 19:19     [PATCH 0/3] git-rev-list libification effort: the next stage Linus Torvalds
2006-02-28 19:26 16% ` [PATCH 2/3] Introduce trivial new pager.c helper infrastructure Linus Torvalds
2006-03-01  4:41 12% [PATCH] Teach git-checkout-index to use file suffixes Shawn Pearce
2006-03-03  1:20  8% [PATCH] Add --temp and --stage=all options to checkout-index Shawn Pearce
2006-03-03  5:25     ` Junio C Hamano
2006-03-03 15:13       ` Shawn Pearce
2006-03-05  5:29         ` Junio C Hamano
2006-03-05  8:24  8%       ` Shawn Pearce
2006-03-03  9:28 49% [PATCH] send-email: accept --no-signed-off-by-cc as the documentation states Eric Wong
     [not found]     <20060323161521.28a874e6.akpm@osdl.org>
     [not found]     ` <20060324002930.GA21184@kroah.com>
     [not found]       ` <20060323163844.5fda7589.akpm@osdl.org>
2006-03-24  0:46         ` Fw: [PATCH 31/49] PCI: PCI/Cardbus cards hidden, needs pci=assign-busses to fix Greg KH
2006-03-24  1:26           ` Junio C Hamano
2006-03-24  1:51             ` Andrew Morton
2006-03-24  2:27 46%           ` Junio C Hamano
2006-03-25 10:43     send-email: dependency removal, cleanup, + small feature Eric Wong
2006-03-25 10:43 40% ` [PATCH 1/4] send-email: Change from Mail::Sendmail to Net::SMTP Eric Wong
2006-03-25 10:43 49% ` [PATCH 2/4] send-email: use built-in time() instead of /bin/date '+%s' Eric Wong
2006-03-25 10:43 43% ` [PATCH 4/4] send-email: add support for mutt aliases files Eric Wong
2006-03-25 10:43 43% ` [PATCH 3/4] send-email: lazy-load Email::Valid and make it optional Eric Wong
2006-03-25 11:01 45% [PATCH] send-email: try to order messages in email clients more correctly Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).