scan reflogs independently from refs

Currently, the search for all reflogs depends on the existence of
corresponding refs under the .git/refs/ directory.  Let's scan the
.git/logs/ directory directly instead.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
diff --git a/refs.c b/refs.c
index 4a52308..da09e43 100644
--- a/refs.c
+++ b/refs.c
@@ -1201,3 +1201,53 @@
 	return ret;
 }
 
+static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)
+{
+	DIR *dir = opendir(git_path("logs/%s", base));
+	int retval = errno;
+
+	if (dir) {
+		struct dirent *de;
+		int baselen = strlen(base);
+		char *log = xmalloc(baselen + 257);
+
+		memcpy(log, base, baselen);
+		if (baselen && base[baselen-1] != '/')
+			log[baselen++] = '/';
+
+		while ((de = readdir(dir)) != NULL) {
+			struct stat st;
+			int namelen;
+
+			if (de->d_name[0] == '.')
+				continue;
+			namelen = strlen(de->d_name);
+			if (namelen > 255)
+				continue;
+			if (has_extension(de->d_name, ".lock"))
+				continue;
+			memcpy(log + baselen, de->d_name, namelen+1);
+			if (stat(git_path("logs/%s", log), &st) < 0)
+				continue;
+			if (S_ISDIR(st.st_mode)) {
+				retval = do_for_each_reflog(log, fn, cb_data);
+			} else {
+				unsigned char sha1[20];
+				if (!resolve_ref(log, sha1, 0, NULL))
+					retval = error("bad ref for %s", log);
+				else
+					retval = fn(log, sha1, 0, cb_data);
+			}
+			if (retval)
+				break;
+		}
+		free(log);
+		closedir(dir);
+	}
+	return retval;
+}
+
+int for_each_reflog(each_ref_fn fn, void *cb_data)
+{
+	return do_for_each_reflog("", fn, cb_data);
+}