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);