http: treat config options sslCAPath and sslCAInfo as paths
[gitweb.git] / sha1_file.c
index 99155c0d6b77aa2a772330d51fa604b1c4a9b0cf..40a0169ceb11e338e22a5937eb43b57c4d3a6846 100644 (file)
@@ -401,13 +401,46 @@ void read_info_alternates(const char * relative_base, int depth)
 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\n", reference);
-       write_or_die(fd, alt, strlen(alt));
-       if (commit_lock_file(lock))
-               die("could not close alternates file");
-       if (alt_odb_tail)
-               link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0);
+       char *alts = git_pathdup("objects/info/alternates");
+       FILE *in, *out;
+
+       hold_lock_file_for_update(lock, alts, LOCK_DIE_ON_ERROR);
+       out = fdopen_lock_file(lock, "w");
+       if (!out)
+               die_errno("unable to fdopen alternates lockfile");
+
+       in = fopen(alts, "r");
+       if (in) {
+               struct strbuf line = STRBUF_INIT;
+               int found = 0;
+
+               while (strbuf_getline(&line, in, '\n') != EOF) {
+                       if (!strcmp(reference, line.buf)) {
+                               found = 1;
+                               break;
+                       }
+                       fprintf_or_die(out, "%s\n", line.buf);
+               }
+
+               strbuf_release(&line);
+               fclose(in);
+
+               if (found) {
+                       rollback_lock_file(lock);
+                       lock = NULL;
+               }
+       }
+       else if (errno != ENOENT)
+               die_errno("unable to read alternates file");
+
+       if (lock) {
+               fprintf_or_die(out, "%s\n", reference);
+               if (commit_lock_file(lock))
+                       die_errno("unable to move new alternates file into place");
+               if (alt_odb_tail)
+                       link_alt_odb_entries(reference, strlen(reference), '\n', NULL, 0);
+       }
+       free(alts);
 }
 
 int foreach_alt_odb(alt_odb_fn fn, void *cb)
@@ -753,6 +786,37 @@ void close_pack_windows(struct packed_git *p)
        }
 }
 
+static int close_pack_fd(struct packed_git *p)
+{
+       if (p->pack_fd < 0)
+               return 0;
+
+       close(p->pack_fd);
+       pack_open_fds--;
+       p->pack_fd = -1;
+
+       return 1;
+}
+
+static void close_pack(struct packed_git *p)
+{
+       close_pack_windows(p);
+       close_pack_fd(p);
+       close_pack_index(p);
+}
+
+void close_all_packs(void)
+{
+       struct packed_git *p;
+
+       for (p = packed_git; p; p = p->next)
+               if (p->do_not_close)
+                       die("BUG! Want to close pack marked 'do-not-close'");
+               else
+                       close_pack(p);
+}
+
+
 /*
  * The LRU pack is the one with the oldest MRU window, preferring packs
  * with no used windows, or the oldest mtime if it has no windows allocated.
@@ -820,12 +884,8 @@ static int close_one_pack(void)
                find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
        }
 
-       if (lru_p) {
-               close(lru_p->pack_fd);
-               pack_open_fds--;
-               lru_p->pack_fd = -1;
-               return 1;
-       }
+       if (lru_p)
+               return close_pack_fd(lru_p);
 
        return 0;
 }
@@ -865,12 +925,7 @@ void free_pack_by_name(const char *pack_name)
                p = *pp;
                if (strcmp(pack_name, p->pack_name) == 0) {
                        clear_delta_base_cache();
-                       close_pack_windows(p);
-                       if (p->pack_fd != -1) {
-                               close(p->pack_fd);
-                               pack_open_fds--;
-                       }
-                       close_pack_index(p);
+                       close_pack(p);
                        free(p->bad_object_sha1);
                        *pp = p->next;
                        if (last_found_pack == p)
@@ -1004,11 +1059,7 @@ static int open_packed_git(struct packed_git *p)
 {
        if (!open_packed_git_1(p))
                return 0;
-       if (p->pack_fd != -1) {
-               close(p->pack_fd);
-               pack_open_fds--;
-               p->pack_fd = -1;
-       }
+       close_pack_fd(p);
        return -1;
 }
 
@@ -1074,11 +1125,8 @@ unsigned char *use_pack(struct packed_git *p,
                                        p->pack_name,
                                        strerror(errno));
                        if (!win->offset && win->len == p->pack_size
-                               && !p->do_not_close) {
-                               close(p->pack_fd);
-                               pack_open_fds--;
-                               p->pack_fd = -1;
-                       }
+                               && !p->do_not_close)
+                               close_pack_fd(p);
                        pack_mmap_calls++;
                        pack_open_windows++;
                        if (pack_mapped > peak_pack_mapped)
@@ -1458,7 +1506,10 @@ int git_open_noatime(const char *name)
        static int sha1_file_open_flag = O_NOATIME;
 
        for (;;) {
-               int fd = open(name, O_RDONLY | sha1_file_open_flag);
+               int fd;
+
+               errno = 0;
+               fd = open(name, O_RDONLY | sha1_file_open_flag);
                if (fd >= 0)
                        return fd;
 
@@ -1576,6 +1627,40 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma
        return git_inflate(stream, 0);
 }
 
+static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
+                                       unsigned long mapsize, void *buffer,
+                                       unsigned long bufsiz, struct strbuf *header)
+{
+       int status;
+
+       status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz);
+
+       /*
+        * Check if entire header is unpacked in the first iteration.
+        */
+       if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
+               return 0;
+
+       /*
+        * buffer[0..bufsiz] was not large enough.  Copy the partial
+        * result out to header, and then append the result of further
+        * reading the stream.
+        */
+       strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer);
+       stream->next_out = buffer;
+       stream->avail_out = bufsiz;
+
+       do {
+               status = git_inflate(stream, 0);
+               strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer);
+               if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
+                       return 0;
+               stream->next_out = buffer;
+               stream->avail_out = bufsiz;
+       } while (status != Z_STREAM_END);
+       return -1;
+}
+
 static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
 {
        int bytes = strlen(buffer) + 1;
@@ -1626,27 +1711,38 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
  * too permissive for what we want to check. So do an anal
  * object header parse by hand.
  */
-int parse_sha1_header(const char *hdr, unsigned long *sizep)
+static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
+                              unsigned int flags)
 {
-       char type[10];
-       int i;
+       const char *type_buf = hdr;
        unsigned long size;
+       int type, type_len = 0;
 
        /*
-        * The type can be at most ten bytes (including the
-        * terminating '\0' that we add), and is followed by
+        * The type can be of any size but is followed by
         * a space.
         */
-       i = 0;
        for (;;) {
                char c = *hdr++;
                if (c == ' ')
                        break;
-               type[i++] = c;
-               if (i >= sizeof(type))
-                       return -1;
+               type_len++;
        }
-       type[i] = 0;
+
+       type = type_from_string_gently(type_buf, type_len, 1);
+       if (oi->typename)
+               strbuf_add(oi->typename, type_buf, type_len);
+       /*
+        * Set type to 0 if its an unknown object and
+        * we're obtaining the type using '--allow-unkown-type'
+        * option.
+        */
+       if ((flags & LOOKUP_UNKNOWN_OBJECT) && (type < 0))
+               type = 0;
+       else if (type < 0)
+               die("invalid object type");
+       if (oi->typep)
+               *oi->typep = type;
 
        /*
         * The length must follow immediately, and be in canonical
@@ -1664,12 +1760,24 @@ int parse_sha1_header(const char *hdr, unsigned long *sizep)
                        size = size * 10 + c;
                }
        }
-       *sizep = size;
+
+       if (oi->sizep)
+               *oi->sizep = size;
 
        /*
         * The length must be followed by a zero byte
         */
-       return *hdr ? -1 : type_from_string(type);
+       return *hdr ? -1 : type;
+}
+
+int parse_sha1_header(const char *hdr, unsigned long *sizep)
+{
+       struct object_info oi;
+
+       oi.sizep = sizep;
+       oi.typename = NULL;
+       oi.typep = NULL;
+       return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT);
 }
 
 static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
@@ -2029,7 +2137,7 @@ static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
 {
        unsigned long hash;
 
-       hash = (unsigned long)p + (unsigned long)base_offset;
+       hash = (unsigned long)(intptr_t)p + (unsigned long)base_offset;
        hash += (hash >> 8) + (hash >> 16);
        return hash % MAX_DELTA_CACHE;
 }
@@ -2534,13 +2642,15 @@ struct packed_git *find_sha1_pack(const unsigned char *sha1,
 }
 
 static int sha1_loose_object_info(const unsigned char *sha1,
-                                 struct object_info *oi)
+                                 struct object_info *oi,
+                                 int flags)
 {
-       int status;
-       unsigned long mapsize, size;
+       int status = 0;
+       unsigned long mapsize;
        void *map;
        git_zstream stream;
        char hdr[32];
+       struct strbuf hdrbuf = STRBUF_INIT;
 
        if (oi->delta_base_sha1)
                hashclr(oi->delta_base_sha1);
@@ -2553,7 +2663,7 @@ static int sha1_loose_object_info(const unsigned char *sha1,
         * return value implicitly indicates whether the
         * object even exists.
         */
-       if (!oi->typep && !oi->sizep) {
+       if (!oi->typep && !oi->typename && !oi->sizep) {
                struct stat st;
                if (stat_sha1_file(sha1, &st) < 0)
                        return -1;
@@ -2567,17 +2677,26 @@ static int sha1_loose_object_info(const unsigned char *sha1,
                return -1;
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
-       if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+       if ((flags & LOOKUP_UNKNOWN_OBJECT)) {
+               if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
+                       status = error("unable to unpack %s header with --allow-unknown-type",
+                                      sha1_to_hex(sha1));
+       } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
                status = error("unable to unpack %s header",
                               sha1_to_hex(sha1));
-       else if ((status = parse_sha1_header(hdr, &size)) < 0)
+       if (status < 0)
+               ; /* Do nothing */
+       else if (hdrbuf.len) {
+               if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
+                       status = error("unable to parse %s header with --allow-unknown-type",
+                                      sha1_to_hex(sha1));
+       } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
                status = error("unable to parse %s header", sha1_to_hex(sha1));
-       else if (oi->sizep)
-               *oi->sizep = size;
        git_inflate_end(&stream);
        munmap(map, mapsize);
-       if (oi->typep)
+       if (status && oi->typep)
                *oi->typep = status;
+       strbuf_release(&hdrbuf);
        return 0;
 }
 
@@ -2586,6 +2705,7 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
        struct cached_object *co;
        struct pack_entry e;
        int rtype;
+       enum object_type real_type;
        const unsigned char *real = lookup_replace_object_extended(sha1, flags);
 
        co = find_cached_object(real);
@@ -2598,13 +2718,15 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                        *(oi->disk_sizep) = 0;
                if (oi->delta_base_sha1)
                        hashclr(oi->delta_base_sha1);
+               if (oi->typename)
+                       strbuf_addstr(oi->typename, typename(co->type));
                oi->whence = OI_CACHED;
                return 0;
        }
 
        if (!find_pack_entry(real, &e)) {
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(real, oi)) {
+               if (!sha1_loose_object_info(real, oi, flags)) {
                        oi->whence = OI_LOOSE;
                        return 0;
                }
@@ -2615,9 +2737,18 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                        return -1;
        }
 
+       /*
+        * packed_object_info() does not follow the delta chain to
+        * find out the real type, unless it is given oi->typep.
+        */
+       if (oi->typename && !oi->typep)
+               oi->typep = &real_type;
+
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
+               if (oi->typep == &real_type)
+                       oi->typep = NULL;
                return sha1_object_info_extended(real, oi, 0);
        } else if (in_delta_base_cache(e.p, e.offset)) {
                oi->whence = OI_DBCACHED;
@@ -2628,6 +2759,10 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
                oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
                                         rtype == OBJ_OFS_DELTA);
        }
+       if (oi->typename)
+               strbuf_addstr(oi->typename, typename(*oi->typep));
+       if (oi->typep == &real_type)
+               oi->typep = NULL;
 
        return 0;
 }
@@ -2821,11 +2956,8 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len,
 
 /*
  * Move the just written object into its final resting place.
- * NEEDSWORK: this should be renamed to finalize_temp_file() as
- * "moving" is only a part of what it does, when no patch between
- * master to pu changes the call sites of this function.
  */
-int move_temp_to_file(const char *tmpfile, const char *filename)
+int finalize_object_file(const char *tmpfile, const char *filename)
 {
        int ret = 0;
 
@@ -2998,7 +3130,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
                                tmp_file, strerror(errno));
        }
 
-       return move_temp_to_file(tmp_file, filename);
+       return finalize_object_file(tmp_file, filename);
 }
 
 static int freshen_loose_object(const unsigned char *sha1)
@@ -3496,14 +3628,19 @@ int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags)
 {
        struct packed_git *p;
        int r = 0;
+       int pack_errors = 0;
 
        prepare_packed_git();
        for (p = packed_git; p; p = p->next) {
                if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
                        continue;
+               if (open_pack_index(p)) {
+                       pack_errors = 1;
+                       continue;
+               }
                r = for_each_object_in_pack(p, cb, data);
                if (r)
                        break;
        }
-       return r;
+       return r ? r : pack_errors;
 }