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.
17 #include <sys/types.h>
19 #include <sys/queue.h>
34 #include "got_compat.h"
36 #include "got_error.h"
37 #include "got_object.h"
38 #include "got_repository.h"
39 #include "got_opentemp.h"
42 #include "got_lib_sha1.h"
43 #include "got_lib_delta.h"
44 #include "got_lib_inflate.h"
45 #include "got_lib_object.h"
46 #include "got_lib_object_idcache.h"
47 #include "got_lib_object_cache.h"
48 #include "got_lib_object_parse.h"
49 #include "got_lib_pack.h"
50 #include "got_lib_repository.h"
53 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
57 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
60 struct got_object_id
*
61 got_object_get_id(struct got_object
*obj
)
66 const struct got_error
*
67 got_object_get_id_str(char **outbuf
, struct got_object
*obj
)
69 return got_object_id_str(outbuf
, &obj
->id
);
72 const struct got_error
*
73 got_object_get_type(int *type
, struct got_repository
*repo
,
74 struct got_object_id
*id
)
76 const struct got_error
*err
= NULL
;
77 struct got_object
*obj
;
79 err
= got_object_open(&obj
, repo
, id
);
84 case GOT_OBJ_TYPE_COMMIT
:
85 case GOT_OBJ_TYPE_TREE
:
86 case GOT_OBJ_TYPE_BLOB
:
87 case GOT_OBJ_TYPE_TAG
:
91 err
= got_error(GOT_ERR_OBJ_TYPE
);
95 got_object_close(obj
);
99 const struct got_error
*
100 got_object_get_path(char **path
, struct got_object_id
*id
,
101 struct got_repository
*repo
)
103 const struct got_error
*err
= NULL
;
109 path_objects
= got_repo_get_path_objects(repo
);
110 if (path_objects
== NULL
)
111 return got_error_from_errno("got_repo_get_path_objects");
113 err
= got_object_id_str(&hex
, id
);
117 if (asprintf(path
, "%s/%.2x/%s", path_objects
,
118 id
->sha1
[0], hex
+ 2) == -1)
119 err
= got_error_from_errno("asprintf");
127 const struct got_error
*
128 got_object_open_loose_fd(int *fd
, struct got_object_id
*id
,
129 struct got_repository
*repo
)
131 const struct got_error
*err
= NULL
;
134 err
= got_object_get_path(&path
, id
, repo
);
137 *fd
= open(path
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
139 err
= got_error_from_errno2("open", path
);
147 const struct got_error
*
148 got_object_open_by_id_str(struct got_object
**obj
, struct got_repository
*repo
,
151 struct got_object_id id
;
153 if (!got_parse_sha1_digest(id
.sha1
, id_str
))
154 return got_error_path(id_str
, GOT_ERR_BAD_OBJ_ID_STR
);
156 return got_object_open(obj
, repo
, &id
);
159 const struct got_error
*
160 got_object_resolve_id_str(struct got_object_id
**id
,
161 struct got_repository
*repo
, const char *id_str
)
163 const struct got_error
*err
= NULL
;
164 struct got_object
*obj
;
166 err
= got_object_open_by_id_str(&obj
, repo
, id_str
);
170 *id
= got_object_id_dup(got_object_get_id(obj
));
171 got_object_close(obj
);
173 return got_error_from_errno("got_object_id_dup");
178 const struct got_error
*
179 got_object_qid_alloc(struct got_object_qid
**qid
, struct got_object_id
*id
)
181 *qid
= calloc(1, sizeof(**qid
));
183 return got_error_from_errno("calloc");
185 memcpy(&(*qid
)->id
, id
, sizeof((*qid
)->id
));
189 const struct got_error
*
190 got_object_id_queue_copy(const struct got_object_id_queue
*src
,
191 struct got_object_id_queue
*dest
)
193 const struct got_error
*err
;
194 struct got_object_qid
*qid
;
196 STAILQ_FOREACH(qid
, src
, entry
) {
197 struct got_object_qid
*new;
199 * Deep-copy the object ID only. Let the caller deal
200 * with setting up the new->data pointer if needed.
202 err
= got_object_qid_alloc(&new, &qid
->id
);
204 got_object_id_queue_free(dest
);
207 STAILQ_INSERT_TAIL(dest
, new, entry
);
214 got_object_tree_get_nentries(struct got_tree_object
*tree
)
216 return tree
->nentries
;
219 struct got_tree_entry
*
220 got_object_tree_get_first_entry(struct got_tree_object
*tree
)
222 return got_object_tree_get_entry(tree
, 0);
225 struct got_tree_entry
*
226 got_object_tree_get_last_entry(struct got_tree_object
*tree
)
228 return got_object_tree_get_entry(tree
, tree
->nentries
- 1);
231 struct got_tree_entry
*
232 got_object_tree_get_entry(struct got_tree_object
*tree
, int i
)
234 if (i
< 0 || i
>= tree
->nentries
)
236 return &tree
->entries
[i
];
240 got_tree_entry_get_mode(struct got_tree_entry
*te
)
246 got_tree_entry_get_name(struct got_tree_entry
*te
)
251 struct got_object_id
*
252 got_tree_entry_get_id(struct got_tree_entry
*te
)
257 const struct got_error
*
258 got_object_blob_read_to_str(char **s
, struct got_blob_object
*blob
)
260 const struct got_error
*err
= NULL
;
261 size_t len
, totlen
, hdrlen
, offset
;
265 hdrlen
= got_object_blob_get_hdrlen(blob
);
271 err
= got_object_blob_read_block(&len
, blob
);
278 totlen
+= len
- hdrlen
;
279 p
= realloc(*s
, totlen
+ 1);
281 err
= got_error_from_errno("realloc");
287 /* Skip blob object header first time around. */
289 got_object_blob_get_read_buf(blob
) + hdrlen
, len
- hdrlen
);
298 const struct got_error
*
299 got_tree_entry_get_symlink_target(char **link_target
, struct got_tree_entry
*te
,
300 struct got_repository
*repo
)
302 const struct got_error
*err
= NULL
;
303 struct got_blob_object
*blob
= NULL
;
308 if (!got_object_tree_entry_is_symlink(te
))
309 return got_error(GOT_ERR_TREE_ENTRY_TYPE
);
311 fd
= got_opentempfd();
313 err
= got_error_from_errno("got_opentempfd");
317 err
= got_object_open_as_blob(&blob
, repo
,
318 got_tree_entry_get_id(te
), PATH_MAX
, fd
);
322 err
= got_object_blob_read_to_str(link_target
, blob
);
324 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
325 err
= got_error_from_errno("close");
327 got_object_blob_close(blob
);
336 got_tree_entry_get_index(struct got_tree_entry
*te
)
341 struct got_tree_entry
*
342 got_tree_entry_get_next(struct got_tree_object
*tree
,
343 struct got_tree_entry
*te
)
345 return got_object_tree_get_entry(tree
, te
->idx
+ 1);
348 struct got_tree_entry
*
349 got_tree_entry_get_prev(struct got_tree_object
*tree
,
350 struct got_tree_entry
*te
)
352 return got_object_tree_get_entry(tree
, te
->idx
- 1);
355 const struct got_error
*
356 got_object_blob_close(struct got_blob_object
*blob
)
358 const struct got_error
*err
= NULL
;
359 free(blob
->read_buf
);
360 if (blob
->f
&& fclose(blob
->f
) == EOF
)
361 err
= got_error_from_errno("fclose");
368 got_object_blob_rewind(struct got_blob_object
*blob
)
375 got_object_blob_id_str(struct got_blob_object
*blob
, char *buf
, size_t size
)
377 return got_object_id_hex(&blob
->id
, buf
, size
);
381 got_object_blob_get_hdrlen(struct got_blob_object
*blob
)
387 got_object_blob_get_read_buf(struct got_blob_object
*blob
)
389 return blob
->read_buf
;
392 const struct got_error
*
393 got_object_blob_read_block(size_t *outlenp
, struct got_blob_object
*blob
)
397 n
= fread(blob
->read_buf
, 1, blob
->blocksize
, blob
->f
);
398 if (n
== 0 && ferror(blob
->f
))
399 return got_ferror(blob
->f
, GOT_ERR_IO
);
404 const struct got_error
*
405 got_object_blob_is_binary(int *binary
, struct got_blob_object
*blob
)
407 const struct got_error
*err
;
411 hdrlen
= got_object_blob_get_hdrlen(blob
);
413 if (fseeko(blob
->f
, hdrlen
, SEEK_SET
) == -1)
414 return got_error_from_errno("fseeko");
416 err
= got_object_blob_read_block(&len
, blob
);
420 *binary
= memchr(blob
->read_buf
, '\0', len
) != NULL
;
422 if (fseeko(blob
->f
, hdrlen
, SEEK_SET
) == -1)
423 return got_error_from_errno("fseeko");
427 const struct got_error
*
428 got_object_blob_getline(char **line
, ssize_t
*linelen
, size_t *linesize
,
429 struct got_blob_object
*blob
)
431 *linelen
= getline(line
, linesize
, blob
->f
);
432 if (*linelen
== -1 && !feof(blob
->f
))
433 return got_error_from_errno("getline");
437 const struct got_error
*
438 got_object_blob_dump_to_file(off_t
*filesize
, int *nlines
,
439 off_t
**line_offsets
, FILE *outfile
, struct got_blob_object
*blob
)
441 const struct got_error
*err
= NULL
;
442 size_t n
, len
, hdrlen
;
445 const int alloc_chunksz
= 512;
447 off_t off
= 0, total_len
= 0;
450 *line_offsets
= NULL
;
456 hdrlen
= got_object_blob_get_hdrlen(blob
);
458 err
= got_object_blob_read_block(&len
, blob
);
463 buf
= got_object_blob_get_read_buf(blob
);
466 if (line_offsets
&& *line_offsets
== NULL
) {
467 /* Have some data but perhaps no '\n'. */
469 nalloc
= alloc_chunksz
;
470 *line_offsets
= calloc(nalloc
,
471 sizeof(**line_offsets
));
472 if (*line_offsets
== NULL
)
473 return got_error_from_errno("calloc");
475 /* Skip forward over end of first line. */
482 /* Scan '\n' offsets in remaining chunk of data. */
484 if (buf
[i
] != '\n') {
489 if (line_offsets
&& nalloc
< *nlines
) {
490 size_t n
= *nlines
+ alloc_chunksz
;
491 off_t
*o
= recallocarray(*line_offsets
,
492 nalloc
, n
, sizeof(**line_offsets
));
495 *line_offsets
= NULL
;
496 return got_error_from_errno(
503 off
= total_len
+ i
- hdrlen
+ 1;
504 (*line_offsets
)[*nlines
- 1] = off
;
509 /* Skip blob object header first time around. */
510 n
= fwrite(buf
+ hdrlen
, 1, len
- hdrlen
, outfile
);
511 if (n
!= len
- hdrlen
)
512 return got_ferror(outfile
, GOT_ERR_IO
);
513 total_len
+= len
- hdrlen
;
517 if (fflush(outfile
) != 0)
518 return got_error_from_errno("fflush");
522 *filesize
= total_len
;
528 got_object_tag_get_name(struct got_tag_object
*tag
)
534 got_object_tag_get_object_type(struct got_tag_object
*tag
)
536 return tag
->obj_type
;
539 struct got_object_id
*
540 got_object_tag_get_object_id(struct got_tag_object
*tag
)
546 got_object_tag_get_tagger_time(struct got_tag_object
*tag
)
548 return tag
->tagger_time
;
552 got_object_tag_get_tagger_gmtoff(struct got_tag_object
*tag
)
554 return tag
->tagger_gmtoff
;
558 got_object_tag_get_tagger(struct got_tag_object
*tag
)
564 got_object_tag_get_message(struct got_tag_object
*tag
)
569 static struct got_tree_entry
*
570 find_entry_by_name(struct got_tree_object
*tree
, const char *name
, size_t len
)
574 /* Note that tree entries are sorted in strncmp() order. */
575 for (i
= 0; i
< tree
->nentries
; i
++) {
576 struct got_tree_entry
*te
= &tree
->entries
[i
];
577 int cmp
= strncmp(te
->name
, name
, len
);
582 if (te
->name
[len
] == '\0')
588 struct got_tree_entry
*
589 got_object_tree_find_entry(struct got_tree_object
*tree
, const char *name
)
591 return find_entry_by_name(tree
, name
, strlen(name
));
594 const struct got_error
*
595 got_object_tree_find_path(struct got_object_id
**id
, mode_t
*mode
,
596 struct got_repository
*repo
, struct got_tree_object
*tree
,
599 const struct got_error
*err
= NULL
;
600 struct got_tree_object
*subtree
= NULL
;
601 struct got_tree_entry
*te
= NULL
;
614 struct got_tree_object
*next_tree
;
623 te
= find_entry_by_name(subtree
, seg
, seglen
);
625 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
636 err
= got_object_open_as_tree(&next_tree
, repo
,
642 got_object_tree_close(subtree
);
648 *id
= got_object_id_dup(&te
->id
);
650 return got_error_from_errno("got_object_id_dup");
654 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
656 if (subtree
&& subtree
!= tree
)
657 got_object_tree_close(subtree
);
661 const struct got_error
*
662 got_object_id_by_path(struct got_object_id
**id
, struct got_repository
*repo
,
663 struct got_commit_object
*commit
, const char *path
)
665 const struct got_error
*err
= NULL
;
666 struct got_tree_object
*tree
= NULL
;
670 /* Handle opening of root of commit's tree. */
671 if (got_path_is_root_dir(path
)) {
672 *id
= got_object_id_dup(commit
->tree_id
);
674 err
= got_error_from_errno("got_object_id_dup");
676 err
= got_object_open_as_tree(&tree
, repo
, commit
->tree_id
);
679 err
= got_object_tree_find_path(id
, NULL
, repo
, tree
, path
);
683 got_object_tree_close(tree
);
688 * Normalize file mode bits to avoid false positive tree entry differences
689 * in case tree entries have unexpected mode bits set.
692 normalize_mode_for_comparison(mode_t mode
)
695 * For directories, the only relevant bit is the IFDIR bit.
696 * This allows us to detect paths changing from a directory
697 * to a file and vice versa.
700 return mode
& S_IFDIR
;
703 * For symlinks, the only relevant bit is the IFLNK bit.
704 * This allows us to detect paths changing from a symlinks
705 * to a file or directory and vice versa.
708 return mode
& S_IFLNK
;
710 /* For files, the only change we care about is the executable bit. */
711 return mode
& S_IXUSR
;
714 const struct got_error
*
715 got_object_tree_path_changed(int *changed
,
716 struct got_tree_object
*tree01
, struct got_tree_object
*tree02
,
717 const char *path
, struct got_repository
*repo
)
719 const struct got_error
*err
= NULL
;
720 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
721 struct got_tree_entry
*te1
= NULL
, *te2
= NULL
;
727 /* We not do support comparing the root path. */
728 if (got_path_is_root_dir(path
))
729 return got_error_path(path
, GOT_ERR_BAD_PATH
);
739 struct got_tree_object
*next_tree1
, *next_tree2
;
749 te1
= find_entry_by_name(tree1
, seg
, seglen
);
751 err
= got_error(GOT_ERR_NO_OBJ
);
756 te2
= find_entry_by_name(tree2
, seg
, seglen
);
759 mode1
= normalize_mode_for_comparison(te1
->mode
);
760 mode2
= normalize_mode_for_comparison(te2
->mode
);
761 if (mode1
!= mode2
) {
766 if (got_object_id_cmp(&te1
->id
, &te2
->id
) == 0) {
772 if (*s
== '\0') { /* final path element */
781 err
= got_object_open_as_tree(&next_tree1
, repo
,
787 got_object_tree_close(tree1
);
791 err
= got_object_open_as_tree(&next_tree2
, repo
,
797 got_object_tree_close(tree2
);
801 got_object_tree_close(tree2
);
807 if (tree1
&& tree1
!= tree01
)
808 got_object_tree_close(tree1
);
809 if (tree2
&& tree2
!= tree02
)
810 got_object_tree_close(tree2
);
814 const struct got_error
*
815 got_object_tree_entry_dup(struct got_tree_entry
**new_te
,
816 struct got_tree_entry
*te
)
818 const struct got_error
*err
= NULL
;
820 *new_te
= calloc(1, sizeof(**new_te
));
822 return got_error_from_errno("calloc");
824 (*new_te
)->mode
= te
->mode
;
825 memcpy((*new_te
)->name
, te
->name
, sizeof((*new_te
)->name
));
826 memcpy(&(*new_te
)->id
, &te
->id
, sizeof((*new_te
)->id
));
831 got_object_tree_entry_is_submodule(struct got_tree_entry
*te
)
833 return (te
->mode
& S_IFMT
) == (S_IFDIR
| S_IFLNK
);
837 got_object_tree_entry_is_symlink(struct got_tree_entry
*te
)
839 /* S_IFDIR check avoids confusing symlinks with submodules. */
840 return ((te
->mode
& (S_IFDIR
| S_IFLNK
)) == S_IFLNK
);
843 static const struct got_error
*
844 resolve_symlink(char **link_target
, const char *path
,
845 struct got_commit_object
*commit
, struct got_repository
*repo
)
847 const struct got_error
*err
= NULL
;
849 char *name
, *parent_path
= NULL
;
850 struct got_object_id
*tree_obj_id
= NULL
;
851 struct got_tree_object
*tree
= NULL
;
852 struct got_tree_entry
*te
= NULL
;
856 if (strlcpy(buf
, path
, sizeof(buf
)) >= sizeof(buf
))
857 return got_error(GOT_ERR_NO_SPACE
);
859 name
= basename(buf
);
861 return got_error_from_errno2("basename", path
);
863 err
= got_path_dirname(&parent_path
, path
);
867 err
= got_object_id_by_path(&tree_obj_id
, repo
, commit
,
870 if (err
->code
== GOT_ERR_NO_TREE_ENTRY
) {
871 /* Display the complete path in error message. */
872 err
= got_error_path(path
, err
->code
);
877 err
= got_object_open_as_tree(&tree
, repo
, tree_obj_id
);
881 te
= got_object_tree_find_entry(tree
, name
);
883 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
887 if (got_object_tree_entry_is_symlink(te
)) {
888 err
= got_tree_entry_get_symlink_target(link_target
, te
, repo
);
891 if (!got_path_is_absolute(*link_target
)) {
893 if (asprintf(&abspath
, "%s/%s", parent_path
,
894 *link_target
) == -1) {
895 err
= got_error_from_errno("asprintf");
899 *link_target
= malloc(PATH_MAX
);
900 if (*link_target
== NULL
) {
901 err
= got_error_from_errno("malloc");
904 err
= got_canonpath(abspath
, *link_target
, PATH_MAX
);
914 got_object_tree_close(tree
);
922 const struct got_error
*
923 got_object_resolve_symlinks(char **link_target
, const char *path
,
924 struct got_commit_object
*commit
, struct got_repository
*repo
)
926 const struct got_error
*err
= NULL
;
927 char *next_target
= NULL
;
928 int max_recursion
= 40; /* matches Git */
933 err
= resolve_symlink(&next_target
,
934 *link_target
? *link_target
: path
, commit
, repo
);
939 if (--max_recursion
== 0) {
940 err
= got_error_path(path
, GOT_ERR_RECURSION
);
944 *link_target
= next_target
;
946 } while (next_target
);
952 got_object_commit_retain(struct got_commit_object
*commit
)
957 const struct got_error
*
958 got_object_raw_alloc(struct got_raw_object
**obj
, uint8_t *outbuf
, int *outfd
,
959 size_t max_in_mem_size
, size_t hdrlen
, off_t size
)
961 const struct got_error
*err
= NULL
;
966 *obj
= calloc(1, sizeof(**obj
));
968 err
= got_error_from_errno("calloc");
972 (*obj
)->tempfile_idx
= -1;
975 (*obj
)->data
= outbuf
;
978 if (fstat(*outfd
, &sb
) == -1) {
979 err
= got_error_from_errno("fstat");
983 if (sb
.st_size
!= tot
) {
984 err
= got_error_msg(GOT_ERR_BAD_OBJ_HDR
,
985 "raw object has unexpected size");
988 #ifndef GOT_PACK_NO_MMAP
989 if (tot
> 0 && tot
<= max_in_mem_size
) {
990 (*obj
)->data
= mmap(NULL
, tot
, PROT_READ
,
991 MAP_PRIVATE
, *outfd
, 0);
992 if ((*obj
)->data
== MAP_FAILED
) {
993 if (errno
!= ENOMEM
) {
994 err
= got_error_from_errno("mmap");
1005 (*obj
)->f
= fdopen(*outfd
, "r");
1006 if ((*obj
)->f
== NULL
) {
1007 err
= got_error_from_errno("fdopen");
1013 (*obj
)->hdrlen
= hdrlen
;
1014 (*obj
)->size
= size
;
1018 got_object_raw_close(*obj
);