2 * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 #include "got_compat.h"
33 #include "got_error.h"
34 #include "got_object.h"
37 #include "got_lib_fileindex.h"
38 #include "got_lib_worktree.h"
40 /* got_fileindex_entry flags */
41 #define GOT_FILEIDX_F_PATH_LEN 0x00000fff
42 #define GOT_FILEIDX_F_STAGE 0x0000f000
43 #define GOT_FILEIDX_F_STAGE_SHIFT 12
44 #define GOT_FILEIDX_F_NOT_FLUSHED 0x00010000
45 #define GOT_FILEIDX_F_NO_BLOB 0x00020000
46 #define GOT_FILEIDX_F_NO_COMMIT 0x00040000
47 #define GOT_FILEIDX_F_NO_FILE_ON_DISK 0x00080000
48 #define GOT_FILEIDX_F_REMOVE_ON_FLUSH 0x00100000
49 #define GOT_FILEIDX_F_SKIPPED 0x00200000
51 struct got_fileindex
{
52 struct got_fileindex_tree entries
;
53 int nentries
; /* Does not include entries marked for removal. */
54 #define GOT_FILEIDX_MAX_ENTRIES INT_MAX
58 got_fileindex_entry_perms_get(struct got_fileindex_entry
*ie
)
60 return ((ie
->mode
& GOT_FILEIDX_MODE_PERMS
) >>
61 GOT_FILEIDX_MODE_PERMS_SHIFT
);
65 fileindex_entry_perms_set(struct got_fileindex_entry
*ie
, mode_t mode
)
67 ie
->mode
&= ~GOT_FILEIDX_MODE_PERMS
;
68 ie
->mode
|= ((mode
<< GOT_FILEIDX_MODE_PERMS_SHIFT
) &
69 GOT_FILEIDX_MODE_PERMS
);
73 got_fileindex_perms_to_st(struct got_fileindex_entry
*ie
)
75 mode_t perms
= got_fileindex_entry_perms_get(ie
);
76 int type
= got_fileindex_entry_filetype_get(ie
);
79 if (type
== GOT_FILEIDX_MODE_REGULAR_FILE
||
80 type
== GOT_FILEIDX_MODE_BAD_SYMLINK
)
85 return (ftype
| (perms
& (S_IRWXU
| S_IRWXG
| S_IRWXO
)));
88 const struct got_error
*
89 got_fileindex_entry_update(struct got_fileindex_entry
*ie
,
90 int wt_fd
, const char *ondisk_path
, uint8_t *blob_sha1
,
91 uint8_t *commit_sha1
, int update_timestamps
)
95 if (fstatat(wt_fd
, ondisk_path
, &sb
, AT_SYMLINK_NOFOLLOW
) != 0) {
96 if (!((ie
->flags
& GOT_FILEIDX_F_NO_FILE_ON_DISK
) &&
98 return got_error_from_errno2("fstatat", ondisk_path
);
99 sb
.st_mode
= GOT_DEFAULT_FILE_MODE
;
101 if (sb
.st_mode
& S_IFDIR
)
102 return got_error_set_errno(EISDIR
, ondisk_path
);
103 ie
->flags
&= ~GOT_FILEIDX_F_NO_FILE_ON_DISK
;
107 if ((ie
->flags
& GOT_FILEIDX_F_NO_FILE_ON_DISK
) == 0) {
108 if (update_timestamps
) {
109 ie
->ctime_sec
= sb
.st_ctim
.tv_sec
;
110 ie
->ctime_nsec
= sb
.st_ctim
.tv_nsec
;
111 ie
->mtime_sec
= sb
.st_mtim
.tv_sec
;
112 ie
->mtime_nsec
= sb
.st_mtim
.tv_nsec
;
116 ie
->size
= (sb
.st_size
& 0xffffffff);
117 if (S_ISLNK(sb
.st_mode
)) {
118 got_fileindex_entry_filetype_set(ie
,
119 GOT_FILEIDX_MODE_SYMLINK
);
120 fileindex_entry_perms_set(ie
, 0);
122 got_fileindex_entry_filetype_set(ie
,
123 GOT_FILEIDX_MODE_REGULAR_FILE
);
124 fileindex_entry_perms_set(ie
,
125 sb
.st_mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
));
130 memcpy(ie
->blob_sha1
, blob_sha1
, SHA1_DIGEST_LENGTH
);
131 ie
->flags
&= ~GOT_FILEIDX_F_NO_BLOB
;
133 ie
->flags
|= GOT_FILEIDX_F_NO_BLOB
;
136 memcpy(ie
->commit_sha1
, commit_sha1
, SHA1_DIGEST_LENGTH
);
137 ie
->flags
&= ~GOT_FILEIDX_F_NO_COMMIT
;
139 ie
->flags
|= GOT_FILEIDX_F_NO_COMMIT
;
145 got_fileindex_entry_mark_deleted_from_disk(struct got_fileindex_entry
*ie
)
147 ie
->flags
|= GOT_FILEIDX_F_NO_FILE_ON_DISK
;
151 got_fileindex_entry_mark_skipped(struct got_fileindex_entry
*ie
)
153 ie
->flags
|= GOT_FILEIDX_F_SKIPPED
;
156 const struct got_error
*
157 got_fileindex_entry_alloc(struct got_fileindex_entry
**ie
,
162 *ie
= calloc(1, sizeof(**ie
));
164 return got_error_from_errno("calloc");
166 (*ie
)->path
= strdup(relpath
);
167 if ((*ie
)->path
== NULL
) {
168 const struct got_error
*err
= got_error_from_errno("strdup");
174 len
= strlen(relpath
);
175 if (len
> GOT_FILEIDX_F_PATH_LEN
)
176 len
= GOT_FILEIDX_F_PATH_LEN
;
183 got_fileindex_entry_free(struct got_fileindex_entry
*ie
)
190 got_fileindex_entry_path_len(const struct got_fileindex_entry
*ie
)
192 return (size_t)(ie
->flags
& GOT_FILEIDX_F_PATH_LEN
);
196 got_fileindex_entry_stage_get(const struct got_fileindex_entry
*ie
)
198 return ((ie
->flags
& GOT_FILEIDX_F_STAGE
) >> GOT_FILEIDX_F_STAGE_SHIFT
);
202 got_fileindex_entry_stage_set(struct got_fileindex_entry
*ie
, uint32_t stage
)
204 ie
->flags
&= ~GOT_FILEIDX_F_STAGE
;
205 ie
->flags
|= ((stage
<< GOT_FILEIDX_F_STAGE_SHIFT
) &
206 GOT_FILEIDX_F_STAGE
);
210 got_fileindex_entry_filetype_get(struct got_fileindex_entry
*ie
)
212 return (ie
->mode
& GOT_FILEIDX_MODE_FILE_TYPE_ONDISK
);
216 got_fileindex_entry_filetype_set(struct got_fileindex_entry
*ie
, int type
)
218 ie
->mode
&= ~GOT_FILEIDX_MODE_FILE_TYPE_ONDISK
;
219 ie
->mode
|= (type
& GOT_FILEIDX_MODE_FILE_TYPE_ONDISK
);
223 got_fileindex_entry_staged_filetype_set(struct got_fileindex_entry
*ie
, int type
)
225 ie
->mode
&= ~GOT_FILEIDX_MODE_FILE_TYPE_STAGED
;
226 ie
->mode
|= ((type
<< GOT_FILEIDX_MODE_FILE_TYPE_STAGED_SHIFT
) &
227 GOT_FILEIDX_MODE_FILE_TYPE_STAGED
);
231 got_fileindex_entry_staged_filetype_get(struct got_fileindex_entry
*ie
)
233 return (ie
->mode
& GOT_FILEIDX_MODE_FILE_TYPE_STAGED
) >>
234 GOT_FILEIDX_MODE_FILE_TYPE_STAGED_SHIFT
;
238 got_fileindex_entry_has_blob(struct got_fileindex_entry
*ie
)
240 return (ie
->flags
& GOT_FILEIDX_F_NO_BLOB
) == 0;
244 got_fileindex_entry_has_commit(struct got_fileindex_entry
*ie
)
246 return (ie
->flags
& GOT_FILEIDX_F_NO_COMMIT
) == 0;
250 got_fileindex_entry_has_file_on_disk(struct got_fileindex_entry
*ie
)
252 return (ie
->flags
& GOT_FILEIDX_F_NO_FILE_ON_DISK
) == 0;
256 got_fileindex_entry_was_skipped(struct got_fileindex_entry
*ie
)
258 return (ie
->flags
& GOT_FILEIDX_F_SKIPPED
) != 0;
261 static const struct got_error
*
262 add_entry(struct got_fileindex
*fileindex
, struct got_fileindex_entry
*ie
)
264 if (fileindex
->nentries
>= GOT_FILEIDX_MAX_ENTRIES
)
265 return got_error(GOT_ERR_NO_SPACE
);
267 RB_INSERT(got_fileindex_tree
, &fileindex
->entries
, ie
);
268 fileindex
->nentries
++;
272 const struct got_error
*
273 got_fileindex_entry_add(struct got_fileindex
*fileindex
,
274 struct got_fileindex_entry
*ie
)
276 /* Flag this entry until it gets written out to disk. */
277 ie
->flags
|= GOT_FILEIDX_F_NOT_FLUSHED
;
279 return add_entry(fileindex
, ie
);
283 got_fileindex_entry_remove(struct got_fileindex
*fileindex
,
284 struct got_fileindex_entry
*ie
)
287 * Removing an entry from the RB tree immediately breaks
288 * in-progress iterations over file index entries.
289 * So flag this entry for removal and remove it once the index
290 * is written out to disk. Meanwhile, pretend this entry no longer
291 * exists if we get queried for it again before then.
293 ie
->flags
|= GOT_FILEIDX_F_REMOVE_ON_FLUSH
;
294 fileindex
->nentries
--;
297 struct got_fileindex_entry
*
298 got_fileindex_entry_get(struct got_fileindex
*fileindex
, const char *path
,
301 struct got_fileindex_entry
*ie
;
302 struct got_fileindex_entry key
;
303 memset(&key
, 0, sizeof(key
));
304 key
.path
= (char *)path
;
305 key
.flags
= (path_len
& GOT_FILEIDX_F_PATH_LEN
);
306 ie
= RB_FIND(got_fileindex_tree
, &fileindex
->entries
, &key
);
307 if (ie
&& (ie
->flags
& GOT_FILEIDX_F_REMOVE_ON_FLUSH
))
312 const struct got_error
*
313 got_fileindex_for_each_entry_safe(struct got_fileindex
*fileindex
,
314 got_fileindex_cb cb
, void *cb_arg
)
316 const struct got_error
*err
;
317 struct got_fileindex_entry
*ie
, *tmp
;
319 RB_FOREACH_SAFE(ie
, got_fileindex_tree
, &fileindex
->entries
, tmp
) {
320 if (ie
->flags
& GOT_FILEIDX_F_REMOVE_ON_FLUSH
)
322 err
= (*cb
)(cb_arg
, ie
);
329 struct got_fileindex
*
330 got_fileindex_alloc(void)
332 struct got_fileindex
*fileindex
;
334 fileindex
= calloc(1, sizeof(*fileindex
));
335 if (fileindex
== NULL
)
338 RB_INIT(&fileindex
->entries
);
343 got_fileindex_free(struct got_fileindex
*fileindex
)
345 struct got_fileindex_entry
*ie
;
347 while ((ie
= RB_MIN(got_fileindex_tree
, &fileindex
->entries
))) {
348 RB_REMOVE(got_fileindex_tree
, &fileindex
->entries
, ie
);
349 got_fileindex_entry_free(ie
);
354 static const struct got_error
*
355 write_fileindex_val64(SHA1_CTX
*ctx
, uint64_t val
, FILE *outfile
)
360 SHA1Update(ctx
, (uint8_t *)&val
, sizeof(val
));
361 n
= fwrite(&val
, 1, sizeof(val
), outfile
);
362 if (n
!= sizeof(val
))
363 return got_ferror(outfile
, GOT_ERR_IO
);
367 static const struct got_error
*
368 write_fileindex_val32(SHA1_CTX
*ctx
, uint32_t val
, FILE *outfile
)
373 SHA1Update(ctx
, (uint8_t *)&val
, sizeof(val
));
374 n
= fwrite(&val
, 1, sizeof(val
), outfile
);
375 if (n
!= sizeof(val
))
376 return got_ferror(outfile
, GOT_ERR_IO
);
380 static const struct got_error
*
381 write_fileindex_val16(SHA1_CTX
*ctx
, uint16_t val
, FILE *outfile
)
386 SHA1Update(ctx
, (uint8_t *)&val
, sizeof(val
));
387 n
= fwrite(&val
, 1, sizeof(val
), outfile
);
388 if (n
!= sizeof(val
))
389 return got_ferror(outfile
, GOT_ERR_IO
);
393 static const struct got_error
*
394 write_fileindex_path(SHA1_CTX
*ctx
, const char *path
, FILE *outfile
)
396 size_t n
, len
, pad
= 0;
397 static const uint8_t zero
[8] = { 0 };
400 while ((len
+ pad
) % 8 != 0)
403 pad
= 8; /* NUL-terminate */
405 SHA1Update(ctx
, path
, len
);
406 n
= fwrite(path
, 1, len
, outfile
);
408 return got_ferror(outfile
, GOT_ERR_IO
);
409 SHA1Update(ctx
, zero
, pad
);
410 n
= fwrite(zero
, 1, pad
, outfile
);
412 return got_ferror(outfile
, GOT_ERR_IO
);
416 static const struct got_error
*
417 write_fileindex_entry(SHA1_CTX
*ctx
, struct got_fileindex_entry
*ie
,
420 const struct got_error
*err
;
424 err
= write_fileindex_val64(ctx
, ie
->ctime_sec
, outfile
);
427 err
= write_fileindex_val64(ctx
, ie
->ctime_nsec
, outfile
);
430 err
= write_fileindex_val64(ctx
, ie
->mtime_sec
, outfile
);
433 err
= write_fileindex_val64(ctx
, ie
->mtime_nsec
, outfile
);
437 err
= write_fileindex_val32(ctx
, ie
->uid
, outfile
);
440 err
= write_fileindex_val32(ctx
, ie
->gid
, outfile
);
443 err
= write_fileindex_val32(ctx
, ie
->size
, outfile
);
447 err
= write_fileindex_val16(ctx
, ie
->mode
, outfile
);
451 SHA1Update(ctx
, ie
->blob_sha1
, SHA1_DIGEST_LENGTH
);
452 n
= fwrite(ie
->blob_sha1
, 1, SHA1_DIGEST_LENGTH
, outfile
);
453 if (n
!= SHA1_DIGEST_LENGTH
)
454 return got_ferror(outfile
, GOT_ERR_IO
);
456 SHA1Update(ctx
, ie
->commit_sha1
, SHA1_DIGEST_LENGTH
);
457 n
= fwrite(ie
->commit_sha1
, 1, SHA1_DIGEST_LENGTH
, outfile
);
458 if (n
!= SHA1_DIGEST_LENGTH
)
459 return got_ferror(outfile
, GOT_ERR_IO
);
461 err
= write_fileindex_val32(ctx
, ie
->flags
, outfile
);
465 err
= write_fileindex_path(ctx
, ie
->path
, outfile
);
469 stage
= got_fileindex_entry_stage_get(ie
);
470 if (stage
== GOT_FILEIDX_STAGE_MODIFY
||
471 stage
== GOT_FILEIDX_STAGE_ADD
) {
472 SHA1Update(ctx
, ie
->staged_blob_sha1
, SHA1_DIGEST_LENGTH
);
473 n
= fwrite(ie
->staged_blob_sha1
, 1, SHA1_DIGEST_LENGTH
,
475 if (n
!= SHA1_DIGEST_LENGTH
)
476 return got_ferror(outfile
, GOT_ERR_IO
);
482 const struct got_error
*
483 got_fileindex_write(struct got_fileindex
*fileindex
, FILE *outfile
)
485 const struct got_error
*err
= NULL
;
486 struct got_fileindex_hdr hdr
;
488 uint8_t sha1
[SHA1_DIGEST_LENGTH
];
490 struct got_fileindex_entry
*ie
, *tmp
;
494 hdr
.signature
= htobe32(GOT_FILE_INDEX_SIGNATURE
);
495 hdr
.version
= htobe32(GOT_FILE_INDEX_VERSION
);
496 hdr
.nentries
= htobe32(fileindex
->nentries
);
498 SHA1Update(&ctx
, (uint8_t *)&hdr
.signature
, sizeof(hdr
.signature
));
499 SHA1Update(&ctx
, (uint8_t *)&hdr
.version
, sizeof(hdr
.version
));
500 SHA1Update(&ctx
, (uint8_t *)&hdr
.nentries
, sizeof(hdr
.nentries
));
501 n
= fwrite(&hdr
.signature
, 1, sizeof(hdr
.signature
), outfile
);
502 if (n
!= sizeof(hdr
.signature
))
503 return got_ferror(outfile
, GOT_ERR_IO
);
504 n
= fwrite(&hdr
.version
, 1, sizeof(hdr
.version
), outfile
);
505 if (n
!= sizeof(hdr
.version
))
506 return got_ferror(outfile
, GOT_ERR_IO
);
507 n
= fwrite(&hdr
.nentries
, 1, sizeof(hdr
.nentries
), outfile
);
508 if (n
!= sizeof(hdr
.nentries
))
509 return got_ferror(outfile
, GOT_ERR_IO
);
511 RB_FOREACH_SAFE(ie
, got_fileindex_tree
, &fileindex
->entries
, tmp
) {
512 ie
->flags
&= ~GOT_FILEIDX_F_NOT_FLUSHED
;
513 ie
->flags
&= ~GOT_FILEIDX_F_SKIPPED
;
514 if (ie
->flags
& GOT_FILEIDX_F_REMOVE_ON_FLUSH
) {
515 RB_REMOVE(got_fileindex_tree
, &fileindex
->entries
, ie
);
516 got_fileindex_entry_free(ie
);
519 err
= write_fileindex_entry(&ctx
, ie
, outfile
);
524 SHA1Final(sha1
, &ctx
);
525 n
= fwrite(sha1
, 1, sizeof(sha1
), outfile
);
526 if (n
!= sizeof(sha1
))
527 return got_ferror(outfile
, GOT_ERR_IO
);
529 if (fflush(outfile
) != 0)
530 return got_error_from_errno("fflush");
535 static const struct got_error
*
536 read_fileindex_val64(uint64_t *val
, SHA1_CTX
*ctx
, FILE *infile
)
540 n
= fread(val
, 1, sizeof(*val
), infile
);
541 if (n
!= sizeof(*val
))
542 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
543 SHA1Update(ctx
, (uint8_t *)val
, sizeof(*val
));
544 *val
= be64toh(*val
);
548 static const struct got_error
*
549 read_fileindex_val32(uint32_t *val
, SHA1_CTX
*ctx
, FILE *infile
)
553 n
= fread(val
, 1, sizeof(*val
), infile
);
554 if (n
!= sizeof(*val
))
555 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
556 SHA1Update(ctx
, (uint8_t *)val
, sizeof(*val
));
557 *val
= be32toh(*val
);
561 static const struct got_error
*
562 read_fileindex_val16(uint16_t *val
, SHA1_CTX
*ctx
, FILE *infile
)
566 n
= fread(val
, 1, sizeof(*val
), infile
);
567 if (n
!= sizeof(*val
))
568 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
569 SHA1Update(ctx
, (uint8_t *)val
, sizeof(*val
));
570 *val
= be16toh(*val
);
574 static const struct got_error
*
575 read_fileindex_path(char **path
, SHA1_CTX
*ctx
, FILE *infile
)
577 const struct got_error
*err
= NULL
;
578 const size_t chunk_size
= 8;
579 size_t n
, len
= 0, totlen
= chunk_size
;
581 *path
= malloc(totlen
);
583 return got_error_from_errno("malloc");
586 if (len
+ chunk_size
> totlen
) {
587 char *p
= reallocarray(*path
, totlen
+ chunk_size
, 1);
589 err
= got_error_from_errno("reallocarray");
592 totlen
+= chunk_size
;
595 n
= fread(*path
+ len
, 1, chunk_size
, infile
);
596 if (n
!= chunk_size
) {
597 err
= got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
600 SHA1Update(ctx
, *path
+ len
, chunk_size
);
602 } while (memchr(*path
+ len
- chunk_size
, '\0', chunk_size
) == NULL
);
611 static const struct got_error
*
612 read_fileindex_entry(struct got_fileindex_entry
**iep
, SHA1_CTX
*ctx
,
613 FILE *infile
, uint32_t version
)
615 const struct got_error
*err
;
616 struct got_fileindex_entry
*ie
;
621 ie
= calloc(1, sizeof(*ie
));
623 return got_error_from_errno("calloc");
625 err
= read_fileindex_val64(&ie
->ctime_sec
, ctx
, infile
);
628 err
= read_fileindex_val64(&ie
->ctime_nsec
, ctx
, infile
);
631 err
= read_fileindex_val64(&ie
->mtime_sec
, ctx
, infile
);
634 err
= read_fileindex_val64(&ie
->mtime_nsec
, ctx
, infile
);
638 err
= read_fileindex_val32(&ie
->uid
, ctx
, infile
);
641 err
= read_fileindex_val32(&ie
->gid
, ctx
, infile
);
644 err
= read_fileindex_val32(&ie
->size
, ctx
, infile
);
648 err
= read_fileindex_val16(&ie
->mode
, ctx
, infile
);
652 n
= fread(ie
->blob_sha1
, 1, SHA1_DIGEST_LENGTH
, infile
);
653 if (n
!= SHA1_DIGEST_LENGTH
) {
654 err
= got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
657 SHA1Update(ctx
, ie
->blob_sha1
, SHA1_DIGEST_LENGTH
);
659 n
= fread(ie
->commit_sha1
, 1, SHA1_DIGEST_LENGTH
, infile
);
660 if (n
!= SHA1_DIGEST_LENGTH
) {
661 err
= got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
664 SHA1Update(ctx
, ie
->commit_sha1
, SHA1_DIGEST_LENGTH
);
666 err
= read_fileindex_val32(&ie
->flags
, ctx
, infile
);
670 err
= read_fileindex_path(&ie
->path
, ctx
, infile
);
675 uint32_t stage
= got_fileindex_entry_stage_get(ie
);
676 if (stage
== GOT_FILEIDX_STAGE_MODIFY
||
677 stage
== GOT_FILEIDX_STAGE_ADD
) {
678 n
= fread(ie
->staged_blob_sha1
, 1, SHA1_DIGEST_LENGTH
,
680 if (n
!= SHA1_DIGEST_LENGTH
) {
681 err
= got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
684 SHA1Update(ctx
, ie
->staged_blob_sha1
, SHA1_DIGEST_LENGTH
);
687 /* GOT_FILE_INDEX_VERSION 1 does not support staging. */
688 ie
->flags
&= ~GOT_FILEIDX_F_STAGE
;
693 got_fileindex_entry_free(ie
);
699 const struct got_error
*
700 got_fileindex_read(struct got_fileindex
*fileindex
, FILE *infile
)
702 const struct got_error
*err
= NULL
;
703 struct got_fileindex_hdr hdr
;
705 struct got_fileindex_entry
*ie
;
706 uint8_t sha1_expected
[SHA1_DIGEST_LENGTH
];
707 uint8_t sha1
[SHA1_DIGEST_LENGTH
];
713 n
= fread(&hdr
.signature
, 1, sizeof(hdr
.signature
), infile
);
714 if (n
!= sizeof(hdr
.signature
)) {
715 if (n
== 0) /* EOF */
717 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
719 n
= fread(&hdr
.version
, 1, sizeof(hdr
.version
), infile
);
720 if (n
!= sizeof(hdr
.version
)) {
721 if (n
== 0) /* EOF */
723 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
725 n
= fread(&hdr
.nentries
, 1, sizeof(hdr
.nentries
), infile
);
726 if (n
!= sizeof(hdr
.nentries
)) {
727 if (n
== 0) /* EOF */
729 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
732 SHA1Update(&ctx
, (uint8_t *)&hdr
.signature
, sizeof(hdr
.signature
));
733 SHA1Update(&ctx
, (uint8_t *)&hdr
.version
, sizeof(hdr
.version
));
734 SHA1Update(&ctx
, (uint8_t *)&hdr
.nentries
, sizeof(hdr
.nentries
));
736 hdr
.signature
= be32toh(hdr
.signature
);
737 hdr
.version
= be32toh(hdr
.version
);
738 hdr
.nentries
= be32toh(hdr
.nentries
);
740 if (hdr
.signature
!= GOT_FILE_INDEX_SIGNATURE
)
741 return got_error(GOT_ERR_FILEIDX_SIG
);
742 if (hdr
.version
> GOT_FILE_INDEX_VERSION
)
743 return got_error(GOT_ERR_FILEIDX_VER
);
745 for (i
= 0; i
< hdr
.nentries
; i
++) {
746 err
= read_fileindex_entry(&ie
, &ctx
, infile
, hdr
.version
);
749 err
= add_entry(fileindex
, ie
);
754 n
= fread(sha1_expected
, 1, sizeof(sha1_expected
), infile
);
755 if (n
!= sizeof(sha1_expected
))
756 return got_ferror(infile
, GOT_ERR_FILEIDX_BAD
);
757 SHA1Final(sha1
, &ctx
);
758 if (memcmp(sha1
, sha1_expected
, SHA1_DIGEST_LENGTH
) != 0)
759 return got_error(GOT_ERR_FILEIDX_CSUM
);
764 static struct got_fileindex_entry
*
765 walk_fileindex(struct got_fileindex
*fileindex
, struct got_fileindex_entry
*ie
)
767 struct got_fileindex_entry
*next
;
769 next
= RB_NEXT(got_fileindex_tree
, &fileindex
->entries
, ie
);
771 /* Skip entries which were added or removed by diff callbacks. */
772 while (next
&& (next
->flags
& (GOT_FILEIDX_F_NOT_FLUSHED
|
773 GOT_FILEIDX_F_REMOVE_ON_FLUSH
)))
774 next
= RB_NEXT(got_fileindex_tree
, &fileindex
->entries
, next
);
779 static const struct got_error
*
780 diff_fileindex_tree(struct got_fileindex
*, struct got_fileindex_entry
**ie
,
781 struct got_tree_object
*tree
, const char *, const char *,
782 struct got_repository
*, struct got_fileindex_diff_tree_cb
*, void *);
784 static const struct got_error
*
785 walk_tree(struct got_tree_entry
**next
, struct got_fileindex
*fileindex
,
786 struct got_fileindex_entry
**ie
, struct got_tree_object
*tree
, int *tidx
,
787 const char *path
, const char *entry_name
, struct got_repository
*repo
,
788 struct got_fileindex_diff_tree_cb
*cb
, void *cb_arg
)
790 const struct got_error
*err
= NULL
;
791 struct got_tree_entry
*te
= got_object_tree_get_entry(tree
, *tidx
);
793 if (!got_object_tree_entry_is_submodule(te
) &&
794 S_ISDIR(got_tree_entry_get_mode(te
))) {
796 struct got_tree_object
*subtree
;
798 if (asprintf(&subpath
, "%s%s%s", path
,
799 path
[0] == '\0' ? "" : "/",
800 got_tree_entry_get_name(te
)) == -1)
801 return got_error_from_errno("asprintf");
803 err
= got_object_open_as_tree(&subtree
, repo
,
804 got_tree_entry_get_id(te
));
810 err
= diff_fileindex_tree(fileindex
, ie
, subtree
, subpath
,
811 entry_name
, repo
, cb
, cb_arg
);
813 got_object_tree_close(subtree
);
819 *next
= got_object_tree_get_entry(tree
, *tidx
);
823 static const struct got_error
*
824 diff_fileindex_tree(struct got_fileindex
*fileindex
,
825 struct got_fileindex_entry
**ie
, struct got_tree_object
*tree
,
826 const char *path
, const char *entry_name
, struct got_repository
*repo
,
827 struct got_fileindex_diff_tree_cb
*cb
, void *cb_arg
)
829 const struct got_error
*err
= NULL
;
830 struct got_tree_entry
*te
= NULL
;
831 size_t path_len
= strlen(path
);
832 struct got_fileindex_entry
*next
;
835 te
= got_object_tree_get_entry(tree
, tidx
);
836 while ((*ie
&& got_path_is_child((*ie
)->path
, path
, path_len
)) || te
) {
839 const char *te_name
= got_tree_entry_get_name(te
);
841 if (asprintf(&te_path
, "%s/%s", path
, te_name
) == -1) {
842 err
= got_error_from_errno("asprintf");
845 cmp
= got_path_cmp((*ie
)->path
, te_path
,
846 got_fileindex_entry_path_len(*ie
), strlen(te_path
));
849 if (got_path_is_child((*ie
)->path
, path
,
851 !got_object_tree_entry_is_submodule(te
) &&
852 (entry_name
== NULL
||
853 strcmp(te_name
, entry_name
) == 0)) {
854 err
= cb
->diff_old_new(cb_arg
, *ie
, te
,
856 if (err
|| entry_name
)
859 *ie
= walk_fileindex(fileindex
, *ie
);
860 err
= walk_tree(&te
, fileindex
, ie
, tree
, &tidx
,
861 path
, entry_name
, repo
, cb
, cb_arg
);
862 } else if (cmp
< 0) {
863 next
= walk_fileindex(fileindex
, *ie
);
864 if (got_path_is_child((*ie
)->path
, path
,
865 path_len
) && entry_name
== NULL
) {
866 err
= cb
->diff_old(cb_arg
, *ie
, path
);
867 if (err
|| entry_name
)
872 if ((entry_name
== NULL
||
873 strcmp(te_name
, entry_name
) == 0)) {
874 err
= cb
->diff_new(cb_arg
, te
, path
);
875 if (err
|| entry_name
)
878 err
= walk_tree(&te
, fileindex
, ie
, tree
, &tidx
,
879 path
, entry_name
, repo
, cb
, cb_arg
);
884 next
= walk_fileindex(fileindex
, *ie
);
885 if (got_path_is_child((*ie
)->path
, path
, path_len
) &&
886 (entry_name
== NULL
||
887 (te
&& strcmp(got_tree_entry_get_name(te
),
888 entry_name
) == 0))) {
889 err
= cb
->diff_old(cb_arg
, *ie
, path
);
890 if (err
|| entry_name
)
895 if (!got_object_tree_entry_is_submodule(te
) &&
896 (entry_name
== NULL
||
897 strcmp(got_tree_entry_get_name(te
), entry_name
)
899 err
= cb
->diff_new(cb_arg
, te
, path
);
900 if (err
|| entry_name
)
903 err
= walk_tree(&te
, fileindex
, ie
, tree
, &tidx
, path
,
904 entry_name
, repo
, cb
, cb_arg
);
913 const struct got_error
*
914 got_fileindex_diff_tree(struct got_fileindex
*fileindex
,
915 struct got_tree_object
*tree
, const char *path
, const char *entry_name
,
916 struct got_repository
*repo
,
917 struct got_fileindex_diff_tree_cb
*cb
, void *cb_arg
)
919 struct got_fileindex_entry
*ie
;
920 ie
= RB_MIN(got_fileindex_tree
, &fileindex
->entries
);
921 while (ie
&& !got_path_is_child(ie
->path
, path
, strlen(path
)))
922 ie
= walk_fileindex(fileindex
, ie
);
923 return diff_fileindex_tree(fileindex
, &ie
, tree
, path
, entry_name
, repo
,
927 static const struct got_error
*
928 diff_fileindex_dir(struct got_fileindex
*, struct got_fileindex_entry
**,
929 struct got_pathlist_head
*, int, const char *, const char *,
930 struct got_repository
*, struct got_fileindex_diff_dir_cb
*, void *);
932 static const struct got_error
*
933 read_dirlist(struct got_pathlist_head
*dirlist
, DIR *dir
, const char *path
)
935 const struct got_error
*err
= NULL
;
936 struct got_pathlist_entry
*new = NULL
;
937 struct dirent
*dep
= NULL
;
938 struct dirent
*de
= NULL
;
941 de
= malloc(sizeof(struct dirent
) + NAME_MAX
+ 1);
943 err
= got_error_from_errno("malloc");
947 if (readdir_r(dir
, de
, &dep
) != 0) {
948 err
= got_error_from_errno("readdir_r");
957 if (strcmp(de
->d_name
, ".") == 0 ||
958 strcmp(de
->d_name
, "..") == 0 ||
960 strcmp(de
->d_name
, GOT_WORKTREE_GOT_DIR
) == 0)) {
965 err
= got_pathlist_insert(&new, dirlist
, de
->d_name
, de
);
971 err
= got_error(GOT_ERR_DIR_DUP_ENTRY
);
981 free_dirlist(struct got_pathlist_head
*dirlist
)
983 struct got_pathlist_entry
*dle
;
985 TAILQ_FOREACH(dle
, dirlist
, entry
)
987 got_pathlist_free(dirlist
);
990 static const struct got_error
*
991 walk_dir(struct got_pathlist_entry
**next
, struct got_fileindex
*fileindex
,
992 struct got_fileindex_entry
**ie
, struct got_pathlist_entry
*dle
, int fd
,
993 const char *path
, const char *rootpath
, struct got_repository
*repo
,
994 struct got_fileindex_diff_dir_cb
*cb
, void *cb_arg
)
996 const struct got_error
*err
= NULL
;
997 struct dirent
*de
= dle
->data
;
1004 if (de
->d_type
== DT_UNKNOWN
) {
1005 /* Occurs on NFS mounts without "readdir plus" RPC. */
1007 if (asprintf(&dir_path
, "%s/%s", rootpath
, path
) == -1)
1008 return got_error_from_errno("asprintf");
1009 err
= got_path_dirent_type(&type
, dir_path
, de
);
1016 if (type
== DT_DIR
) {
1019 struct got_pathlist_head subdirlist
;
1021 TAILQ_INIT(&subdirlist
);
1023 if (asprintf(&subpath
, "%s%s%s", path
,
1024 path
[0] == '\0' ? "" : "/", de
->d_name
) == -1)
1025 return got_error_from_errno("asprintf");
1027 if (asprintf(&subdirpath
, "%s/%s", rootpath
, subpath
) == -1) {
1029 return got_error_from_errno("asprintf");
1032 subdirfd
= openat(fd
, de
->d_name
,
1033 O_RDONLY
| O_NOFOLLOW
| O_DIRECTORY
);
1034 if (subdirfd
== -1) {
1035 if (errno
== EACCES
) {
1036 *next
= TAILQ_NEXT(dle
, entry
);
1039 err
= got_error_from_errno2("openat", subdirpath
);
1045 subdir
= fdopendir(subdirfd
);
1047 return got_error_from_errno2("fdopendir", path
);
1049 err
= read_dirlist(&subdirlist
, subdir
, subdirpath
);
1056 err
= diff_fileindex_dir(fileindex
, ie
, &subdirlist
,
1057 dirfd(subdir
), rootpath
, subpath
, repo
, cb
, cb_arg
);
1058 if (subdir
&& closedir(subdir
) == -1 && err
== NULL
)
1059 err
= got_error_from_errno2("closedir", subdirpath
);
1062 free_dirlist(&subdirlist
);
1067 *next
= TAILQ_NEXT(dle
, entry
);
1071 static const struct got_error
*
1072 diff_fileindex_dir(struct got_fileindex
*fileindex
,
1073 struct got_fileindex_entry
**ie
, struct got_pathlist_head
*dirlist
,
1074 int dirfd
, const char *rootpath
, const char *path
,
1075 struct got_repository
*repo
,
1076 struct got_fileindex_diff_dir_cb
*cb
, void *cb_arg
)
1078 const struct got_error
*err
= NULL
;
1079 struct dirent
*de
= NULL
;
1080 size_t path_len
= strlen(path
);
1081 struct got_pathlist_entry
*dle
;
1083 if (cb
->diff_traverse
) {
1084 err
= cb
->diff_traverse(cb_arg
, path
, dirfd
);
1089 dle
= TAILQ_FIRST(dirlist
);
1090 while ((*ie
&& got_path_is_child((*ie
)->path
, path
, path_len
)) || dle
) {
1095 if (asprintf(&de_path
, "%s/%s", path
,
1096 de
->d_name
) == -1) {
1097 err
= got_error_from_errno("asprintf");
1100 cmp
= got_path_cmp((*ie
)->path
, de_path
,
1101 got_fileindex_entry_path_len(*ie
),
1102 strlen(path
) + 1 + strlen(de
->d_name
));
1105 err
= cb
->diff_old_new(cb_arg
, *ie
, de
, path
,
1109 *ie
= walk_fileindex(fileindex
, *ie
);
1110 err
= walk_dir(&dle
, fileindex
, ie
, dle
, dirfd
,
1111 path
, rootpath
, repo
, cb
, cb_arg
);
1112 } else if (cmp
< 0 ) {
1113 err
= cb
->diff_old(cb_arg
, *ie
, path
);
1116 *ie
= walk_fileindex(fileindex
, *ie
);
1118 err
= cb
->diff_new(cb_arg
, de
, path
, dirfd
);
1121 err
= walk_dir(&dle
, fileindex
, ie
, dle
, dirfd
,
1122 path
, rootpath
, repo
, cb
, cb_arg
);
1127 err
= cb
->diff_old(cb_arg
, *ie
, path
);
1130 *ie
= walk_fileindex(fileindex
, *ie
);
1133 err
= cb
->diff_new(cb_arg
, de
, path
, dirfd
);
1136 err
= walk_dir(&dle
, fileindex
, ie
, dle
, dirfd
, path
,
1137 rootpath
, repo
, cb
, cb_arg
);
1146 const struct got_error
*
1147 got_fileindex_diff_dir(struct got_fileindex
*fileindex
, int fd
,
1148 const char *rootpath
, const char *path
, struct got_repository
*repo
,
1149 struct got_fileindex_diff_dir_cb
*cb
, void *cb_arg
)
1151 const struct got_error
*err
;
1152 struct got_fileindex_entry
*ie
;
1153 struct got_pathlist_head dirlist
;
1157 TAILQ_INIT(&dirlist
);
1160 * Duplicate the file descriptor so we can call closedir() below
1161 * without closing the file descriptor passed in by our caller.
1165 return got_error_from_errno2("dup", path
);
1166 if (lseek(fd2
, 0, SEEK_SET
) == -1) {
1167 err
= got_error_from_errno2("lseek", path
);
1171 dir
= fdopendir(fd2
);
1173 err
= got_error_from_errno2("fdopendir", path
);
1177 err
= read_dirlist(&dirlist
, dir
, path
);
1183 ie
= RB_MIN(got_fileindex_tree
, &fileindex
->entries
);
1184 while (ie
&& !got_path_is_child(ie
->path
, path
, strlen(path
)))
1185 ie
= walk_fileindex(fileindex
, ie
);
1186 err
= diff_fileindex_dir(fileindex
, &ie
, &dirlist
, dirfd(dir
),
1187 rootpath
, path
, repo
, cb
, cb_arg
);
1189 if (closedir(dir
) == -1 && err
== NULL
)
1190 err
= got_error_from_errno2("closedir", path
);
1191 free_dirlist(&dirlist
);
1195 RB_GENERATE(got_fileindex_tree
, got_fileindex_entry
, entry
, got_fileindex_cmp
);