git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Jeff King <peff@peff.net>
To: git@vger.kernel.org
Cc: Alexey Muranov <alexey.muranov@gmail.com>
Subject: [PATCH 2/3] teach sha1_name to look in graveyard reflogs
Date: Thu, 19 Jul 2012 17:33:26 -0400	[thread overview]
Message-ID: <20120719213326.GB20385@sigill.intra.peff.net> (raw)
In-Reply-To: <20120719213225.GA20311@sigill.intra.peff.net>

The previous commit introduced graveyard reflogs, where the
reflog for a deleted branch "foo" appears in
"logs/graveyard/refs/heads/foo~".

This patch teaches dwim_log to search for these logs if the
ref does not exist, and teaches read_ref_at to fall back to
them when the literal reflog does not exist.  This allows
"deleted@{1}" to refer to the final commit of a deleted
branch (either to view or to re-create the branch).  You can
also go further back, or refer to the deleted reflog entries
by time. Accessing deleted@{0} will yield the null sha1.

Similarly, for_each_reflog_ent learns to fallback to
graveyard refs, which allows the reflog walker to work.
However, this is slightly less friendly, as the revision
parser expects the matching ref to exist before it realizes
that we are interested in the reflog. Therefore you must use
"git log -g deleted@{1}" insted of "git log -g deleted" to
walk a deleted reflog.

In both cases, we also tighten up the mode-checking when
opening the reflogs. dwim_log checks that the entry we found
is a regular file (not a directory) to avoid D/F confusion
(e.g., you ask for "foo" but "foo/bar" exists and we find
the "foo" but it is a directory).

However, read_ref_at and for_each_reflog_ent did not do this
check, and relied on earlier parts of the code to have
verified the log they are about to open. This meant that
even before this patch, a race condition in changing refs
between dwim_log and the actual read could cause bizarre
errors (e.g., read_ref_at would open and try to mmap a
directory). This patch makes it even easier to trigger those
conditions (because the ref namespace and the fallback
graveyard namespace can have D/F ambiguity for a certain
path). To solve this, we check the mode of the file we open
and treat it as if it did not exist if it is not a regular
file (this is the same way dwim_log handles it).

Signed-off-by: Jeff King <peff@peff.net>
---
 refs.c | 46 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 11 deletions(-)

diff --git a/refs.c b/refs.c
index 553de77..551a0f9 100644
--- a/refs.c
+++ b/refs.c
@@ -1590,9 +1590,16 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 
 		mksnpath(path, sizeof(path), *p, len, str);
 		ref = resolve_ref_unsafe(path, hash, 1, NULL);
-		if (!ref)
-			continue;
-		if (!stat(git_path("logs/%s", path), &st) &&
+		if (!ref) {
+			if (!stat(refname_to_graveyard_reflog(path), &st) &&
+			    S_ISREG(st.st_mode)) {
+				it = path;
+				hashcpy(hash, null_sha1);
+			}
+			else
+				continue;
+		}
+		else if (!stat(git_path("logs/%s", path), &st) &&
 		    S_ISREG(st.st_mode))
 			it = path;
 		else if (strcmp(ref, path) &&
@@ -2201,9 +2208,16 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
 
 	logfile = git_path("logs/%s", refname);
 	logfd = open(logfile, O_RDONLY, 0);
-	if (logfd < 0)
-		die_errno("Unable to read log '%s'", logfile);
-	fstat(logfd, &st);
+	if (logfd < 0 || fstat(logfd, &st) < 0 || !S_ISREG(st.st_mode)) {
+		const char *deleted_log = refname_to_graveyard_reflog(refname);
+
+		if (logfd >= 0)
+			close(logfd);
+		logfd = open(deleted_log, O_RDONLY);
+		if (logfd < 0 || fstat(logfd, &st) < 0 || !S_ISREG(st.st_mode))
+			die_errno("Unable to read log '%s'", logfile);
+		logfile = deleted_log;
+	}
 	if (!st.st_size)
 		die("Log %s is empty.", logfile);
 	mapsz = xsize_t(st.st_size);
@@ -2296,18 +2310,28 @@ int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long
 {
 	const char *logfile;
 	FILE *logfp;
+	struct stat st;
 	struct strbuf sb = STRBUF_INIT;
 	int ret = 0;
 
 	logfile = git_path("logs/%s", refname);
 	logfp = fopen(logfile, "r");
-	if (!logfp)
-		return -1;
+	if (!logfp || fstat(fileno(logfp), &st) < 0 || !S_ISREG(st.st_mode)) {
+		logfile = refname_to_graveyard_reflog(refname);
+
+		if (logfp)
+			fclose(logfp);
+		logfp = fopen(logfile, "r");
+		if (!logfp)
+			return -1;
+		if (fstat(fileno(logfp), &st) < 0 || !S_ISREG(st.st_mode)) {
+			fclose(logfp);
+			return -1;
+		}
+	}
 
 	if (ofs) {
-		struct stat statbuf;
-		if (fstat(fileno(logfp), &statbuf) ||
-		    statbuf.st_size < ofs ||
+		if (st.st_size < ofs ||
 		    fseek(logfp, -ofs, SEEK_END) ||
 		    strbuf_getwholeline(&sb, logfp, '\n')) {
 			fclose(logfp);
-- 
1.7.10.5.40.g059818d

  parent reply	other threads:[~2012-07-19 21:33 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-19  7:30 Feature request: fetch --prune by default Alexey Muranov
2012-07-19 11:55 ` Jeff King
2012-07-19 14:03   ` Dan Johnson
2012-07-19 15:11     ` Stefan Haller
2012-08-16 23:22     ` Junio C Hamano
2012-08-21  6:51       ` Jeff King
2013-06-20 19:22     ` Sam Roberts
2012-07-19 16:21   ` Alexey Muranov
2012-07-19 17:34     ` Konstantin Khomoutov
2012-07-19 21:20       ` Alexey Muranov
2012-07-19 21:57         ` Alexey Muranov
2012-07-20  7:11         ` Johannes Sixt
2012-07-20  7:28           ` Alexey Muranov
2012-08-16 23:27             ` Junio C Hamano
2012-07-19 16:40   ` Alexey Muranov
2012-07-19 16:48     ` Dan Johnson
2012-07-19 16:51       ` Alexey Muranov
2012-07-19 21:32   ` [RFC/PATCH 0/3] reflog graveyard Jeff King
2012-07-19 21:33     ` [PATCH 1/3] retain reflogs for deleted refs Jeff King
2012-07-19 22:23       ` Alexey Muranov
2012-07-20 14:26         ` Jeff King
2012-07-20 14:32           ` Alexey Muranov
2012-07-19 22:36       ` Junio C Hamano
2012-07-20 14:43         ` Jeff King
2012-07-20 15:07           ` Jeff King
2012-07-20 15:39             ` Junio C Hamano
2012-07-20 15:42           ` Junio C Hamano
2012-07-20 15:50             ` Jeff King
2012-08-16 23:29         ` Junio C Hamano
2012-07-20  9:49       ` Michael Haggerty
2012-07-20 15:44         ` Jeff King
2012-07-20 16:37           ` Johannes Sixt
2012-07-20 17:09             ` Jeff King
2012-07-22 11:03               ` Alexey Muranov
2012-07-26 12:47               ` Nguyen Thai Ngoc Duy
2012-07-26 16:26                 ` Alexey Muranov
2012-07-26 16:41                   ` Matthieu Moy
2012-07-26 16:59                     ` Jeff King
2012-07-26 17:24                       ` Alexey Muranov
2012-07-26 17:46               ` Junio C Hamano
2012-07-26 17:52                 ` Jeff King
2012-07-22 11:10           ` Alexey Muranov
2012-07-22 11:12             ` Alexey Muranov
2012-07-22 13:14             ` Jeff King
2012-07-22 14:40               ` Alexey Muranov
2012-07-22 15:50                 ` Jeff King
2012-07-20 16:32         ` Johannes Sixt
2012-08-18 17:14       ` [RFC 0/3] Reflogs for deleted refs: fix breakage and suggest namespace change mhagger
2012-08-18 17:14         ` [RFC 1/3] t9300: format test in modern style prior to modifying it mhagger
2012-08-18 17:14         ` [RFC 2/3] Delete reflogs for dead references to allow pruning mhagger
2012-08-21  8:33           ` Jeff King
2012-08-18 17:14         ` [RFC 3/3] Change naming convention for the reflog graveyard mhagger
2012-08-18 20:39         ` [RFC 0/3] Reflogs for deleted refs: fix breakage and suggest namespace change Junio C Hamano
2012-08-18 21:11           ` Alexey Muranov
2012-08-19  0:02             ` Junio C Hamano
2012-08-19  7:07               ` Alexey Muranov
2012-08-19  7:15               ` Alexey Muranov
2012-08-19 11:28               ` Alexey Muranov
2012-08-19 17:38                 ` Junio C Hamano
2012-08-19 22:09                   ` Alexey Muranov
2012-08-20  0:26                     ` Junio C Hamano
2012-08-20  1:01                       ` Junio C Hamano
2012-08-20 11:32                       ` Alexey Muranov
2012-08-20 11:57                         ` Alexey Muranov
2012-08-19 13:19           ` Michael Haggerty
2012-08-19 16:27             ` Junio C Hamano
2012-08-21  8:27           ` Jeff King
2012-08-21 17:56             ` Junio C Hamano
2012-07-19 21:33     ` Jeff King [this message]
2012-07-19 22:39       ` [PATCH 2/3] teach sha1_name to look in graveyard reflogs Junio C Hamano
2012-07-20 15:53         ` Jeff King
2012-07-22 20:53           ` Junio C Hamano
2012-07-19 21:33     ` [PATCH 3/3] add tests for reflogs of deleted refs Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120719213326.GB20385@sigill.intra.peff.net \
    --to=peff@peff.net \
    --cc=alexey.muranov@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).