summaryrefslogtreecommitdiff
path: root/read-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'read-cache.c')
-rw-r--r--read-cache.c137
1 files changed, 113 insertions, 24 deletions
diff --git a/read-cache.c b/read-cache.c
index 967f483f78..22a814311d 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -8,6 +8,12 @@
#include "cache-tree.h"
#include "refs.h"
#include "dir.h"
+#include "tree.h"
+#include "commit.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "blob.h"
/* Index extensions.
*
@@ -154,7 +160,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
return 0;
}
-static int is_empty_blob_sha1(const unsigned char *sha1)
+int is_empty_blob_sha1(const unsigned char *sha1)
{
static const unsigned char empty_blob_sha1[20] = {
0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
@@ -506,6 +512,14 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
return new;
}
+static void record_intent_to_add(struct cache_entry *ce)
+{
+ unsigned char sha1[20];
+ if (write_sha1_file("", 0, blob_type, sha1))
+ die("cannot create an empty blob in the object database");
+ hashcpy(ce->sha1, sha1);
+}
+
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
{
int size, namelen, was_same;
@@ -514,6 +528,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
int pretend = flags & ADD_CACHE_PRETEND;
+ int intent_only = flags & ADD_CACHE_INTENT;
+ int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
+ (intent_only ? ADD_CACHE_NEW_ONLY : 0));
if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
return error("%s: can only add regular files, symbolic links or git-directories", path);
@@ -527,7 +544,8 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
ce = xcalloc(1, size);
memcpy(ce->name, path, namelen);
ce->ce_flags = namelen;
- fill_stat_cache_info(ce, st);
+ if (!intent_only)
+ fill_stat_cache_info(ce, st);
if (trust_executable_bit && has_symlinks)
ce->ce_mode = create_ce_mode(st_mode);
@@ -550,8 +568,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
alias->ce_flags |= CE_ADDED;
return 0;
}
- if (index_path(ce->sha1, path, st, 1))
- return error("unable to index file %s", path);
+ if (!intent_only) {
+ if (index_path(ce->sha1, path, st, 1))
+ return error("unable to index file %s", path);
+ } else
+ record_intent_to_add(ce);
+
if (ignore_case && alias && different_name(ce, alias))
ce = create_alias_ce(ce, alias);
ce->ce_flags |= CE_ADDED;
@@ -564,7 +586,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
if (pretend)
;
- else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+ else if (add_index_entry(istate, ce, add_option))
return error("unable to add %s to index",path);
if (verbose && !was_same)
printf("add '%s'\n", path);
@@ -586,8 +608,10 @@ struct cache_entry *make_cache_entry(unsigned int mode,
int size, len;
struct cache_entry *ce;
- if (!verify_path(path))
+ if (!verify_path(path)) {
+ error("Invalid path '%s'", path);
return NULL;
+ }
len = strlen(path);
size = cache_entry_size(len);
@@ -843,13 +867,15 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
+ int new_only = option & ADD_CACHE_NEW_ONLY;
cache_tree_invalidate_path(istate->cache_tree, ce->name);
pos = index_name_pos(istate, ce->name, ce->ce_flags);
/* existing match? Just replace it. */
if (pos >= 0) {
- replace_index_entry(istate, pos, ce);
+ if (!new_only)
+ replace_index_entry(istate, pos, ce);
return 0;
}
pos = -pos-1;
@@ -869,7 +895,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
if (!ok_to_add)
return -1;
if (!verify_path(ce->name))
- return -1;
+ return error("Invalid path '%s'", ce->name);
if (!skip_df_check &&
check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
@@ -1067,16 +1093,16 @@ struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
static int verify_hdr(struct cache_header *hdr, unsigned long size)
{
- SHA_CTX c;
+ git_SHA_CTX c;
unsigned char sha1[20];
if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
return error("bad signature");
if (hdr->hdr_version != htonl(2))
return error("bad index version");
- SHA1_Init(&c);
- SHA1_Update(&c, hdr, size - 20);
- SHA1_Final(sha1, &c);
+ git_SHA1_Init(&c);
+ git_SHA1_Update(&c, hdr, size - 20);
+ git_SHA1_Final(sha1, &c);
if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
return error("bad index file sha1 signature");
return 0;
@@ -1118,6 +1144,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
ce->ce_size = ntohl(ondisk->size);
/* On-disk flags are just 16 bits */
ce->ce_flags = ntohs(ondisk->flags);
+
+ /* For future extension: we do not understand this entry yet */
+ if (ce->ce_flags & CE_EXTENDED)
+ die("Unknown index entry format");
hashcpy(ce->sha1, ondisk->sha1);
len = ce->ce_flags & CE_NAMEMASK;
@@ -1239,6 +1269,11 @@ unmap:
die("index file corrupt");
}
+int is_index_unborn(struct index_state *istate)
+{
+ return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
+}
+
int discard_index(struct index_state *istate)
{
istate->cache_nr = 0;
@@ -1269,11 +1304,11 @@ int unmerged_index(const struct index_state *istate)
static unsigned char write_buffer[WRITE_BUFFER_SIZE];
static unsigned long write_buffer_len;
-static int ce_write_flush(SHA_CTX *context, int fd)
+static int ce_write_flush(git_SHA_CTX *context, int fd)
{
unsigned int buffered = write_buffer_len;
if (buffered) {
- SHA1_Update(context, write_buffer, buffered);
+ git_SHA1_Update(context, write_buffer, buffered);
if (write_in_full(fd, write_buffer, buffered) != buffered)
return -1;
write_buffer_len = 0;
@@ -1281,7 +1316,7 @@ static int ce_write_flush(SHA_CTX *context, int fd)
return 0;
}
-static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
+static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
{
while (len) {
unsigned int buffered = write_buffer_len;
@@ -1303,7 +1338,7 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
return 0;
}
-static int write_index_ext_header(SHA_CTX *context, int fd,
+static int write_index_ext_header(git_SHA_CTX *context, int fd,
unsigned int ext, unsigned int sz)
{
ext = htonl(ext);
@@ -1312,13 +1347,13 @@ static int write_index_ext_header(SHA_CTX *context, int fd,
(ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
}
-static int ce_flush(SHA_CTX *context, int fd)
+static int ce_flush(git_SHA_CTX *context, int fd)
{
unsigned int left = write_buffer_len;
if (left) {
write_buffer_len = 0;
- SHA1_Update(context, write_buffer, left);
+ git_SHA1_Update(context, write_buffer, left);
}
/* Flush first if not enough space for SHA1 signature */
@@ -1329,7 +1364,7 @@ static int ce_flush(SHA_CTX *context, int fd)
}
/* Append the SHA1 signature at the end */
- SHA1_Final(write_buffer + left, context);
+ git_SHA1_Final(write_buffer + left, context);
left += 20;
return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
}
@@ -1383,7 +1418,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
}
}
-static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
+static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
{
int size = ondisk_ce_size(ce);
struct ondisk_cache_entry *ondisk = xcalloc(1, size);
@@ -1407,7 +1442,7 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
int write_index(const struct index_state *istate, int newfd)
{
- SHA_CTX c;
+ git_SHA_CTX c;
struct cache_header hdr;
int i, err, removed;
struct cache_entry **cache = istate->cache;
@@ -1421,7 +1456,7 @@ int write_index(const struct index_state *istate, int newfd)
hdr.hdr_version = htonl(2);
hdr.hdr_entries = htonl(entries - removed);
- SHA1_Init(&c);
+ git_SHA1_Init(&c);
if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
return -1;
@@ -1437,9 +1472,8 @@ int write_index(const struct index_state *istate, int newfd)
/* Write extension data here */
if (istate->cache_tree) {
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
- strbuf_init(&sb, 0);
cache_tree_write(&sb, istate->cache_tree);
err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
|| ce_write(&c, newfd, sb.buf, sb.len) < 0;
@@ -1486,6 +1520,61 @@ int read_index_unmerged(struct index_state *istate)
return unmerged;
}
+struct update_callback_data
+{
+ int flags;
+ int add_errors;
+};
+
+static void update_callback(struct diff_queue_struct *q,
+ struct diff_options *opt, void *cbdata)
+{
+ int i;
+ struct update_callback_data *data = cbdata;
+
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ const char *path = p->one->path;
+ switch (p->status) {
+ default:
+ die("unexpected diff status %c", p->status);
+ case DIFF_STATUS_UNMERGED:
+ case DIFF_STATUS_MODIFIED:
+ case DIFF_STATUS_TYPE_CHANGED:
+ if (add_file_to_index(&the_index, path, data->flags)) {
+ if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
+ die("updating files failed");
+ data->add_errors++;
+ }
+ break;
+ case DIFF_STATUS_DELETED:
+ if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
+ break;
+ if (!(data->flags & ADD_CACHE_PRETEND))
+ remove_file_from_index(&the_index, path);
+ if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
+ printf("remove '%s'\n", path);
+ break;
+ }
+ }
+}
+
+int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
+{
+ struct update_callback_data data;
+ struct rev_info rev;
+ init_revisions(&rev, prefix);
+ setup_revisions(0, NULL, &rev, NULL);
+ rev.prune_data = pathspec;
+ rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = update_callback;
+ data.flags = flags;
+ data.add_errors = 0;
+ rev.diffopt.format_callback_data = &data;
+ run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+ return !!data.add_errors;
+}
+
/*
* Returns 1 if the path is an "other" path with respect to
* the index; that is, the path is not mentioned in the index at all,