Skip to content

Commit dccb32b

Browse files
avargitster
authored andcommitted
object-file.c: stop dying in parse_loose_header()
Make parse_loose_header() return error codes and data instead of invoking die() by itself. For now we'll move the relevant die() call to loose_object_info() and read_loose_object() to keep this change smaller. In a subsequent commit we'll make read_loose_object() return an error code instead of dying. We should also address the "allow_unknown" case (should be moved to builtin/cat-file.c), but for now I'll be leaving it. For making parse_loose_header() not die() change its prototype to accept a "struct object_info *" instead of the "unsigned long *sizep" it accepted before. Its callers can now check the populated populated "oi->typep". Because of this we don't need to pass in the "unsigned int flags" which we used for OBJECT_INFO_ALLOW_UNKNOWN_TYPE, we can instead do that check in loose_object_info(). This also refactors some confusing control flow around the "status" variable. In some cases we set it to the return value of "error()", i.e. -1, and later checked if "status < 0" was true. Since 93cff9a (sha1_loose_object_info: return error for corrupted objects, 2017-04-01) the return value of loose_object_info() (then named sha1_loose_object_info()) had been a "status" variable that be any negative value, as we were expecting to return the "enum object_type". The only negative type happens to be OBJ_BAD, but the code still assumed that more might be added. This was then used later in e.g. c84a1f3 (sha1_file: refactor read_object, 2017-06-21). Now that parse_loose_header() will return 0 on success instead of the type (which it'll stick into the "struct object_info") we don't need to conflate these two cases in its callers. Since parse_loose_header() doesn't need to return an arbitrary "status" we only need to treat its "ret < 0" specially, but can idiomatically overwrite it with our own error() return. This along with having made unpack_loose_header() return an "enum unpack_loose_header_result" in an earlier commit means that we can move the previously nested if/else cases mostly into the "ULHR_OK" branch of the "switch" statement. We should be less silent if we reach that "status = -1" branch, which happens if we've got trailing garbage in loose objects, see f6371f9 (sha1_file: add read_loose_object() function, 2017-01-13) for a better way to handle it. For now let's punt on it, a subsequent commit will address that edge case. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5848fb1 commit dccb32b

File tree

3 files changed

+44
-37
lines changed

3 files changed

+44
-37
lines changed

cache.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,9 +1332,16 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
13321332
unsigned long bufsiz,
13331333
struct strbuf *hdrbuf);
13341334

1335+
/**
1336+
* parse_loose_header() parses the starting "<type> <len>\0" of an
1337+
* object. If it doesn't follow that format -1 is returned. To check
1338+
* the validity of the <type> populate the "typep" in the "struct
1339+
* object_info". It will be OBJ_BAD if the object type is unknown. The
1340+
* parsed <len> can be retrieved via "oi->sizep", and from there
1341+
* passed to unpack_loose_rest().
1342+
*/
13351343
struct object_info;
1336-
int parse_loose_header(const char *hdr, struct object_info *oi,
1337-
unsigned int flags);
1344+
int parse_loose_header(const char *hdr, struct object_info *oi);
13381345

13391346
int check_object_signature(struct repository *r, const struct object_id *oid,
13401347
void *buf, unsigned long size, const char *type);

object-file.c

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,8 +1324,7 @@ static void *unpack_loose_rest(git_zstream *stream,
13241324
* too permissive for what we want to check. So do an anal
13251325
* object header parse by hand.
13261326
*/
1327-
int parse_loose_header(const char *hdr, struct object_info *oi,
1328-
unsigned int flags)
1327+
int parse_loose_header(const char *hdr, struct object_info *oi)
13291328
{
13301329
const char *type_buf = hdr;
13311330
unsigned long size;
@@ -1347,15 +1346,6 @@ int parse_loose_header(const char *hdr, struct object_info *oi,
13471346
type = type_from_string_gently(type_buf, type_len, 1);
13481347
if (oi->type_name)
13491348
strbuf_add(oi->type_name, type_buf, type_len);
1350-
/*
1351-
* Set type to 0 if its an unknown object and
1352-
* we're obtaining the type using '--allow-unknown-type'
1353-
* option.
1354-
*/
1355-
if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
1356-
type = 0;
1357-
else if (type < 0)
1358-
die(_("invalid object type"));
13591349
if (oi->typep)
13601350
*oi->typep = type;
13611351

@@ -1382,7 +1372,14 @@ int parse_loose_header(const char *hdr, struct object_info *oi,
13821372
/*
13831373
* The length must be followed by a zero byte
13841374
*/
1385-
return *hdr ? -1 : type;
1375+
if (*hdr)
1376+
return -1;
1377+
1378+
/*
1379+
* The format is valid, but the type may still be bogus. The
1380+
* Caller needs to check its oi->typep.
1381+
*/
1382+
return 0;
13861383
}
13871384

13881385
static int loose_object_info(struct repository *r,
@@ -1396,6 +1393,7 @@ static int loose_object_info(struct repository *r,
13961393
char hdr[MAX_HEADER_LEN];
13971394
struct strbuf hdrbuf = STRBUF_INIT;
13981395
unsigned long size_scratch;
1396+
enum object_type type_scratch;
13991397
int allow_unknown = flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
14001398

14011399
if (oi->delta_base_oid)
@@ -1427,13 +1425,27 @@ static int loose_object_info(struct repository *r,
14271425

14281426
if (!oi->sizep)
14291427
oi->sizep = &size_scratch;
1428+
if (!oi->typep)
1429+
oi->typep = &type_scratch;
14301430

14311431
if (oi->disk_sizep)
14321432
*oi->disk_sizep = mapsize;
14331433

14341434
switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
14351435
allow_unknown ? &hdrbuf : NULL)) {
14361436
case ULHR_OK:
1437+
if (parse_loose_header(hdrbuf.len ? hdrbuf.buf : hdr, oi) < 0)
1438+
status = error(_("unable to parse %s header"), oid_to_hex(oid));
1439+
else if (!allow_unknown && *oi->typep < 0)
1440+
die(_("invalid object type"));
1441+
1442+
if (!oi->contentp)
1443+
break;
1444+
*oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
1445+
if (*oi->contentp)
1446+
goto cleanup;
1447+
1448+
status = -1;
14371449
break;
14381450
case ULHR_BAD:
14391451
status = error(_("unable to unpack %s header"),
@@ -1445,31 +1457,16 @@ static int loose_object_info(struct repository *r,
14451457
break;
14461458
}
14471459

1448-
if (status < 0) {
1449-
/* Do nothing */
1450-
} else if (hdrbuf.len) {
1451-
if ((status = parse_loose_header(hdrbuf.buf, oi, flags)) < 0)
1452-
status = error(_("unable to parse %s header with --allow-unknown-type"),
1453-
oid_to_hex(oid));
1454-
} else if ((status = parse_loose_header(hdr, oi, flags)) < 0)
1455-
status = error(_("unable to parse %s header"), oid_to_hex(oid));
1456-
1457-
if (status >= 0 && oi->contentp) {
1458-
*oi->contentp = unpack_loose_rest(&stream, hdr,
1459-
*oi->sizep, oid);
1460-
if (!*oi->contentp) {
1461-
git_inflate_end(&stream);
1462-
status = -1;
1463-
}
1464-
} else
1465-
git_inflate_end(&stream);
1466-
1460+
git_inflate_end(&stream);
1461+
cleanup:
14671462
munmap(map, mapsize);
14681463
if (oi->sizep == &size_scratch)
14691464
oi->sizep = NULL;
14701465
strbuf_release(&hdrbuf);
1466+
if (oi->typep == &type_scratch)
1467+
oi->typep = NULL;
14711468
oi->whence = OI_LOOSE;
1472-
return (status < 0) ? status : 0;
1469+
return status;
14731470
}
14741471

14751472
int obj_read_use_lock = 0;
@@ -2533,6 +2530,7 @@ int read_loose_object(const char *path,
25332530
git_zstream stream;
25342531
char hdr[MAX_HEADER_LEN];
25352532
struct object_info oi = OBJECT_INFO_INIT;
2533+
oi.typep = type;
25362534
oi.sizep = size;
25372535

25382536
*contents = NULL;
@@ -2549,12 +2547,13 @@ int read_loose_object(const char *path,
25492547
goto out;
25502548
}
25512549

2552-
*type = parse_loose_header(hdr, &oi, 0);
2553-
if (*type < 0) {
2550+
if (parse_loose_header(hdr, &oi) < 0) {
25542551
error(_("unable to parse header of %s"), path);
25552552
git_inflate_end(&stream);
25562553
goto out;
25572554
}
2555+
if (*type < 0)
2556+
die(_("invalid object type"));
25582557

25592558
if (*type == OBJ_BLOB && *size > big_file_threshold) {
25602559
if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)

streaming.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ static int open_istream_loose(struct git_istream *st, struct repository *r,
225225
{
226226
struct object_info oi = OBJECT_INFO_INIT;
227227
oi.sizep = &st->size;
228+
oi.typep = type;
228229

229230
st->u.loose.mapped = map_loose_object(r, oid, &st->u.loose.mapsize);
230231
if (!st->u.loose.mapped)
@@ -238,7 +239,7 @@ static int open_istream_loose(struct git_istream *st, struct repository *r,
238239
case ULHR_TOO_LONG:
239240
goto error;
240241
}
241-
if (parse_loose_header(st->u.loose.hdr, &oi, 0) < 0)
242+
if (parse_loose_header(st->u.loose.hdr, &oi) < 0 || *type < 0)
242243
goto error;
243244

244245
st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;

0 commit comments

Comments
 (0)