Code

i18n: add infrastructure for translating Git with gettext
[git.git] / sha1_file.c
index d5616dca0809bdb9fd6a7a1980b92ded9ae6e230..27f3b9b278a97f66f92ca61a2bc39e30f0a70317 100644 (file)
@@ -248,27 +248,30 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
        const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
-       /* 43 = 40-byte + 2 '/' + terminating NUL */
-       int pfxlen = len;
-       int entlen = pfxlen + 43;
-       int base_len = -1;
+       int pfxlen, entlen;
+       struct strbuf pathbuf = STRBUF_INIT;
 
        if (!is_absolute_path(entry) && relative_base) {
-               /* Relative alt-odb */
-               if (base_len < 0)
-                       base_len = strlen(relative_base) + 1;
-               entlen += base_len;
-               pfxlen += base_len;
+               strbuf_addstr(&pathbuf, real_path(relative_base));
+               strbuf_addch(&pathbuf, '/');
        }
-       ent = xmalloc(sizeof(*ent) + entlen);
+       strbuf_add(&pathbuf, entry, len);
 
-       if (!is_absolute_path(entry) && relative_base) {
-               memcpy(ent->base, relative_base, base_len - 1);
-               ent->base[base_len - 1] = '/';
-               memcpy(ent->base + base_len, entry, len);
-       }
-       else
-               memcpy(ent->base, entry, pfxlen);
+       normalize_path_copy(pathbuf.buf, pathbuf.buf);
+
+       pfxlen = strlen(pathbuf.buf);
+
+       /*
+        * The trailing slash after the directory name is given by
+        * this function at the end. Remove duplicates.
+        */
+       while (pfxlen && pathbuf.buf[pfxlen-1] == '/')
+               pfxlen -= 1;
+
+       entlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */
+       ent = xmalloc(sizeof(*ent) + entlen);
+       memcpy(ent->base, pathbuf.buf, pfxlen);
+       strbuf_release(&pathbuf);
 
        ent->name = ent->base + pfxlen + 1;
        ent->base[pfxlen + 3] = '/';
@@ -380,7 +383,7 @@ void add_to_alternates_file(const char *reference)
 {
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
        int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR);
-       char *alt = mkpath("%s/objects\n", reference);
+       char *alt = mkpath("%s\n", reference);
        write_or_die(fd, alt, strlen(alt));
        if (commit_lock_file(lock))
                die("could not close alternates file");
@@ -1217,14 +1220,34 @@ static int experimental_loose_object(unsigned char *map)
        unsigned int word;
 
        /*
-        * Is it a zlib-compressed buffer? If so, the first byte
-        * must be 0x78 (15-bit window size, deflated), and the
-        * first 16-bit word is evenly divisible by 31. If so,
-        * we are looking at the official format, not the experimental
-        * one.
+        * We must determine if the buffer contains the standard
+        * zlib-deflated stream or the experimental format based
+        * on the in-pack object format. Compare the header byte
+        * for each format:
+        *
+        * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
+        * Experimental pack-based : Stttssss : ttt = 1,2,3,4
+        *
+        * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
+        * in standard loose-object format, UNLESS it is a Git-pack
+        * format object *exactly* 8 bytes in size when inflated.
+        *
+        * However, RFC1950 also specifies that the 1st 16-bit word
+        * must be divisible by 31 - this checksum tells us our buffer
+        * is in the standard format, giving a false positive only if
+        * the 1st word of the Git-pack format object happens to be
+        * divisible by 31, ie:
+        *      ((byte0 * 256) + byte1) % 31 = 0
+        *   =>        0ttt10000www1000 % 31 = 0
+        *
+        * As it happens, this case can only arise for www=3 & ttt=1
+        * - ie, a Commit object, which would have to be 8 bytes in
+        * size. As no Commit can be that small, we find that the
+        * combination of these two criteria (bitmask & checksum)
+        * can always correctly determine the buffer format.
         */
        word = (map[0] << 8) + map[1];
-       if (map[0] == 0x78 && !(word % 31))
+       if ((map[0] & 0x8F) == 0x08 && !(word % 31))
                return 0;
        else
                return 1;
@@ -1964,7 +1987,7 @@ off_t find_pack_entry_one(const unsigned char *sha1,
        return 0;
 }
 
-static int is_pack_valid(struct packed_git *p)
+int is_pack_valid(struct packed_git *p)
 {
        /* An already open pack is known to be valid. */
        if (p->pack_fd != -1)
@@ -2015,7 +2038,7 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
                         * was loaded!
                         */
                        if (!is_pack_valid(p)) {
-                               error("packfile %s cannot be accessed", p->pack_name);
+                               warning("packfile %s cannot be accessed", p->pack_name);
                                goto next;
                        }
                        e->offset = offset;