send-email: Change from Mail::Sendmail to Net::SMTP
[git.git] / sha1_file.c
index 8bebbb2..58edec0 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"
@@ -74,6 +72,8 @@ int adjust_shared_perm(const char *path)
 int safe_create_leading_directories(char *path)
 {
        char *pos = path;
+       struct stat st;
+
        if (*pos == '/')
                pos++;
 
@@ -82,12 +82,17 @@ 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;
@@ -242,6 +247,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
                for ( ; cp < ep && *cp != sep; cp++)
                        ;
                if (last != cp) {
+                       struct stat st;
                        struct alternate_object_database *alt;
                        /* 43 = 40-byte + 2 '/' + terminating NUL */
                        int pfxlen = cp - last;
@@ -264,9 +270,19 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
                        }
                        else
                                memcpy(ent->base, last, pfxlen);
+
                        ent->name = ent->base + pfxlen + 1;
-                       ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
-                       ent->base[entlen-1] = 0;
+                       ent->base[pfxlen + 3] = '/';
+                       ent->base[pfxlen] = ent->base[entlen-1] = 0;
+
+                       /* Detect cases where alternate disappeared */
+                       if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
+                               error("object directory %s does not exist; "
+                                     "check .git/objects/info/alternates.",
+                                     ent->base);
+                               goto bad;
+                       }
+                       ent->base[pfxlen] = '/';
 
                        /* Prevent the common mistake of listing the same
                         * thing twice, or object directory itself.
@@ -349,16 +365,12 @@ struct packed_git *packed_git;
 static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
                                void **idx_map_)
 {
-       SHA_CTX ctx;
-       unsigned char sha1[20];
        void *idx_map;
        unsigned int *index;
        unsigned long idx_size;
        int nr, i;
-       int fd;
+       int fd = open(path, O_RDONLY);
        struct stat st;
-
-       fd = open(path, O_RDONLY);
        if (fd < 0)
                return -1;
        if (fstat(fd, &st)) {
@@ -396,16 +408,6 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
        if (idx_size != 4*256 + nr * 24 + 20 + 20)
                return error("wrong index file size");
 
-       /*
-        * File checksum.
-        */
-       SHA1_Init(&ctx);
-       SHA1_Update(&ctx, idx_map, idx_size-20);
-       SHA1_Final(sha1, &ctx);
-
-       if (memcmp(sha1, idx_map + idx_size - 20, 20))
-               return error("index checksum mismatch");
-
        return 0;
 }
 
@@ -560,8 +562,12 @@ 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) {
+               if (errno != ENOENT)
+                       error("unable to open object pack directory: %s: %s",
+                             path, strerror(errno));
                return;
+       }
        path[len++] = '/';
        while ((de = readdir(dir)) != NULL) {
                int namelen = strlen(de->d_name);
@@ -835,11 +841,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;
@@ -853,7 +878,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;
@@ -948,6 +973,16 @@ static void *unpack_delta_entry(unsigned char *base_sha1,
 
        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));
+       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));
+
        data = base_sha1 + 20;
        data_size = left - 20;
        delta_data = xmalloc(delta_size);
@@ -965,14 +1000,6 @@ static void *unpack_delta_entry(unsigned char *base_sha1,
        if ((st != Z_STREAM_END) || stream.total_out != delta_size)
                die("delta data unpack failed");
 
-       /* 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));
        result = patch_delta(base, base_size,
                             delta_data, delta_size,
                             &result_size);
@@ -1488,7 +1515,8 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
 
        local = mkstemp(tmpfile);
        if (local < 0)
-               return error("Couldn't open %s for %s\n", tmpfile, sha1_to_hex(sha1));
+               return error("Couldn't open %s for %s",
+                            tmpfile, sha1_to_hex(sha1));
 
        memset(&stream, 0, sizeof(stream));
 
@@ -1536,7 +1564,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
        }
        if (memcmp(sha1, real_sha1, 20)) {
                unlink(tmpfile);
-               return error("File %s has bad hash\n", sha1_to_hex(sha1));
+               return error("File %s has bad hash", sha1_to_hex(sha1));
        }
 
        return move_temp_to_file(tmpfile, sha1_file_name(sha1));