git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Ronnie Sahlberg <sahlberg@google.com>
Date
Jul 25, 2014, 16:12 UTC
Message-ID
<CAL=YDWnWAoCrJn28vGKb=xrKKO=fCN=Uz+nM+eh+dYbHCFYpgQ@mail.gmail.com>
In-Reply-To
<1406285039-22469-4-git-send-email-pclouds@gmail.com>
Nice.
On Fri, Jul 25, 2014 at 3:43 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
Show 38 quoted lines
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  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.

Show 236 quoted lines
> +{
> +       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;
> +}
> +
>  /*
>   * 'result' content will be destroyed. Its value may be undefined if
>   * resolve_ref returns -1.
> @@ -1542,9 +1641,8 @@ static int handle_missing_loose_ref(const char *refname,
>  int resolve_ref(const char *refname, struct strbuf *result,
>                 unsigned char *sha1, int reading, int *flag)
>  {
> -       struct strbuf buffer = STRBUF_INIT;
>         int depth = MAXDEPTH;
> -       int ret = -1;
> +       int ret = 0;
>
>         if (flag)
>                 *flag = 0;
> @@ -1557,108 +1655,24 @@ int resolve_ref(const char *refname, struct strbuf *result,
>         strbuf_reset(result);
>         strbuf_addstr(result, refname);
>
> -       for (;;) {
> +       while (!ret) {
>                 char path[PATH_MAX];
> -               const char *ref = result->buf;
> -               struct stat st;
> -               const char *buf;
>
>                 if (--depth < 0) {
>                         errno = ELOOP;
> +                       ret = -1;
>                         break;
>                 }
>
> -               git_snpath(path, sizeof(path), "%s", ref);
> -
> -               /*
> -                * 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) {
> -                       if (errno == ENOENT)
> -                               ret = handle_missing_loose_ref(ref, sha1,
> -                                                              reading, flag);
> -                       break;
> +               git_snpath(path, sizeof(path), "%s", result->buf);
> +               ret = parse_ref(path, result, sha1, flag);
> +               if (ret == -2) {
> +                       ret = handle_missing_loose_ref(result->buf, sha1,
> +                                                      reading, flag);
> +                       ret = ret ? -1 : 1;
>                 }
> -
> -               /* Follow "normalized" - ie "refs/.." symlinks by hand */
> -               if (S_ISLNK(st.st_mode)) {
> -                       /* no need to reset buffer, strbuf_readlink does that */
> -                       if (strbuf_readlink(&buffer, path, 256) < 0) {
> -                               if (errno == ENOENT || errno == EINVAL)
> -                                       /* inconsistent with lstat; retry */
> -                                       goto stat_ref;
> -                               else
> -                                       break;
> -                       }
> -                       if (starts_with(buffer.buf, "refs/") &&
> -                           !check_refname_format(buffer.buf, 0)) {
> -                               strbuf_reset(result);
> -                               strbuf_addbuf(result, &buffer);
> -                               if (flag)
> -                                       *flag |= REF_ISSYMREF;
> -                               continue;
> -                       }
> -               }
> -
> -               /* Is it a directory? */
> -               if (S_ISDIR(st.st_mode)) {
> -                       errno = EISDIR;
> -                       break;
> -               }
> -
> -               /*
> -                * Anything else, just open it and try to use it as
> -                * a ref
> -                */
> -               strbuf_reset(&buffer);
> -               if (strbuf_read_file(&buffer, path, 256) < 0) {
> -                       if (errno == ENOENT)
> -                               /* inconsistent with lstat; retry */
> -                               goto stat_ref;
> -                       else
> -                               break;
> -               }
> -               strbuf_rtrim(&buffer);
> -
> -               /*
> -                * Is it a symbolic ref?
> -                */
> -               if (!skip_prefix(buffer.buf, "ref:", &buf)) {
> -                       /*
> -                        * 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;
> -                       } else
> -                               ret = 0;
> -                       break;
> -               }
> -               if (flag)
> -                       *flag |= REF_ISSYMREF;
> -               while (isspace(*buf))
> -                       buf++;
> -               if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
> -                       if (flag)
> -                               *flag |= REF_ISBROKEN;
> -                       errno = EINVAL;
> -                       break;
> -               }
> -               strbuf_reset(result);
> -               strbuf_addstr(result, buf);
>         }
> -       strbuf_release(&buffer);
> -       return ret;
> +       return ret > 0 ? 0 : -1;
>  }
>
>  const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
> --
> 1.9.1.346.ga2b5940
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous: Nguyễn Thái Ngọc DuyNext: Duy Nguyen
Message 9 of 11 in “Consolidate ref parsing code”
  1. 0/4 Consolidate ref parsing codeNguyễn Thái Ngọc Duy, Jul 25, 2014
  2. 1/4 strbuf.c: keep errno in strbuf_read_file()Nguyễn Thái Ngọc Duy, Jul 25, 2014
  3. Eric SunshineJul 25, 2014
  4. Michael HaggertySep 26, 2014
  5. 2/4 refs.c: refactor resolve_ref_unsafe() to use strbuf internallyNguyễn Thái Ngọc Duy, Jul 25, 2014
  6. Eric SunshineJul 25, 2014
  7. Junio C HamanoJul 30, 2014
  8. 3/4 refs.c: move ref parsing code out of resolve_ref()Nguyễn Thái Ngọc Duy, Jul 25, 2014
  9. Ronnie SahlbergJul 25, 2014
  10. Duy NguyenJul 26, 2014
  11. 4/4 refs.c: rewrite resolve_gitlink_ref() to use parse_ref()Nguyễn Thái Ngọc Duy, Jul 25, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.