Merge branch 'jc/pack-reuse'
[git.git] / sha1_file.c
index d451a94..9cab99a 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;
@@ -518,8 +551,10 @@ static void prepare_packed_git_one(char *objdir, int local)
        sprintf(path, "%s/pack", objdir);
        len = strlen(path);
        dir = opendir(path);
-       if (!dir)
+       if (!dir) {
+               fprintf(stderr, "unable to open object pack directory: %s: %s\n", path, strerror(errno));
                return;
+       }
        path[len++] = '/';
        while ((de = readdir(dir)) != NULL) {
                int namelen = strlen(de->d_name);
@@ -793,11 +828,30 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of
        return offset;
 }
 
+int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
+                          unsigned char *base, unsigned long *sizep,
+                          enum object_type *kindp)
+{
+       unsigned long ptr;
+       int status = -1;
+
+       use_packed_git(p);
+       ptr = offset;
+       ptr = unpack_object_header(p, ptr, kindp, sizep);
+       if (*kindp != OBJ_DELTA)
+               goto done;
+       memcpy(base, p->pack_base + ptr, 20);
+       status = 0;
+ done:
+       unuse_packed_git(p);
+       return status;
+}
+
 void packed_object_info_detail(struct pack_entry *e,
                               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;
@@ -811,7 +865,7 @@ void packed_object_info_detail(struct pack_entry *e,
        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;
@@ -1241,6 +1295,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;