don't scan pack index offsets for large values if pack file is < 2GB This saves an iteration over the entire h->offsets array when opening a pack index which should not contain large offsets in the first place. ok millert@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
diff --git a/lib/got_lib_pack.h b/lib/got_lib_pack.h
index 08e7b0c..5321690 100644
--- a/lib/got_lib_pack.h
+++ b/lib/got_lib_pack.h
@@ -169,7 +169,7 @@ struct got_packfile_obj_data {
} __attribute__((__packed__));
} __attribute__((__packed__));
-const struct got_error *got_packidx_init_hdr(struct got_packidx *, int);
+const struct got_error *got_packidx_init_hdr(struct got_packidx *, int, off_t);
const struct got_error *got_packidx_open(struct got_packidx **,
int, const char *, int);
const struct got_error *got_packidx_close(struct got_packidx *);
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index e35958f..6268cad 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -358,6 +358,7 @@ struct got_imsg_index_pack_progress {
/* Structure for GOT_IMSG_PACKIDX. */
struct got_imsg_packidx {
size_t len;
+ off_t packfile_size;
/* Additionally, a file desciptor is passed via imsg. */
};
diff --git a/lib/pack.c b/lib/pack.c
index 9d93bee..b29f6d2 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -69,7 +69,7 @@ verify_fanout_table(uint32_t *fanout_table)
}
const struct got_error *
-got_packidx_init_hdr(struct got_packidx *p, int verify)
+got_packidx_init_hdr(struct got_packidx *p, int verify, off_t packfile_size)
{
const struct got_error *err = NULL;
struct got_packidx_v2_hdr *h;
@@ -258,13 +258,19 @@ got_packidx_init_hdr(struct got_packidx *p, int verify)
offset += nobj * sizeof(*h->offsets);
/* Large file offsets are contained only in files > 2GB. */
- for (i = 0; i < nobj; i++) {
- uint32_t o = h->offsets[i];
- if (o & htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX))
- p->nlargeobj++;
+ if (verify || packfile_size > 0x7fffffff) {
+ for (i = 0; i < nobj; i++) {
+ uint32_t o = h->offsets[i];
+ if (o & htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX))
+ p->nlargeobj++;
+ }
}
if (p->nlargeobj == 0)
goto checksum;
+ else if (packfile_size <= 0x7fffffff) {
+ err = got_error(GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
if (remain < p->nlargeobj * sizeof(*h->large_offsets)) {
err = got_error(GOT_ERR_BAD_PACKIDX);
@@ -334,7 +340,7 @@ got_packidx_open(struct got_packidx **packidx,
const struct got_error *err = NULL;
struct got_packidx *p = NULL;
char *pack_relpath;
- struct stat sb;
+ struct stat idx_sb, pack_sb;
*packidx = NULL;
@@ -347,7 +353,7 @@ got_packidx_open(struct got_packidx **packidx,
* Some Git repositories have this problem. Git seems to ignore
* the existence of lonely pack index files but we do not.
*/
- if (fstatat(dir_fd, pack_relpath, &sb, 0) == -1) {
+ if (fstatat(dir_fd, pack_relpath, &pack_sb, 0) == -1) {
if (errno == ENOENT) {
err = got_error_fmt(GOT_ERR_LONELY_PACKIDX,
"%s", relpath);
@@ -369,13 +375,13 @@ got_packidx_open(struct got_packidx **packidx,
goto done;
}
- if (fstat(p->fd, &sb) != 0) {
+ if (fstat(p->fd, &idx_sb) != 0) {
err = got_error_from_errno2("fstat", relpath);
close(p->fd);
free(p);
goto done;
}
- p->len = sb.st_size;
+ p->len = idx_sb.st_size;
if (p->len < sizeof(p->hdr)) {
err = got_error(GOT_ERR_BAD_PACKIDX);
close(p->fd);
@@ -400,7 +406,7 @@ got_packidx_open(struct got_packidx **packidx,
}
#endif
- err = got_packidx_init_hdr(p, verify);
+ err = got_packidx_init_hdr(p, verify, pack_sb.st_size);
done:
if (err) {
if (p)
diff --git a/lib/privsep.c b/lib/privsep.c
index 9b4a7ee..274f3c3 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -1737,6 +1737,7 @@ got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack,
int fd;
ipackidx.len = packidx->len;
+ ipackidx.packfile_size = pack->filesize;
fd = dup(packidx->fd);
if (fd == -1)
return got_error_from_errno("dup");
diff --git a/libexec/got-read-pack/got-read-pack.c b/libexec/got-read-pack/got-read-pack.c
index 2013a7a..8fdda11 100644
--- a/libexec/got-read-pack/got-read-pack.c
+++ b/libexec/got-read-pack/got-read-pack.c
@@ -899,7 +899,7 @@ receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
if (p->map == MAP_FAILED)
p->map = NULL; /* fall back to read(2) */
#endif
- err = got_packidx_init_hdr(p, 1);
+ err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
done:
if (err) {
if (imsg.fd != -1)