read-cache.c 6.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 */
6
#include <stdarg.h>
7 8 9 10 11
#include "cache.h"

struct cache_entry **active_cache = NULL;
unsigned int active_nr = 0, active_alloc = 0;

12 13 14 15
int cache_match_stat(struct cache_entry *ce, struct stat *st)
{
	unsigned int changed = 0;

16
	if (ce->ce_mtime.sec != htonl(st->st_mtime))
17
		changed |= MTIME_CHANGED;
18 19 20
	if (ce->ce_ctime.sec != htonl(st->st_ctime))
		changed |= CTIME_CHANGED;

21
#ifdef NSEC
22 23 24 25 26 27 28 29
	/*
	 * nsec seems unreliable - not all filesystems support it, so
	 * as long as it is in the inode cache you get right nsec
	 * but after it gets flushed, you get zero nsec.
	 */
	if (ce->ce_mtime.nsec != htonl(st->st_mtim.tv_nsec)
		changed |= MTIME_CHANGED;
	if (ce->ce_ctime.nsec != htonl(st->st_ctim.tv_nsec)
30
		changed |= CTIME_CHANGED;
31 32 33 34
#endif	

	if (ce->ce_uid != htonl(st->st_uid) ||
	    ce->ce_gid != htonl(st->st_gid))
35
		changed |= OWNER_CHANGED;
36
	/* We consider only the owner x bit to be relevant for "mode changes" */
37
	if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))
38
		changed |= MODE_CHANGED;
39 40
	if (ce->ce_dev != htonl(st->st_dev) ||
	    ce->ce_ino != htonl(st->st_ino))
41
		changed |= INODE_CHANGED;
42
	if (ce->ce_size != htonl(st->st_size))
43 44 45 46
		changed |= DATA_CHANGED;
	return changed;
}

47
int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2)
48
{
49 50
	int len1 = flags1 & CE_NAMEMASK;
	int len2 = flags2 & CE_NAMEMASK;
51 52 53 54 55 56 57 58 59 60
	int len = len1 < len2 ? len1 : len2;
	int cmp;

	cmp = memcmp(name1, name2, len);
	if (cmp)
		return cmp;
	if (len1 < len2)
		return -1;
	if (len1 > len2)
		return 1;
61 62 63 64
	if (flags1 < flags2)
		return -1;
	if (flags1 > flags2)
		return 1;
65 66 67 68 69 70 71 72 73 74 75 76
	return 0;
}

int cache_name_pos(const char *name, int namelen)
{
	int first, last;

	first = 0;
	last = active_nr;
	while (last > first) {
		int next = (last + first) >> 1;
		struct cache_entry *ce = active_cache[next];
77
		int cmp = cache_name_compare(name, namelen, ce->name, htons(ce->ce_flags));
78
		if (!cmp)
79
			return next;
80 81 82 83 84 85
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
86
	return -first-1;
87 88
}

89 90 91 92 93 94 95 96 97 98
/* Remove entry, return true if there are more entries to go.. */
static int remove_entry_at(int pos)
{
	active_nr--;
	if (pos >= active_nr)
		return 0;
	memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *));
	return 1;
}

99 100 101
int remove_file_from_cache(char *path)
{
	int pos = cache_name_pos(path, strlen(path));
102 103 104
	if (pos < 0)
		pos = -pos-1;
	while (pos < active_nr && !strcmp(active_cache[pos]->name, path))
105
		remove_entry_at(pos);
106 107 108
	return 0;
}

109 110 111 112 113 114
static int same_name(struct cache_entry *a, struct cache_entry *b)
{
	int len = ce_namelen(a);
	return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
}

115
int add_cache_entry(struct cache_entry *ce, int ok_to_add)
116 117 118
{
	int pos;

119
	pos = cache_name_pos(ce->name, htons(ce->ce_flags));
120 121

	/* existing match? Just replace it */
122 123
	if (pos >= 0) {
		active_cache[pos] = ce;
124 125
		return 0;
	}
126
	pos = -pos-1;
127

128 129 130 131 132 133 134 135 136 137 138 139
	/*
	 * Inserting a merged entry ("stage 0") into the index
	 * will always replace all non-merged entries..
	 */
	if (pos < active_nr && ce_stage(ce) == 0) {
		while (same_name(active_cache[pos], ce)) {
			ok_to_add = 1;
			if (!remove_entry_at(pos))
				break;
		}
	}

140 141 142
	if (!ok_to_add)
		return -1;

143 144 145 146 147 148 149 150 151 152 153 154 155 156
	/* Make sure the array is big enough .. */
	if (active_nr == active_alloc) {
		active_alloc = alloc_nr(active_alloc);
		active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
	}

	/* Add it in.. */
	active_nr++;
	if (active_nr > pos)
		memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
	active_cache[pos] = ce;
	return 0;
}

157 158 159 160 161
static int verify_hdr(struct cache_header *hdr, unsigned long size)
{
	SHA_CTX c;
	unsigned char sha1[20];

162
	if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
163
		return error("bad signature");
164
	if (hdr->hdr_version != htonl(1))
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
		return error("bad version");
	SHA1_Init(&c);
	SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
	SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
	SHA1_Final(sha1, &c);
	if (memcmp(sha1, hdr->sha1, 20))
		return error("bad header sha1");
	return 0;
}

int read_cache(void)
{
	int fd, i;
	struct stat st;
	unsigned long size, offset;
	void *map;
	struct cache_header *hdr;

	errno = EBUSY;
	if (active_cache)
		return error("more than one cachefile");
	errno = ENOENT;
	sha1_file_directory = getenv(DB_ENVIRONMENT);
	if (!sha1_file_directory)
		sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
	if (access(sha1_file_directory, X_OK) < 0)
		return error("no access to SHA1 file directory");
192
	fd = open(".git/index", O_RDONLY);
193 194 195
	if (fd < 0)
		return (errno == ENOENT) ? 0 : error("open failed");

196
	size = 0; // avoid gcc warning
197 198 199 200
	map = (void *)-1;
	if (!fstat(fd, &st)) {
		size = st.st_size;
		errno = EINVAL;
201
		if (size >= sizeof(struct cache_header))
202 203 204 205 206 207 208 209 210 211
			map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
	}
	close(fd);
	if (-1 == (int)(long)map)
		return error("mmap failed");

	hdr = map;
	if (verify_hdr(hdr, size) < 0)
		goto unmap;

212
	active_nr = ntohl(hdr->hdr_entries);
213 214 215 216
	active_alloc = alloc_nr(active_nr);
	active_cache = calloc(active_alloc, sizeof(struct cache_entry *));

	offset = sizeof(*hdr);
217
	for (i = 0; i < active_nr; i++) {
218 219 220 221 222 223 224 225 226 227 228 229
		struct cache_entry *ce = map + offset;
		offset = offset + ce_size(ce);
		active_cache[i] = ce;
	}
	return active_nr;

unmap:
	munmap(map, size);
	errno = EINVAL;
	return error("verify header failed");
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
#define WRITE_BUFFER_SIZE 8192
static char write_buffer[WRITE_BUFFER_SIZE];
static unsigned long write_buffer_len;

static int ce_write(int fd, void *data, unsigned int len)
{
	while (len) {
		unsigned int buffered = write_buffer_len;
		unsigned int partial = WRITE_BUFFER_SIZE - buffered;
		if (partial > len)
			partial = len;
		memcpy(write_buffer + buffered, data, partial);
		buffered += partial;
		if (buffered == WRITE_BUFFER_SIZE) {
			if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
				return -1;
			buffered = 0;
		}
		write_buffer_len = buffered;
		len -= partial;
		data += partial;
 	}
 	return 0;
}

static int ce_flush(int fd)
{
	unsigned int left = write_buffer_len;
	if (left) {
		write_buffer_len = 0;
		if (write(fd, write_buffer, left) != left)
			return -1;
	}
	return 0;
}

266 267 268 269 270 271
int write_cache(int newfd, struct cache_entry **cache, int entries)
{
	SHA_CTX c;
	struct cache_header hdr;
	int i;

272 273 274
	hdr.hdr_signature = htonl(CACHE_SIGNATURE);
	hdr.hdr_version = htonl(1);
	hdr.hdr_entries = htonl(entries);
275 276 277 278 279 280 281 282 283 284

	SHA1_Init(&c);
	SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
	for (i = 0; i < entries; i++) {
		struct cache_entry *ce = cache[i];
		int size = ce_size(ce);
		SHA1_Update(&c, ce, size);
	}
	SHA1_Final(hdr.sha1, &c);

285
	if (ce_write(newfd, &hdr, sizeof(hdr)) < 0)
286 287 288 289
		return -1;

	for (i = 0; i < entries; i++) {
		struct cache_entry *ce = cache[i];
290
		if (ce_write(newfd, ce, ce_size(ce)) < 0)
291 292
			return -1;
	}
293
	return ce_flush(newfd);
294
}