commit c34b20a267f11d16c26b79b2979d91fc9a75132f from: Stefan Sperling date: Mon Mar 12 12:06:03 2018 UTC write file index after checking out files commit - 9d31a1d8a43396fe66a94b1110e395d134bebf3f commit + c34b20a267f11d16c26b79b2979d91fc9a75132f blob - 85fdbb17fe65945c8f9d5c7e0ae4996976cd62b6 blob + 8ca7884bfbdf28f02f05c54fa74ff4c901619efc --- lib/fileindex.c +++ lib/fileindex.c @@ -21,26 +21,27 @@ #include #include #include +#include #include "got_error.h" #include "got_fileindex_lib.h" const struct got_error * -got_fileindex_entry_open(struct got_fileindex_entry **entry, const char *path, - uint8_t *blob_sha1) +got_fileindex_entry_open(struct got_fileindex_entry **entry, + const char *ondisk_path, const char *relpath, uint8_t *blob_sha1) { struct stat sb; size_t len; - if (lstat(path, &sb) != 0) + if (lstat(ondisk_path, &sb) != 0) return got_error_from_errno(); *entry = calloc(1, sizeof(**entry)); if (*entry == NULL) return got_error(GOT_ERR_NO_MEM); - (*entry)->path = strdup(path); + (*entry)->path = strdup(relpath); if ((*entry)->path == NULL) { free(*entry); *entry = NULL; @@ -61,7 +62,7 @@ got_fileindex_entry_open(struct got_fileindex_entry ** (*entry)->mode |= ((sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) << GOT_INDEX_ENTRY_MODE_PERMS_SHIFT); memcpy((*entry)->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH); - len = strlen(path); + len = strlen(relpath); if (len > GOT_INDEX_ENTRY_F_PATH_LEN) len = GOT_INDEX_ENTRY_F_PATH_LEN; (*entry)->flags |= len; @@ -111,8 +112,155 @@ got_fileindex_close(struct got_fileindex *fileindex) free(fileindex); } +static const struct got_error * +write_fileindex_val64(SHA1_CTX *ctx, uint64_t val, FILE *outfile) +{ + uint8_t buf[sizeof(uint64_t)]; + size_t n; + + val = htobe64(val); + memcpy(buf, &val, sizeof(val)); + SHA1Update(ctx, buf, sizeof(val)); + n = fwrite(buf, 1, sizeof(val), outfile); + if (n != sizeof(val)) + return got_ferror(outfile, GOT_ERR_IO); + return NULL; +} + +static const struct got_error * +write_fileindex_val32(SHA1_CTX *ctx, uint32_t val, FILE *outfile) +{ + uint8_t buf[sizeof(uint32_t)]; + size_t n; + + val = htobe32(val); + memcpy(buf, &val, sizeof(val)); + SHA1Update(ctx, buf, sizeof(val)); + n = fwrite(buf, 1, sizeof(val), outfile); + if (n != sizeof(val)) + return got_ferror(outfile, GOT_ERR_IO); + return NULL; +} + +static const struct got_error * +write_fileindex_val16(SHA1_CTX *ctx, uint16_t val, FILE *outfile) +{ + uint8_t buf[sizeof(uint16_t)]; + size_t n; + + val = htobe16(val); + memcpy(buf, &val, sizeof(val)); + SHA1Update(ctx, buf, sizeof(val)); + n = fwrite(buf, 1, sizeof(val), outfile); + if (n != sizeof(val)) + return got_ferror(outfile, GOT_ERR_IO); + return NULL; +} + +static const struct got_error * +write_fileindex_path(SHA1_CTX *ctx, const char *path, FILE *outfile) +{ + size_t n, len, pad; + static const uint8_t zero[8] = { 0 }; + + len = strlen(path); + pad = (len % 8); + + SHA1Update(ctx, path, len); + n = fwrite(path, 1, len, outfile); + if (n != len) + return got_ferror(outfile, GOT_ERR_IO); + if (pad == 0) + return NULL; + SHA1Update(ctx, zero, pad); + n = fwrite(zero, 1, pad, outfile); + if (n != pad) + return got_ferror(outfile, GOT_ERR_IO); + return NULL; +} + +static const struct got_error * +write_fileindex_entry(SHA1_CTX *ctx, struct got_fileindex_entry *entry, + FILE *outfile) +{ + const struct got_error *err; + size_t n, len, pad; + + err = write_fileindex_val64(ctx, entry->ctime_sec, outfile); + if (err) + return err; + err = write_fileindex_val64(ctx, entry->ctime_nsec, outfile); + if (err) + return err; + err = write_fileindex_val64(ctx, entry->mtime_sec, outfile); + if (err) + return err; + err = write_fileindex_val64(ctx, entry->mtime_nsec, outfile); + if (err) + return err; + + err = write_fileindex_val32(ctx, entry->uid, outfile); + if (err) + return err; + err = write_fileindex_val32(ctx, entry->gid, outfile); + if (err) + return err; + err = write_fileindex_val32(ctx, entry->size, outfile); + if (err) + return err; + + err = write_fileindex_val16(ctx, entry->mode, outfile); + if (err) + return err; + + SHA1Update(ctx, entry->blob_sha1, SHA1_DIGEST_LENGTH); + n = fwrite(entry->blob_sha1, 1, SHA1_DIGEST_LENGTH, outfile); + if (n != SHA1_DIGEST_LENGTH) + return got_ferror(outfile, GOT_ERR_IO); + + err = write_fileindex_val32(ctx, entry->flags, outfile); + if (err) + return err; + + err = write_fileindex_path(ctx, entry->path, outfile); + return err; +} + const struct got_error * got_fileindex_write(struct got_fileindex *fileindex, FILE *outfile) { + struct got_fileindex_hdr hdr; + struct got_fileindex_entry *entry; + SHA1_CTX ctx; + uint8_t sha1[SHA1_DIGEST_LENGTH]; + size_t n; + const size_t len = sizeof(hdr.signature) + sizeof(hdr.version) + + sizeof(hdr.nentries); + uint8_t buf[len]; + + SHA1Init(&ctx); + + hdr.signature = htobe32(GOT_FILE_INDEX_SIGNATURE); + hdr.version = htobe32(GOT_FILE_INDEX_VERSION); + hdr.nentries = htobe32(fileindex->nentries); + + memcpy(buf, &hdr, len); + SHA1Update(&ctx, buf, len); + n = fwrite(buf, 1, len, outfile); + if (n != len) + return got_ferror(outfile, GOT_ERR_IO); + + TAILQ_FOREACH(entry, &fileindex->entries, entry) { + const struct got_error *err; + err = write_fileindex_entry(&ctx, entry, outfile); + if (err) + return err; + } + + SHA1Final(sha1, &ctx); + n = fwrite(sha1, 1, sizeof(sha1), outfile); + if (n != sizeof(sha1)) + return got_ferror(outfile, GOT_ERR_IO); + return NULL; } blob - 546f7ddd279eba8e6792b2ea8e126f4bc0d3d40b blob + 018f4f25c636bf8cfb37d7b1765211c73acae8e9 --- lib/got_fileindex_lib.h +++ lib/got_fileindex_lib.h @@ -74,6 +74,7 @@ struct got_fileindex { /* On-disk file index header structure. */ struct got_fileindex_hdr { uint32_t signature; /* big-endian */ +#define GOT_FILE_INDEX_SIGNATURE 0x676f7449 /* 'g', 'o', 't', 'I' */ uint32_t version; /* big-endian */ #define GOT_FILE_INDEX_VERSION 1 uint32_t nentries; /* big-endian */ @@ -82,7 +83,7 @@ struct got_fileindex_hdr { }; const struct got_error *got_fileindex_entry_open(struct got_fileindex_entry **, - const char *, uint8_t *); + const char *, const char *, uint8_t *); void got_fileindex_entry_close(struct got_fileindex_entry *); struct got_fileindex *got_fileindex_open(void); void got_fileindex_close(struct got_fileindex *); blob - c8140c77f4fb12393cc353436d2ef004276aae3c blob + e7ba544ae402ec0cfcc1c84183ca0c8278771fd4 --- lib/worktree.c +++ lib/worktree.c @@ -377,22 +377,22 @@ add_file_on_disk(struct got_worktree *worktree, struct const char *path, struct got_blob_object *blob, struct got_repository *repo) { const struct got_error *err = NULL; - char *abspath; + char *ondisk_path; int fd; size_t len, hdrlen; struct got_fileindex_entry *entry; - if (asprintf(&abspath, "%s/%s", worktree->root_path, + if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, apply_path_prefix(worktree, path)) == -1) return got_error(GOT_ERR_NO_MEM); - fd = open(abspath, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, + fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE); if (fd == -1) { err = got_error_from_errno(); if (errno == EEXIST) { struct stat sb; - if (lstat(abspath, &sb) == -1) { + if (lstat(ondisk_path, &sb) == -1) { err = got_error_from_errno(); } else if (!S_ISREG(sb.st_mode)) { /* TODO file is obstructed; do something */ @@ -424,7 +424,8 @@ add_file_on_disk(struct got_worktree *worktree, struct fsync(fd); - err = got_fileindex_entry_open(&entry, abspath, blob->id.sha1); + err = got_fileindex_entry_open(&entry, ondisk_path, + apply_path_prefix(worktree, path), blob->id.sha1); if (err) goto done; @@ -433,7 +434,7 @@ add_file_on_disk(struct got_worktree *worktree, struct goto done; done: close(fd); - free(abspath); + free(ondisk_path); return err; }