write_shared_index(): use tempfile module
[gitweb.git] / read-cache.c
index 36ff89f29e5f56a5b3dcfd803f12cd139295b8b8..89be2268cd39fc87983b2bb66597e968f76e32cd 100644 (file)
@@ -5,6 +5,7 @@
  */
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "tempfile.h"
 #include "lockfile.h"
 #include "cache-tree.h"
 #include "refs.h"
@@ -39,11 +40,12 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 #define CACHE_EXT_TREE 0x54524545      /* "TREE" */
 #define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */
 #define CACHE_EXT_LINK 0x6c696e6b        /* "link" */
+#define CACHE_EXT_UNTRACKED 0x554E5452   /* "UNTR" */
 
 /* changes that can be kept in $GIT_DIR/index (basically all extensions) */
 #define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
                 CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
-                SPLIT_INDEX_ORDERED)
+                SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED)
 
 struct index_state the_index;
 static const char *alternate_index_output;
@@ -79,6 +81,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
        memcpy(new->name, new_name, namelen + 1);
 
        cache_tree_invalidate_path(istate, old->name);
+       untracked_cache_remove_from_index(istate, old->name);
        remove_index_entry_at(istate, nr);
        add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 }
@@ -270,20 +273,34 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
        return changed;
 }
 
-static int is_racy_timestamp(const struct index_state *istate,
-                            const struct cache_entry *ce)
+static int is_racy_stat(const struct index_state *istate,
+                       const struct stat_data *sd)
 {
-       return (!S_ISGITLINK(ce->ce_mode) &&
-               istate->timestamp.sec &&
+       return (istate->timestamp.sec &&
 #ifdef USE_NSEC
                 /* nanosecond timestamped files can also be racy! */
-               (istate->timestamp.sec < ce->ce_stat_data.sd_mtime.sec ||
-                (istate->timestamp.sec == ce->ce_stat_data.sd_mtime.sec &&
-                 istate->timestamp.nsec <= ce->ce_stat_data.sd_mtime.nsec))
+               (istate->timestamp.sec < sd->sd_mtime.sec ||
+                (istate->timestamp.sec == sd->sd_mtime.sec &&
+                 istate->timestamp.nsec <= sd->sd_mtime.nsec))
 #else
-               istate->timestamp.sec <= ce->ce_stat_data.sd_mtime.sec
+               istate->timestamp.sec <= sd->sd_mtime.sec
 #endif
-                );
+               );
+}
+
+static int is_racy_timestamp(const struct index_state *istate,
+                            const struct cache_entry *ce)
+{
+       return (!S_ISGITLINK(ce->ce_mode) &&
+               is_racy_stat(istate, &ce->ce_stat_data));
+}
+
+int match_stat_data_racy(const struct index_state *istate,
+                        const struct stat_data *sd, struct stat *st)
+{
+       if (is_racy_stat(istate, sd))
+               return MTIME_CHANGED;
+       return match_stat_data(sd, st);
 }
 
 int ie_match_stat(const struct index_state *istate,
@@ -538,6 +555,7 @@ int remove_file_from_index(struct index_state *istate, const char *path)
        if (pos < 0)
                pos = -pos-1;
        cache_tree_invalidate_path(istate, path);
+       untracked_cache_remove_from_index(istate, path);
        while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path))
                remove_index_entry_at(istate, pos);
        return 0;
@@ -982,6 +1000,8 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
        }
        pos = -pos-1;
 
+       untracked_cache_add_to_index(istate, ce->name);
+
        /*
         * Inserting a merged entry ("stage 0") into the index
         * will always replace all non-merged entries..
@@ -1372,6 +1392,9 @@ static int read_index_extension(struct index_state *istate,
                if (read_link_extension(istate, data, sz))
                        return -1;
                break;
+       case CACHE_EXT_UNTRACKED:
+               istate->untracked = read_untracked_extension(data, sz);
+               break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
                        return error("index uses %.4s extension, which we do not understand",
@@ -1667,6 +1690,8 @@ int discard_index(struct index_state *istate)
        istate->cache = NULL;
        istate->cache_alloc = 0;
        discard_split_index(istate);
+       free_untracked_cache(istate->untracked);
+       istate->untracked = NULL;
        return 0;
 }
 
@@ -2053,6 +2078,17 @@ static int do_write_index(struct index_state *istate, int newfd,
                if (err)
                        return -1;
        }
+       if (!strip_extensions && istate->untracked) {
+               struct strbuf sb = STRBUF_INIT;
+
+               write_untracked_extension(&sb, istate->untracked);
+               err = write_index_ext_header(&c, newfd, CACHE_EXT_UNTRACKED,
+                                            sb.len) < 0 ||
+                       ce_write(&c, newfd, sb.buf, sb.len) < 0;
+               strbuf_release(&sb);
+               if (err)
+                       return -1;
+       }
 
        if (ce_flush(&c, newfd, istate->sha1) || fstat(newfd, &st))
                return -1;
@@ -2077,7 +2113,7 @@ static int commit_locked_index(struct lock_file *lk)
 static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
 {
-       int ret = do_write_index(istate, lock->fd, 0);
+       int ret = do_write_index(istate, get_lock_file_fd(lock), 0);
        if (ret)
                return ret;
        assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
@@ -2101,54 +2137,27 @@ static int write_split_index(struct index_state *istate,
        return ret;
 }
 
-static char *temporary_sharedindex;
-
-static void remove_temporary_sharedindex(void)
-{
-       if (temporary_sharedindex) {
-               unlink_or_warn(temporary_sharedindex);
-               free(temporary_sharedindex);
-               temporary_sharedindex = NULL;
-       }
-}
-
-static void remove_temporary_sharedindex_on_signal(int signo)
-{
-       remove_temporary_sharedindex();
-       sigchain_pop(signo);
-       raise(signo);
-}
+static struct tempfile temporary_sharedindex;
 
 static int write_shared_index(struct index_state *istate,
                              struct lock_file *lock, unsigned flags)
 {
        struct split_index *si = istate->split_index;
-       static int installed_handler;
        int fd, ret;
 
-       temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
-       fd = mkstemp(temporary_sharedindex);
+       fd = mks_tempfile(&temporary_sharedindex, git_path("sharedindex_XXXXXX"));
        if (fd < 0) {
-               free(temporary_sharedindex);
-               temporary_sharedindex = NULL;
                hashclr(si->base_sha1);
                return do_write_locked_index(istate, lock, flags);
        }
-       if (!installed_handler) {
-               atexit(remove_temporary_sharedindex);
-               sigchain_push_common(remove_temporary_sharedindex_on_signal);
-       }
        move_cache_to_base_index(istate);
        ret = do_write_index(si->base, fd, 1);
-       close(fd);
        if (ret) {
-               remove_temporary_sharedindex();
+               delete_tempfile(&temporary_sharedindex);
                return ret;
        }
-       ret = rename(temporary_sharedindex,
-                    git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
-       free(temporary_sharedindex);
-       temporary_sharedindex = NULL;
+       ret = rename_tempfile(&temporary_sharedindex,
+                             git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret)
                hashcpy(si->base_sha1, si->base->sha1);
        return ret;