Re: [PATCH 3/4] refs.c: move ref parsing code out of resolve_ref()

2014-07-25 Thread Duy Nguyen
On Fri, Jul 25, 2014 at 11:12 PM, Ronnie Sahlberg  wrote:
>> diff --git a/refs.c b/refs.c
>> index bec2bb1..2769f20 100644
>> --- a/refs.c
>> +++ b/refs.c
>> @@ -1533,6 +1533,105 @@ static int handle_missing_loose_ref(const char 
>> *refname,
>> }
>>  }
>>
>> +int parse_ref(const char *path, struct strbuf *ref,
>> + unsigned char *sha1, int *flag)
>
> Can you make this function static?
> It is not used by anything outside of this series and thus making it
> static avoids growing the public refs api.

It's to be used by builtin/checkout.c in nd/multiple-work-trees. I
could mark it static now and unmark it later, but I'd need to add the
static prototype back in refs.c because in the next patch
resolve_gitlink_ref() uses this function and resolve_gitlink_ref() is
before parse_ref().
-- 
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 3/4] refs.c: move ref parsing code out of resolve_ref()

2014-07-25 Thread Ronnie Sahlberg
Nice.

On Fri, Jul 25, 2014 at 3:43 AM, Nguyễn Thái Ngọc Duy  wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy 
> ---
>  cache.h |  11 
>  refs.c  | 204 
> ++--
>  2 files changed, 120 insertions(+), 95 deletions(-)
>
> diff --git a/cache.h b/cache.h
> index 5ffbafb..40a63d9 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -1003,6 +1003,17 @@ extern int read_ref(const char *refname, unsigned char 
> *sha1);
>  extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, 
> int reading, int *flag);
>  extern char *resolve_refdup(const char *ref, unsigned char *sha1, int 
> reading, int *flag);
>  extern int resolve_ref(const char *refname, struct strbuf *result, unsigned 
> char *sha1, int reading, int *flag);
> +/*
> + * Given a ref in "ref" and its path, returns
> + *
> + * -2  failed to open with ENOENT, the caller is responsible for
> + * checking missing loose ref (see resolve_ref for example)
> + * -1  if there's an error, "ref" can no longer be trusted, "flag" may
> + * be set. errno is valid.
> + *  0  this is a symref, "ref" now contains the linked ref
> + * +1  normal ref, "sha1" is valid
> + */
> +extern int parse_ref(const char *path, struct strbuf *ref, unsigned char 
> *sha1, int *flag);
>
>  extern int dwim_ref(const char *str, int len, unsigned char *sha1, char 
> **ref);
>  extern int dwim_log(const char *str, int len, unsigned char *sha1, char 
> **ref);
> diff --git a/refs.c b/refs.c
> index bec2bb1..2769f20 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -1533,6 +1533,105 @@ static int handle_missing_loose_ref(const char 
> *refname,
> }
>  }
>
> +int parse_ref(const char *path, struct strbuf *ref,
> + unsigned char *sha1, int *flag)

Can you make this function static?
It is not used by anything outside of this series and thus making it
static avoids growing the public refs api.


> +{
> +   struct strbuf buffer = STRBUF_INIT;
> +   struct stat st;
> +   const char *buf;
> +
> +   /*
> +* We might have to loop back here to avoid a race condition:
> +* first we lstat() the file, then we try to read it as a link
> +* or as a file.  But if somebody changes the type of the file
> +* (file <-> directory <-> symlink) between the lstat() and
> +* reading, then we don't want to report that as an error but
> +* rather try again starting with the lstat().
> +*/
> +stat_ref:
> +   if (lstat(path, &st) < 0)
> +   return errno == ENOENT ? -2 : -1;
> +
> +   /* Follow "normalized" - ie "refs/.." symlinks by hand */
> +   if (S_ISLNK(st.st_mode)) {
> +   struct strbuf new_path = STRBUF_INIT;
> +   if (strbuf_readlink(&new_path, path, 256) < 0) {
> +   strbuf_release(&new_path);
> +   if (errno == ENOENT || errno == EINVAL)
> +   /* inconsistent with lstat; retry */
> +   goto stat_ref;
> +   else
> +   return -1;
> +   }
> +   if (starts_with(new_path.buf, "refs/") &&
> +   !check_refname_format(new_path.buf, 0)) {
> +   strbuf_reset(ref);
> +   strbuf_addbuf(ref, &new_path);
> +   if (flag)
> +   *flag |= REF_ISSYMREF;
> +   strbuf_release(&new_path);
> +   return 0;
> +   }
> +   strbuf_release(&new_path);
> +   }
> +
> +   /* Is it a directory? */
> +   if (S_ISDIR(st.st_mode)) {
> +   errno = EISDIR;
> +   return -1;
> +   }
> +
> +   /*
> +* Anything else, just open it and try to use it as
> +* a ref
> +*/
> +   if (strbuf_read_file(&buffer, path, 256) < 0) {
> +   strbuf_release(&buffer);
> +   if (errno == ENOENT)
> +   /* inconsistent with lstat; retry */
> +   goto stat_ref;
> +   else
> +   return -1;
> +   }
> +   strbuf_rtrim(&buffer);
> +
> +   /*
> +* Is it a symbolic ref?
> +*/
> +   if (!skip_prefix(buffer.buf, "ref:", &buf)) {
> +   int ret;
> +   /*
> +* Please note that FETCH_HEAD has a second line
> +* containing other data.
> +*/
> +   if (get_sha1_hex(buffer.buf, sha1) ||
> +   (buffer.buf[40] != '\0' && !isspace(buffer.buf[40]))) {
> +   if (flag)
> +   *flag |= REF_ISBROKEN;
> +   errno = EINVAL;
> +   ret = -1;
> +   } else
> +   ret = 1;
> +   strbuf_release(&buffer);
> +   return ret;
> +   }
> +   

[PATCH 3/4] refs.c: move ref parsing code out of resolve_ref()

2014-07-25 Thread Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 cache.h |  11 
 refs.c  | 204 ++--
 2 files changed, 120 insertions(+), 95 deletions(-)

diff --git a/cache.h b/cache.h
index 5ffbafb..40a63d9 100644
--- a/cache.h
+++ b/cache.h
@@ -1003,6 +1003,17 @@ extern int read_ref(const char *refname, unsigned char 
*sha1);
 extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, 
int reading, int *flag);
 extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, 
int *flag);
 extern int resolve_ref(const char *refname, struct strbuf *result, unsigned 
char *sha1, int reading, int *flag);
+/*
+ * Given a ref in "ref" and its path, returns
+ *
+ * -2  failed to open with ENOENT, the caller is responsible for
+ * checking missing loose ref (see resolve_ref for example)
+ * -1  if there's an error, "ref" can no longer be trusted, "flag" may
+ * be set. errno is valid.
+ *  0  this is a symref, "ref" now contains the linked ref
+ * +1  normal ref, "sha1" is valid
+ */
+extern int parse_ref(const char *path, struct strbuf *ref, unsigned char 
*sha1, int *flag);
 
 extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
diff --git a/refs.c b/refs.c
index bec2bb1..2769f20 100644
--- a/refs.c
+++ b/refs.c
@@ -1533,6 +1533,105 @@ static int handle_missing_loose_ref(const char *refname,
}
 }
 
+int parse_ref(const char *path, struct strbuf *ref,
+ unsigned char *sha1, int *flag)
+{
+   struct strbuf buffer = STRBUF_INIT;
+   struct stat st;
+   const char *buf;
+
+   /*
+* We might have to loop back here to avoid a race condition:
+* first we lstat() the file, then we try to read it as a link
+* or as a file.  But if somebody changes the type of the file
+* (file <-> directory <-> symlink) between the lstat() and
+* reading, then we don't want to report that as an error but
+* rather try again starting with the lstat().
+*/
+stat_ref:
+   if (lstat(path, &st) < 0)
+   return errno == ENOENT ? -2 : -1;
+
+   /* Follow "normalized" - ie "refs/.." symlinks by hand */
+   if (S_ISLNK(st.st_mode)) {
+   struct strbuf new_path = STRBUF_INIT;
+   if (strbuf_readlink(&new_path, path, 256) < 0) {
+   strbuf_release(&new_path);
+   if (errno == ENOENT || errno == EINVAL)
+   /* inconsistent with lstat; retry */
+   goto stat_ref;
+   else
+   return -1;
+   }
+   if (starts_with(new_path.buf, "refs/") &&
+   !check_refname_format(new_path.buf, 0)) {
+   strbuf_reset(ref);
+   strbuf_addbuf(ref, &new_path);
+   if (flag)
+   *flag |= REF_ISSYMREF;
+   strbuf_release(&new_path);
+   return 0;
+   }
+   strbuf_release(&new_path);
+   }
+
+   /* Is it a directory? */
+   if (S_ISDIR(st.st_mode)) {
+   errno = EISDIR;
+   return -1;
+   }
+
+   /*
+* Anything else, just open it and try to use it as
+* a ref
+*/
+   if (strbuf_read_file(&buffer, path, 256) < 0) {
+   strbuf_release(&buffer);
+   if (errno == ENOENT)
+   /* inconsistent with lstat; retry */
+   goto stat_ref;
+   else
+   return -1;
+   }
+   strbuf_rtrim(&buffer);
+
+   /*
+* Is it a symbolic ref?
+*/
+   if (!skip_prefix(buffer.buf, "ref:", &buf)) {
+   int ret;
+   /*
+* Please note that FETCH_HEAD has a second line
+* containing other data.
+*/
+   if (get_sha1_hex(buffer.buf, sha1) ||
+   (buffer.buf[40] != '\0' && !isspace(buffer.buf[40]))) {
+   if (flag)
+   *flag |= REF_ISBROKEN;
+   errno = EINVAL;
+   ret = -1;
+   } else
+   ret = 1;
+   strbuf_release(&buffer);
+   return ret;
+   }
+   if (flag)
+   *flag |= REF_ISSYMREF;
+   while (isspace(*buf))
+   buf++;
+   if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
+   if (flag)
+   *flag |= REF_ISBROKEN;
+   strbuf_release(&buffer);
+   errno = EINVAL;
+   return -1;
+   }
+   strbuf_reset(ref);
+   strbuf_addstr(ref, buf);
+   strbuf_release(&buffer);
+   return 0;
+}
+
 /*