Merge branch 'jh/partial-clone' into next
[gitweb.git] / sha1_file.c
index d7089813762513254b8fe48199a57ecdeb8600f3..2e58f5560a63426ab1b9848434ea0e1ac3ba1fba 100644 (file)
@@ -29,6 +29,7 @@
 #include "mergesort.h"
 #include "quote.h"
 #include "packfile.h"
+#include "fetch-object.h"
 
 const unsigned char null_sha1[GIT_MAX_RAWSZ];
 const struct object_id null_oid;
@@ -39,6 +40,64 @@ const struct object_id empty_blob_oid = {
        EMPTY_BLOB_SHA1_BIN_LITERAL
 };
 
+static void git_hash_sha1_init(void *ctx)
+{
+       git_SHA1_Init((git_SHA_CTX *)ctx);
+}
+
+static void git_hash_sha1_update(void *ctx, const void *data, size_t len)
+{
+       git_SHA1_Update((git_SHA_CTX *)ctx, data, len);
+}
+
+static void git_hash_sha1_final(unsigned char *hash, void *ctx)
+{
+       git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
+}
+
+static void git_hash_unknown_init(void *ctx)
+{
+       die("trying to init unknown hash");
+}
+
+static void git_hash_unknown_update(void *ctx, const void *data, size_t len)
+{
+       die("trying to update unknown hash");
+}
+
+static void git_hash_unknown_final(unsigned char *hash, void *ctx)
+{
+       die("trying to finalize unknown hash");
+}
+
+const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
+       {
+               NULL,
+               0x00000000,
+               0,
+               0,
+               0,
+               git_hash_unknown_init,
+               git_hash_unknown_update,
+               git_hash_unknown_final,
+               NULL,
+               NULL,
+       },
+       {
+               "sha-1",
+               /* "sha1", big-endian */
+               0x73686131,
+               sizeof(git_SHA_CTX),
+               GIT_SHA1_RAWSZ,
+               GIT_SHA1_HEXSZ,
+               git_hash_sha1_init,
+               git_hash_sha1_update,
+               git_hash_sha1_final,
+               &empty_tree_oid,
+               &empty_blob_oid,
+       },
+};
+
 /*
  * This is meant to hold a *small* number of objects that you would
  * want read_sha1_file() to be able to return, but yet you do not want
@@ -74,6 +133,18 @@ static struct cached_object *find_cached_object(const unsigned char *sha1)
        return NULL;
 }
 
+
+static enum safe_crlf get_safe_crlf(unsigned flags)
+{
+       if (flags & HASH_RENORMALIZE)
+               return SAFE_CRLF_RENORMALIZE;
+       else if (flags & HASH_WRITE_OBJECT)
+               return safe_crlf;
+       else
+               return SAFE_CRLF_FALSE;
+}
+
+
 int mkdir_in_gitdir(const char *path)
 {
        if (mkdir(path, 0777)) {
@@ -404,6 +475,9 @@ static void link_alt_odb_entries(const char *alt, int sep,
        struct strbuf objdirbuf = STRBUF_INIT;
        struct strbuf entry = STRBUF_INIT;
 
+       if (!alt || !*alt)
+               return;
+
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
                                relative_base);
@@ -604,7 +678,6 @@ void prepare_alt_odb(void)
                return;
 
        alt = getenv(ALTERNATE_DB_ENVIRONMENT);
-       if (!alt) alt = "";
 
        alt_odb_tail = &alt_odb_list;
        link_alt_odb_entries(alt, PATH_SEP, NULL, 0);
@@ -1141,6 +1214,8 @@ static int sha1_loose_object_info(const unsigned char *sha1,
        return (status < 0) ? status : 0;
 }
 
+int fetch_if_missing = 1;
+
 int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
 {
        static struct object_info blank_oi = OBJECT_INFO_INIT;
@@ -1149,6 +1224,10 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
        const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
                                    lookup_replace_object(sha1) :
                                    sha1;
+       int already_retried = 0;
+
+       if (is_null_sha1(real))
+               return -1;
 
        if (!oi)
                oi = &blank_oi;
@@ -1173,19 +1252,32 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                }
        }
 
-       if (!find_pack_entry(real, &e)) {
+       while (1) {
+               if (find_pack_entry(real, &e))
+                       break;
+
                /* Most likely it's a loose object. */
                if (!sha1_loose_object_info(real, oi, flags))
                        return 0;
 
                /* Not a loose object; someone else may have just packed it. */
-               if (flags & OBJECT_INFO_QUICK) {
-                       return -1;
-               } else {
-                       reprepare_packed_git();
-                       if (!find_pack_entry(real, &e))
-                               return -1;
+               reprepare_packed_git();
+               if (find_pack_entry(real, &e))
+                       break;
+
+               /* Check if it is a missing object */
+               if (fetch_if_missing && repository_format_partial_clone &&
+                   !already_retried) {
+                       /*
+                        * TODO Investigate haveing fetch_object() return
+                        * TODO error/success and stopping the music here.
+                        */
+                       fetch_object(repository_format_partial_clone, real);
+                       already_retried = 1;
+                       continue;
                }
+
+               return -1;
        }
 
        if (oi == &blank_oi)
@@ -1194,7 +1286,6 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                 * information below, so return early.
                 */
                return 0;
-
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
@@ -1677,7 +1768,7 @@ static int index_mem(struct object_id *oid, void *buf, size_t size,
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(&the_index, path, buf, size, &nbuf,
-                                  write_object ? safe_crlf : SAFE_CRLF_FALSE)) {
+                                  get_safe_crlf(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
@@ -1711,7 +1802,7 @@ static int index_stream_convert_blob(struct object_id *oid, int fd,
        assert(would_convert_to_git_filter_fd(path));
 
        convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
-                                write_object ? safe_crlf : SAFE_CRLF_FALSE);
+                                get_safe_crlf(flags));
 
        if (write_object)
                ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
@@ -1889,7 +1980,6 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        origlen = path->len;
        strbuf_complete(path, '/');
        strbuf_addf(path, "%02x", subdir_nr);
-       baselen = path->len;
 
        dir = opendir(path->buf);
        if (!dir) {
@@ -1900,15 +1990,18 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        }
 
        oid.hash[0] = subdir_nr;
+       strbuf_addch(path, '/');
+       baselen = path->len;
 
        while ((de = readdir(dir))) {
+               size_t namelen;
                if (is_dot_or_dotdot(de->d_name))
                        continue;
 
+               namelen = strlen(de->d_name);
                strbuf_setlen(path, baselen);
-               strbuf_addf(path, "/%s", de->d_name);
-
-               if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2 &&
+               strbuf_add(path, de->d_name, namelen);
+               if (namelen == GIT_SHA1_HEXSZ - 2 &&
                    !hex_to_bytes(oid.hash + 1, de->d_name,
                                  GIT_SHA1_RAWSZ - 1)) {
                        if (obj_cb) {
@@ -1927,7 +2020,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
        }
        closedir(dir);
 
-       strbuf_setlen(path, baselen);
+       strbuf_setlen(path, baselen - 1);
        if (!r && subdir_cb)
                r = subdir_cb(subdir_nr, path->buf, data);