files-backend: break out ref reading

Refactor resolve_ref_1 in terms of a new function read_raw_ref, which is responsible for reading ref data from the ref storage. Later, we will make read_raw_ref a pluggable backend function, and make resolve_ref_unsafe common. Signed-off-by: David Turner <dturner@twopensource.com> Helped-by: Duy Nguyen <pclouds@gmail.com> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Turner committed Apr 7, 2016 at 15:03 UTC 7048653a7351df6049e2306a51b0a06b83aa181b
1 file changed +145 -99
refs/files-backend.c
+145 -99
@@ -1390,6 +1390,141 @@ static int resolve_missing_loose_ref(const char *refname,
1390 return -1;
1391 }
1392
1393 +/*
1394 + * Read a raw ref from the filesystem or packed refs file.
1395 + *
1396 + * If the ref is a sha1, fill in sha1 and return 0.
1397 + *
1398 + * If the ref is symbolic, fill in *symref with the referrent
1399 + * (e.g. "refs/heads/master") and return 0. The caller is responsible
1400 + * for validating the referrent. Set REF_ISSYMREF in flags.
1401 + *
1402 + * If the ref doesn't exist, set errno to ENOENT and return -1.
1403 + *
1404 + * If the ref exists but is neither a symbolic ref nor a sha1, it is
1405 + * broken. Set REF_ISBROKEN in flags, set errno to EINVAL, and return
1406 + * -1.
1407 + *
1408 + * If there is another error reading the ref, set errno appropriately and
1409 + * return -1.
1410 + *
1411 + * Backend-specific flags might be set in flags as well, regardless of
1412 + * outcome.
1413 + *
1414 + * sb_path is workspace: the caller should allocate and free it.
1415 + *
1416 + * It is OK for refname to point into symref. In this case:
1417 + * - if the function succeeds with REF_ISSYMREF, symref will be
1418 + * overwritten and the memory pointed to by refname might be changed
1419 + * or even freed.
1420 + * - in all other cases, symref will be untouched, and therefore
1421 + * refname will still be valid and unchanged.
1422 + */
1423 +static int read_raw_ref(const char *refname, unsigned char *sha1,
1424 + struct strbuf *symref, struct strbuf *sb_path,
1425 + struct strbuf *sb_contents, int *flags)
1426 +{
1427 + const char *path;
1428 + const char *buf;
1429 + struct stat st;
1430 + int fd;
1431 +
1432 + strbuf_reset(sb_path);
1433 + strbuf_git_path(sb_path, "%s", refname);
1434 + path = sb_path->buf;
1435 +
1436 +stat_ref:
1437 + /*
1438 + * We might have to loop back here to avoid a race
1439 + * condition: first we lstat() the file, then we try
1440 + * to read it as a link or as a file. But if somebody
1441 + * changes the type of the file (file <-> directory
1442 + * <-> symlink) between the lstat() and reading, then
1443 + * we don't want to report that as an error but rather
1444 + * try again starting with the lstat().
1445 + */
1446 +
1447 + if (lstat(path, &st) < 0) {
1448 + if (errno != ENOENT)
1449 + return -1;
1450 + if (resolve_missing_loose_ref(refname, sha1, flags)) {
1451 + errno = ENOENT;
1452 + return -1;
1453 + }
1454 + return 0;
1455 + }
1456 +
1457 + /* Follow "normalized" - ie "refs/.." symlinks by hand */
1458 + if (S_ISLNK(st.st_mode)) {
1459 + strbuf_reset(sb_contents);
1460 + if (strbuf_readlink(sb_contents, path, 0) < 0) {
1461 + if (errno == ENOENT || errno == EINVAL)
1462 + /* inconsistent with lstat; retry */
1463 + goto stat_ref;
1464 + else
1465 + return -1;
1466 + }
1467 + if (starts_with(sb_contents->buf, "refs/") &&
1468 + !check_refname_format(sb_contents->buf, 0)) {
1469 + strbuf_swap(sb_contents, symref);
1470 + *flags |= REF_ISSYMREF;
1471 + return 0;
1472 + }
1473 + }
1474 +
1475 + /* Is it a directory? */
1476 + if (S_ISDIR(st.st_mode)) {
1477 + errno = EISDIR;
1478 + return -1;
1479 + }
1480 +
1481 + /*
1482 + * Anything else, just open it and try to use it as
1483 + * a ref
1484 + */
1485 + fd = open(path, O_RDONLY);
1486 + if (fd < 0) {
1487 + if (errno == ENOENT)
1488 + /* inconsistent with lstat; retry */
1489 + goto stat_ref;
1490 + else
1491 + return -1;
1492 + }
1493 + strbuf_reset(sb_contents);
1494 + if (strbuf_read(sb_contents, fd, 256) < 0) {
1495 + int save_errno = errno;
1496 + close(fd);
1497 + errno = save_errno;
1498 + return -1;
1499 + }
1500 + close(fd);
1501 + strbuf_rtrim(sb_contents);
1502 + buf = sb_contents->buf;
1503 + if (starts_with(buf, "ref:")) {
1504 + buf += 4;
1505 + while (isspace(*buf))
1506 + buf++;
1507 +
1508 + strbuf_reset(symref);
1509 + strbuf_addstr(symref, buf);
1510 + *flags |= REF_ISSYMREF;
1511 + return 0;
1512 + }
1513 +
1514 + /*
1515 + * Please note that FETCH_HEAD has additional
1516 + * data after the sha.
1517 + */
1518 + if (get_sha1_hex(buf, sha1) ||
1519 + (buf[40] != '\0' && !isspace(buf[40]))) {
1520 + *flags |= REF_ISBROKEN;
1521 + errno = EINVAL;
1522 + return -1;
1523 + }
1524 +
1525 + return 0;
1526 +}
1527 +
1528 /* This function needs to return a meaningful errno on failure */
1529 static const char *resolve_ref_1(const char *refname,
1530 int resolve_flags,
@@ -1422,118 +1557,29 @@ static const char *resolve_ref_1(const char *refname,
1557 }
1558
1559 for (symref_count = 0; symref_count < MAXDEPTH; symref_count++) {
1425 - const char *path;
1426 - struct stat st;
1427 - int fd;
1560 + int read_flags = 0;
1561
1429 - strbuf_reset(sb_path);
1430 - strbuf_git_path(sb_path, "%s", refname);
1431 - path = sb_path->buf;
1432 -
1433 - /*
1434 - * We might have to loop back here to avoid a race
1435 - * condition: first we lstat() the file, then we try
1436 - * to read it as a link or as a file. But if somebody
1437 - * changes the type of the file (file <-> directory
1438 - * <-> symlink) between the lstat() and reading, then
1439 - * we don't want to report that as an error but rather
1440 - * try again starting with the lstat().
1441 - */
1442 - stat_ref:
1443 - if (lstat(path, &st) < 0) {
1444 - if (errno != ENOENT)
1562 + if (read_raw_ref(refname, sha1, sb_refname,
1563 + sb_path, sb_contents, &read_flags)) {
1564 + *flags |= read_flags;
1565 + if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
1566 return NULL;
1446 - if (resolve_missing_loose_ref(refname, sha1, flags)) {
1447 - if (resolve_flags & RESOLVE_REF_READING) {
1448 - errno = ENOENT;
1449 - return NULL;
1450 - }
1451 - hashclr(sha1);
1452 - }
1453 - if (*flags & REF_BAD_NAME) {
1454 - hashclr(sha1);
1567 + hashclr(sha1);
1568 + if (*flags & REF_BAD_NAME)
1569 *flags |= REF_ISBROKEN;
1456 - }
1570 return refname;
1571 }
1572
1460 - /* Follow "normalized" - ie "refs/.." symlinks by hand */
1461 - if (S_ISLNK(st.st_mode)) {
1462 - strbuf_reset(sb_contents);
1463 - if (strbuf_readlink(sb_contents, path, 0) < 0) {
1464 - if (errno == ENOENT || errno == EINVAL)
1465 - /* inconsistent with lstat; retry */
1466 - goto stat_ref;
1467 - else
1468 - return NULL;
1469 - }
1470 - if (starts_with(sb_contents->buf, "refs/") &&
1471 - !check_refname_format(sb_contents->buf, 0)) {
1472 - strbuf_swap(sb_refname, sb_contents);
1473 - refname = sb_refname->buf;
1474 - *flags |= REF_ISSYMREF;
1475 - if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
1476 - hashclr(sha1);
1477 - return refname;
1478 - }
1479 - continue;
1480 - }
1481 - }
1482 -
1483 - /* Is it a directory? */
1484 - if (S_ISDIR(st.st_mode)) {
1485 - errno = EISDIR;
1486 - return NULL;
1487 - }
1488 -
1489 - /*
1490 - * Anything else, just open it and try to use it as
1491 - * a ref
1492 - */
1493 - fd = open(path, O_RDONLY);
1494 - if (fd < 0) {
1495 - if (errno == ENOENT)
1496 - /* inconsistent with lstat; retry */
1497 - goto stat_ref;
1498 - else
1499 - return NULL;
1500 - }
1501 - strbuf_reset(sb_contents);
1502 - if (strbuf_read(sb_contents, fd, 256) < 0) {
1503 - int save_errno = errno;
1504 - close(fd);
1505 - errno = save_errno;
1506 - return NULL;
1507 - }
1508 - close(fd);
1509 - strbuf_rtrim(sb_contents);
1573 + *flags |= read_flags;
1574
1511 - /*
1512 - * Is it a symbolic ref?
1513 - */
1514 - if (!starts_with(sb_contents->buf, "ref:")) {
1515 - /*
1516 - * Please note that FETCH_HEAD has a second
1517 - * line containing other data.
1518 - */
1519 - if (get_sha1_hex(sb_contents->buf, sha1) ||
1520 - (sb_contents->buf[40] != '\0' && !isspace(sb_contents->buf[40]))) {
1521 - *flags |= REF_ISBROKEN;
1522 - errno = EINVAL;
1523 - return NULL;
1524 - }
1575 + if (!(read_flags & REF_ISSYMREF)) {
1576 if (*flags & REF_BAD_NAME) {
1577 hashclr(sha1);
1578 *flags |= REF_ISBROKEN;
1579 }
1580 return refname;
1581 }
1531 - *flags |= REF_ISSYMREF;
1532 - refname = sb_contents->buf + 4;
1533 - while (isspace(*refname))
1534 - refname++;
1535 - strbuf_reset(sb_refname);
1536 - strbuf_addstr(sb_refname, refname);
1582 +
1583 refname = sb_refname->buf;
1584 if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
1585 hashclr(sha1);