untracked cache: load from UNTR index extension

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Mar 8, 2015 at 17:12 UTC f9e6c649589e0940ccb82821107fb658277ed86b
3 files changed +226
dir.c
+219
@@ -2283,3 +2283,222 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
2283 strbuf_release(&wd.sb_stat);
2284 strbuf_release(&wd.sb_sha1);
2285 }
2286 +
2287 +static void free_untracked(struct untracked_cache_dir *ucd)
2288 +{
2289 + int i;
2290 + if (!ucd)
2291 + return;
2292 + for (i = 0; i < ucd->dirs_nr; i++)
2293 + free_untracked(ucd->dirs[i]);
2294 + for (i = 0; i < ucd->untracked_nr; i++)
2295 + free(ucd->untracked[i]);
2296 + free(ucd->untracked);
2297 + free(ucd->dirs);
2298 + free(ucd);
2299 +}
2300 +
2301 +void free_untracked_cache(struct untracked_cache *uc)
2302 +{
2303 + if (uc)
2304 + free_untracked(uc->root);
2305 + free(uc);
2306 +}
2307 +
2308 +struct read_data {
2309 + int index;
2310 + struct untracked_cache_dir **ucd;
2311 + struct ewah_bitmap *check_only;
2312 + struct ewah_bitmap *valid;
2313 + struct ewah_bitmap *sha1_valid;
2314 + const unsigned char *data;
2315 + const unsigned char *end;
2316 +};
2317 +
2318 +static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from)
2319 +{
2320 + to->sd_ctime.sec = get_be32(&from->sd_ctime.sec);
2321 + to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec);
2322 + to->sd_mtime.sec = get_be32(&from->sd_mtime.sec);
2323 + to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec);
2324 + to->sd_dev = get_be32(&from->sd_dev);
2325 + to->sd_ino = get_be32(&from->sd_ino);
2326 + to->sd_uid = get_be32(&from->sd_uid);
2327 + to->sd_gid = get_be32(&from->sd_gid);
2328 + to->sd_size = get_be32(&from->sd_size);
2329 +}
2330 +
2331 +static int read_one_dir(struct untracked_cache_dir **untracked_,
2332 + struct read_data *rd)
2333 +{
2334 + struct untracked_cache_dir ud, *untracked;
2335 + const unsigned char *next, *data = rd->data, *end = rd->end;
2336 + unsigned int value;
2337 + int i, len;
2338 +
2339 + memset(&ud, 0, sizeof(ud));
2340 +
2341 + next = data;
2342 + value = decode_varint(&next);
2343 + if (next > end)
2344 + return -1;
2345 + ud.recurse = 1;
2346 + ud.untracked_alloc = value;
2347 + ud.untracked_nr = value;
2348 + if (ud.untracked_nr)
2349 + ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);
2350 + data = next;
2351 +
2352 + next = data;
2353 + ud.dirs_alloc = ud.dirs_nr = decode_varint(&next);
2354 + if (next > end)
2355 + return -1;
2356 + ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);
2357 + data = next;
2358 +
2359 + len = strlen((const char *)data);
2360 + next = data + len + 1;
2361 + if (next > rd->end)
2362 + return -1;
2363 + *untracked_ = untracked = xmalloc(sizeof(*untracked) + len);
2364 + memcpy(untracked, &ud, sizeof(ud));
2365 + memcpy(untracked->name, data, len + 1);
2366 + data = next;
2367 +
2368 + for (i = 0; i < untracked->untracked_nr; i++) {
2369 + len = strlen((const char *)data);
2370 + next = data + len + 1;
2371 + if (next > rd->end)
2372 + return -1;
2373 + untracked->untracked[i] = xstrdup((const char*)data);
2374 + data = next;
2375 + }
2376 +
2377 + rd->ucd[rd->index++] = untracked;
2378 + rd->data = data;
2379 +
2380 + for (i = 0; i < untracked->dirs_nr; i++) {
2381 + len = read_one_dir(untracked->dirs + i, rd);
2382 + if (len < 0)
2383 + return -1;
2384 + }
2385 + return 0;
2386 +}
2387 +
2388 +static void set_check_only(size_t pos, void *cb)
2389 +{
2390 + struct read_data *rd = cb;
2391 + struct untracked_cache_dir *ud = rd->ucd[pos];
2392 + ud->check_only = 1;
2393 +}
2394 +
2395 +static void read_stat(size_t pos, void *cb)
2396 +{
2397 + struct read_data *rd = cb;
2398 + struct untracked_cache_dir *ud = rd->ucd[pos];
2399 + if (rd->data + sizeof(struct stat_data) > rd->end) {
2400 + rd->data = rd->end + 1;
2401 + return;
2402 + }
2403 + stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data);
2404 + rd->data += sizeof(struct stat_data);
2405 + ud->valid = 1;
2406 +}
2407 +
2408 +static void read_sha1(size_t pos, void *cb)
2409 +{
2410 + struct read_data *rd = cb;
2411 + struct untracked_cache_dir *ud = rd->ucd[pos];
2412 + if (rd->data + 20 > rd->end) {
2413 + rd->data = rd->end + 1;
2414 + return;
2415 + }
2416 + hashcpy(ud->exclude_sha1, rd->data);
2417 + rd->data += 20;
2418 +}
2419 +
2420 +static void load_sha1_stat(struct sha1_stat *sha1_stat,
2421 + const struct stat_data *stat,
2422 + const unsigned char *sha1)
2423 +{
2424 + stat_data_from_disk(&sha1_stat->stat, stat);
2425 + hashcpy(sha1_stat->sha1, sha1);
2426 + sha1_stat->valid = 1;
2427 +}
2428 +
2429 +struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
2430 +{
2431 + const struct ondisk_untracked_cache *ouc;
2432 + struct untracked_cache *uc;
2433 + struct read_data rd;
2434 + const unsigned char *next = data, *end = (const unsigned char *)data + sz;
2435 + int len;
2436 +
2437 + if (sz <= 1 || end[-1] != '\0')
2438 + return NULL;
2439 + end--;
2440 +
2441 + ouc = (const struct ondisk_untracked_cache *)next;
2442 + if (next + ouc_size(0) > end)
2443 + return NULL;
2444 +
2445 + uc = xcalloc(1, sizeof(*uc));
2446 + load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
2447 + ouc->info_exclude_sha1);
2448 + load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
2449 + ouc->excludes_file_sha1);
2450 + uc->dir_flags = get_be32(&ouc->dir_flags);
2451 + uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
2452 + /* NUL after exclude_per_dir is covered by sizeof(*ouc) */
2453 + next += ouc_size(strlen(ouc->exclude_per_dir));
2454 + if (next >= end)
2455 + goto done2;
2456 +
2457 + len = decode_varint(&next);
2458 + if (next > end || len == 0)
2459 + goto done2;
2460 +
2461 + rd.valid = ewah_new();
2462 + rd.check_only = ewah_new();
2463 + rd.sha1_valid = ewah_new();
2464 + rd.data = next;
2465 + rd.end = end;
2466 + rd.index = 0;
2467 + rd.ucd = xmalloc(sizeof(*rd.ucd) * len);
2468 +
2469 + if (read_one_dir(&uc->root, &rd) || rd.index != len)
2470 + goto done;
2471 +
2472 + next = rd.data;
2473 + len = ewah_read_mmap(rd.valid, next, end - next);
2474 + if (len < 0)
2475 + goto done;
2476 +
2477 + next += len;
2478 + len = ewah_read_mmap(rd.check_only, next, end - next);
2479 + if (len < 0)
2480 + goto done;
2481 +
2482 + next += len;
2483 + len = ewah_read_mmap(rd.sha1_valid, next, end - next);
2484 + if (len < 0)
2485 + goto done;
2486 +
2487 + ewah_each_bit(rd.check_only, set_check_only, &rd);
2488 + rd.data = next + len;
2489 + ewah_each_bit(rd.valid, read_stat, &rd);
2490 + ewah_each_bit(rd.sha1_valid, read_sha1, &rd);
2491 + next = rd.data;
2492 +
2493 +done:
2494 + free(rd.ucd);
2495 + ewah_free(rd.valid);
2496 + ewah_free(rd.check_only);
2497 + ewah_free(rd.sha1_valid);
2498 +done2:
2499 + if (next != end) {
2500 + free_untracked_cache(uc);
2501 + uc = NULL;
2502 + }
2503 + return uc;
2504 +}
dir.h
+2
@@ -298,5 +298,7 @@ static inline int dir_path_match(const struct dir_entry *ent,
298 has_trailing_dir);
299 }
300
301 +void free_untracked_cache(struct untracked_cache *);
302 +struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
303 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
304 #endif
read-cache.c
+5
@@ -1371,6 +1371,9 @@ static int read_index_extension(struct index_state *istate,
1371 if (read_link_extension(istate, data, sz))
1372 return -1;
1373 break;
1374 + case CACHE_EXT_UNTRACKED:
1375 + istate->untracked = read_untracked_extension(data, sz);
1376 + break;
1377 default:
1378 if (*ext < 'A' || 'Z' < *ext)
1379 return error("index uses %.4s extension, which we do not understand",
@@ -1662,6 +1665,8 @@ int discard_index(struct index_state *istate)
1665 istate->cache = NULL;
1666 istate->cache_alloc = 0;
1667 discard_split_index(istate);
1668 + free_untracked_cache(istate->untracked);
1669 + istate->untracked = NULL;
1670 return 0;
1671 }
1672