usability: don't ask questions if no reply is required
[gitweb.git] / sha1_file.c
index ca1c90e5d33785d980f8e053089cf98970bb1b44..d77b915db699f6f58731f645d6bcc188843d9eb8 100644 (file)
 #include "mru.h"
 #include "list.h"
 #include "mergesort.h"
-
-#ifndef O_NOATIME
-#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
-#define O_NOATIME 01000000
-#else
-#define O_NOATIME 0
-#endif
-#endif
+#include "quote.h"
 
 #define SZ_FMT PRIuMAX
 static inline uintmax_t sz_fmt(size_t s) { return s; }
@@ -210,31 +203,26 @@ static const char *alt_sha1_path(struct alternate_object_database *alt,
        return buf->buf;
 }
 
-/*
- * Return the name of the pack or index file with the specified sha1
- * in its filename.  *base and *name are scratch space that must be
- * provided by the caller.  which should be "pack" or "idx".
- */
-static char *sha1_get_pack_name(const unsigned char *sha1,
-                               struct strbuf *buf,
-                               const char *which)
+ char *odb_pack_name(struct strbuf *buf,
+                    const unsigned char *sha1,
+                    const char *ext)
 {
        strbuf_reset(buf);
        strbuf_addf(buf, "%s/pack/pack-%s.%s", get_object_directory(),
-                   sha1_to_hex(sha1), which);
+                   sha1_to_hex(sha1), ext);
        return buf->buf;
 }
 
 char *sha1_pack_name(const unsigned char *sha1)
 {
        static struct strbuf buf = STRBUF_INIT;
-       return sha1_get_pack_name(sha1, &buf, "pack");
+       return odb_pack_name(&buf, sha1, "pack");
 }
 
 char *sha1_pack_index_name(const unsigned char *sha1)
 {
        static struct strbuf buf = STRBUF_INIT;
-       return sha1_get_pack_name(sha1, &buf, "idx");
+       return odb_pack_name(&buf, sha1, "idx");
 }
 
 struct alternate_object_database *alt_odb_list;
@@ -291,7 +279,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
        struct strbuf pathbuf = STRBUF_INIT;
 
        if (!is_absolute_path(entry) && relative_base) {
-               strbuf_addstr(&pathbuf, real_path(relative_base));
+               strbuf_realpath(&pathbuf, relative_base, 1);
                strbuf_addch(&pathbuf, '/');
        }
        strbuf_addstr(&pathbuf, entry);
@@ -329,13 +317,40 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
        return 0;
 }
 
+static const char *parse_alt_odb_entry(const char *string,
+                                      int sep,
+                                      struct strbuf *out)
+{
+       const char *end;
+
+       strbuf_reset(out);
+
+       if (*string == '#') {
+               /* comment; consume up to next separator */
+               end = strchrnul(string, sep);
+       } else if (*string == '"' && !unquote_c_style(out, string, &end)) {
+               /*
+                * quoted path; unquote_c_style has copied the
+                * data for us and set "end". Broken quoting (e.g.,
+                * an entry that doesn't end with a quote) falls
+                * back to the unquoted case below.
+                */
+       } else {
+               /* normal, unquoted path */
+               end = strchrnul(string, sep);
+               strbuf_add(out, string, end - string);
+       }
+
+       if (*end)
+               end++;
+       return end;
+}
+
 static void link_alt_odb_entries(const char *alt, int len, int sep,
                                 const char *relative_base, int depth)
 {
-       struct string_list entries = STRING_LIST_INIT_NODUP;
-       char *alt_copy;
-       int i;
        struct strbuf objdirbuf = STRBUF_INIT;
+       struct strbuf entry = STRBUF_INIT;
 
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
@@ -348,16 +363,13 @@ static void link_alt_odb_entries(const char *alt, int len, int sep,
                die("unable to normalize object directory: %s",
                    objdirbuf.buf);
 
-       alt_copy = xmemdupz(alt, len);
-       string_list_split_in_place(&entries, alt_copy, sep, -1);
-       for (i = 0; i < entries.nr; i++) {
-               const char *entry = entries.items[i].string;
-               if (entry[0] == '\0' || entry[0] == '#')
+       while (*alt) {
+               alt = parse_alt_odb_entry(alt, sep, &entry);
+               if (!entry.len)
                        continue;
-               link_alt_odb_entry(entry, relative_base, depth, objdirbuf.buf);
+               link_alt_odb_entry(entry.buf, relative_base, depth, objdirbuf.buf);
        }
-       string_list_clear(&entries, 0);
-       free(alt_copy);
+       strbuf_release(&entry);
        strbuf_release(&objdirbuf);
 }
 
@@ -1586,31 +1598,31 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
        return hashcmp(sha1, real_sha1) ? -1 : 0;
 }
 
-int git_open(const char *name)
+int git_open_cloexec(const char *name, int flags)
 {
-       static int sha1_file_open_flag = O_NOATIME | O_CLOEXEC;
-
-       for (;;) {
-               int fd;
-
-               errno = 0;
-               fd = open(name, O_RDONLY | sha1_file_open_flag);
-               if (fd >= 0)
-                       return fd;
+       int fd;
+       static int o_cloexec = O_CLOEXEC;
 
+       fd = open(name, flags | o_cloexec);
+       if ((o_cloexec & O_CLOEXEC) && fd < 0 && errno == EINVAL) {
                /* Try again w/o O_CLOEXEC: the kernel might not support it */
-               if ((sha1_file_open_flag & O_CLOEXEC) && errno == EINVAL) {
-                       sha1_file_open_flag &= ~O_CLOEXEC;
-                       continue;
-               }
+               o_cloexec &= ~O_CLOEXEC;
+               fd = open(name, flags | o_cloexec);
+       }
 
-               /* Might the failure be due to O_NOATIME? */
-               if (errno != ENOENT && (sha1_file_open_flag & O_NOATIME)) {
-                       sha1_file_open_flag &= ~O_NOATIME;
-                       continue;
+#if defined(F_GETFL) && defined(F_SETFL) && defined(FD_CLOEXEC)
+       {
+               static int fd_cloexec = FD_CLOEXEC;
+
+               if (!o_cloexec && 0 <= fd && fd_cloexec) {
+                       /* Opened w/o O_CLOEXEC?  try with fcntl(2) to add it */
+                       int flags = fcntl(fd, F_GETFL);
+                       if (fcntl(fd, F_SETFL, flags | fd_cloexec))
+                               fd_cloexec = 0;
                }
-               return -1;
        }
+#endif
+       return fd;
 }
 
 /*
@@ -2354,11 +2366,10 @@ static inline void release_delta_base_cache(struct delta_base_cache_entry *ent)
 
 void clear_delta_base_cache(void)
 {
-       struct hashmap_iter iter;
-       struct delta_base_cache_entry *entry;
-       for (entry = hashmap_iter_first(&delta_base_cache, &iter);
-            entry;
-            entry = hashmap_iter_next(&iter)) {
+       struct list_head *lru, *tmp;
+       list_for_each_safe(lru, tmp, &delta_base_cache_lru) {
+               struct delta_base_cache_entry *entry =
+                       list_entry(lru, struct delta_base_cache_entry, lru);
                release_delta_base_cache(entry);
        }
 }
@@ -2516,6 +2527,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        while (delta_stack_nr) {
                void *delta_data;
                void *base = data;
+               void *external_base = NULL;
                unsigned long delta_size, base_size = size;
                int i;
 
@@ -2542,6 +2554,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                                      p->pack_name);
                                mark_bad_packed_object(p, base_sha1);
                                base = read_object(base_sha1, &type, &base_size);
+                               external_base = base;
                        }
                }
 
@@ -2560,6 +2573,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                              "at offset %"PRIuMAX" from %s",
                              (uintmax_t)curpos, p->pack_name);
                        data = NULL;
+                       free(external_base);
                        continue;
                }
 
@@ -2579,6 +2593,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                        error("failed to apply delta");
 
                free(delta_data);
+               free(external_base);
        }
 
        *final_type = type;
@@ -3847,6 +3862,11 @@ static int check_stream_sha1(git_zstream *stream,
                error("corrupt loose object '%s'", sha1_to_hex(expected_sha1));
                return -1;
        }
+       if (stream->avail_in) {
+               error("garbage at end of loose object '%s'",
+                     sha1_to_hex(expected_sha1));
+               return -1;
+       }
 
        git_SHA1_Final(real_sha1, &c);
        if (hashcmp(expected_sha1, real_sha1)) {