Use a hashtable for objects instead of a sorted list
[git.git] / sha1_file.c
index 111a71d..3d11a9b 100644 (file)
@@ -6,8 +6,6 @@
  * This handles basic git sha1 object files - packing, unpacking,
  * creation etc.
  */
-#include <sys/types.h>
-#include <dirent.h>
 #include "cache.h"
 #include "delta.h"
 #include "pack.h"
@@ -48,9 +46,34 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
        return 0;
 }
 
+int adjust_shared_perm(const char *path)
+{
+       struct stat st;
+       int mode;
+
+       if (!shared_repository)
+               return 0;
+       if (lstat(path, &st) < 0)
+               return -1;
+       mode = st.st_mode;
+       if (mode & S_IRUSR)
+               mode |= S_IRGRP;
+       if (mode & S_IWUSR)
+               mode |= S_IWGRP;
+       if (mode & S_IXUSR)
+               mode |= S_IXGRP;
+       if (S_ISDIR(mode))
+               mode |= S_ISGID;
+       if (chmod(path, mode) < 0)
+               return -2;
+       return 0;
+}
+
 int safe_create_leading_directories(char *path)
 {
        char *pos = path;
+       struct stat st;
+
        if (*pos == '/')
                pos++;
 
@@ -59,11 +82,21 @@ int safe_create_leading_directories(char *path)
                if (!pos)
                        break;
                *pos = 0;
-               if (mkdir(path, 0777) < 0)
-                       if (errno != EEXIST) {
+               if (!stat(path, &st)) {
+                       /* path exists */
+                       if (!S_ISDIR(st.st_mode)) {
                                *pos = '/';
-                               return -1;
+                               return -3;
                        }
+               }
+               else if (mkdir(path, 0777)) {
+                       *pos = '/';
+                       return -1;
+               }
+               else if (adjust_shared_perm(path)) {
+                       *pos = '/';
+                       return -2;
+               }
                *pos++ = '/';
        }
        return 0;
@@ -81,6 +114,8 @@ char * sha1_to_hex(const unsigned char *sha1)
                *buf++ = hex[val >> 4];
                *buf++ = hex[val & 0xf];
        }
+       *buf = '\0';
+
        return buffer;
 }
 
@@ -464,7 +499,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
        p->pack_last_used = 0;
        p->pack_use_cnt = 0;
        p->pack_local = local;
-       if (!get_sha1_hex(path + path_len - 40 - 4, sha1))
+       if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
                memcpy(p->sha1, sha1, 20);
        return p;
 }
@@ -1239,6 +1274,8 @@ static int link_temp_to_file(const char *tmpfile, char *filename)
                if (dir) {
                        *dir = 0;
                        mkdir(filename, 0777);
+                       if (adjust_shared_perm(filename))
+                               return -2;
                        *dir = '/';
                        if (!link(tmpfile, filename))
                                return 0;
@@ -1274,7 +1311,7 @@ int move_temp_to_file(const char *tmpfile, char *filename)
        unlink(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
-                       fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
+                       fprintf(stderr, "unable to write sha1 filename %s: %s\n", filename, strerror(ret));
                        return -1;
                }
                /* FIXME!!! Collision check here ? */
@@ -1313,7 +1350,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
        }
 
        if (errno != ENOENT) {
-               fprintf(stderr, "sha1 file %s: %s", filename, strerror(errno));
+               fprintf(stderr, "sha1 file %s: %s\n", filename, strerror(errno));
                return -1;
        }
 
@@ -1321,7 +1358,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
 
        fd = mkstemp(tmpfile);
        if (fd < 0) {
-               fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
+               fprintf(stderr, "unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
                return -1;
        }
 
@@ -1410,7 +1447,7 @@ int write_sha1_to_fd(int fd, const unsigned char *sha1)
                size = write(fd, buf + posn, objsize - posn);
                if (size <= 0) {
                        if (!size) {
-                               fprintf(stderr, "write closed");
+                               fprintf(stderr, "write closed\n");
                        } else {
                                perror("write ");
                        }
@@ -1528,6 +1565,40 @@ int has_sha1_file(const unsigned char *sha1)
        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;