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

Re: [GSoC][PATCH 2/2] clone: use dir-iterator to avoid explicit dir traversal

From
Matheus Tavares Bernardino <matheus.bernardino@usp.br>
Date
Feb 18, 2019, 21:13 UTC
Message-ID
<CAHd-oW60a+zz9J+u0HiRuTy-FKYN4s95fCcR3mgJz0hUokhTCQ@mail.gmail.com>
In-Reply-To
<20190216143824.GJ6085@hank.intra.tgummerer.com>
On Sat, Feb 16, 2019 at 12:38 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:
Show 29 quoted lines
>
> On 02/15, Matheus Tavares wrote:
> > Replace usage of opendir/readdir/closedir API to traverse directories
> > recursively, at copy_or_link_directory function, by the dir-iterator
> > API.
> >
> > Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
> > ---
> >  builtin/clone.c | 39 +++++++++++++++++++--------------------
> >  1 file changed, 19 insertions(+), 20 deletions(-)
> >
> > diff --git a/builtin/clone.c b/builtin/clone.c
> > index 2a1cc4dab9..66ae347f79 100644
> > --- a/builtin/clone.c
> > +++ b/builtin/clone.c
> > @@ -23,6 +23,8 @@
> >  #include "transport.h"
> >  #include "strbuf.h"
> >  #include "dir.h"
> > +#include "dir-iterator.h"
> > +#include "iterator.h"
> >  #include "sigchain.h"
> >  #include "branch.h"
> >  #include "remote.h"
> > @@ -413,40 +415,33 @@ static void mkdir_if_missing(const char *pathname, mode_t mode)
> >  static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
> >                                  const char *src_repo, int src_baselen)
> >  {
>
Hi, Thomas. Thanks for the review.
Show 6 quoted lines
> The src_baselen parameter is now unused, and should be removed.  Our
> codebase currently doesn't compile with -Wunused-parameter, so this is
> not something the compiler can catch at the moment unfortunately.
> However there is some work going on towards removing unused parameter
> from the codebase, so it would be nice to not make things worse here.
>
Nice! I will fix that in v2.
Show 40 quoted lines
> *1*: https://public-inbox.org/git/20190214054736.GA20091@sigill.intra.peff.net
>
> > -     struct dirent *de;
> > -     struct stat buf;
> >       int src_len, dest_len;
> > -     DIR *dir;
> > -
> > -     dir = opendir(src->buf);
> > -     if (!dir)
> > -             die_errno(_("failed to open '%s'"), src->buf);
> > +     struct dir_iterator *iter;
> > +     int iter_status;
> >
> >       mkdir_if_missing(dest->buf, 0777);
> >
> > +     iter = dir_iterator_begin(src->buf);
> > +
> >       strbuf_addch(src, '/');
> >       src_len = src->len;
> >       strbuf_addch(dest, '/');
> >       dest_len = dest->len;
> >
> > -     while ((de = readdir(dir)) != NULL) {
> > +     while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
> >               strbuf_setlen(src, src_len);
> > -             strbuf_addstr(src, de->d_name);
> > +             strbuf_addstr(src, iter->relative_path);
> >               strbuf_setlen(dest, dest_len);
> > -             strbuf_addstr(dest, de->d_name);
> > -             if (stat(src->buf, &buf)) {
> > -                     warning (_("failed to stat %s\n"), src->buf);
> > -                     continue;
> > -             }
>
> Why was this warning removed?  I don't see a corresponding warning in
> the iterator API.  The one thing the iterator API is doing is that it
> does an lstat on the path to check if it exists.  However that does
> not follow symlinks, and ignores possible other errors such as
> permission errors.
>

You are right. I didn't know the differences from lstat and stat. And reflecting on this now, I realize that the problem is even deeper: copy_or_link_directory follows symlinks but dir-iterator don't, so I cannot use dir-iterator without falling back to recursion on copy_or_link_directory. Because of that, I thought off adding an option for dir-iterator to follow symlinks. Does this seem like a good idea?

Also, I just noticed that dir-iterator follows hidden paths while copy_or_link_directory don't. Maybe another option to add for dir-iterator?

Show 42 quoted lines
> If there is a good reason to remove the warning, that would be useful
> to describe in the commit message.
>
> > -             if (S_ISDIR(buf.st_mode)) {
> > -                     if (de->d_name[0] != '.')
> > -                             copy_or_link_directory(src, dest,
> > -                                                    src_repo, src_baselen);
> > +             strbuf_addstr(dest, iter->relative_path);
> > +
> > +             if (S_ISDIR(iter->st.st_mode)) {
> > +                     if (iter->basename[0] != '.')
> > +                             mkdir_if_missing(dest->buf, 0777);
> >                       continue;
> >               }
> >
> >               /* Files that cannot be copied bit-for-bit... */
> > -             if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
> > +             if (!strcmp(iter->relative_path, "info/alternates")) {
> >                       copy_alternates(src, dest, src_repo);
> >                       continue;
> >               }
> > @@ -463,7 +458,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
> >               if (copy_file_with_time(dest->buf, src->buf, 0666))
> >                       die_errno(_("failed to copy file to '%s'"), dest->buf);
> >       }
> > -     closedir(dir);
> > +
> > +     if (iter_status != ITER_DONE) {
> > +             strbuf_setlen(src, src_len);
> > +             die(_("failed to iterate over '%s'"), src->buf);
> > +     }
>
> Interestingly enough, this is not something that can currently
> happen if I read the dir-iterator code correctly.  Even though the
> dir_iterator_advance function says it can return ITER_ERROR, it never
> actually does.  The only way the iter_status can be not ITER_DONE at
> this point is if we would 'break' out of the loop.
>
> I don't think it hurts to be defensive here in case someone decides to
> break out of the loop in the future, just something odd I noticed
> while reviewing the code.
>

Yes, I also noticed that. But I thought it would be nice to make this check so that this code stays consistent to the documentation at dir-iterator.h (although implementation is different).

Something I just noticed now is that copy_or_link_directory dies upon an opendir error, but dir-iterator just prints a warning and keeps going (looking for another file/dir to return for the caller). Is this ok? Or should I, perhaps, add a "pedantic" option to dir-iterator so that, when enabled, it immediately returns ITER_ERROR when an error occurs instead of keep going?

I'm proposing some new options to dir-iterator because as the patch that adds it says "There are obviously a lot of features that could easily be added to this class", and maybe those would be useful for other dir-iterator users. But I don't know if that would be the best way of doing it, so any feedback on this will be much appreciated. Also, I saw on public-inbox[1] a patchset from 2017 proposing new features/options for dir-iterator, but I don't really know if (and why) it was rejected. (I couldn't find the patches on master/pu log)

[1] https://public-inbox.org/git/1493226219-33423-1-git-send-email-bnmvco@gmail.com/

Thanks, Matheus Tavares

Show 6 quoted lines
> >  }
> >
> >  static void clone_local(const char *src_repo, const char *dest_repo)
> > --
> > 2.20.1
> >
Previous: Thomas GummererNext: Thomas Gummerer
Message 8 of 14 in “clone: convert explicit traversal to”
  1. Matheus TavaresFeb 15, 2019
  2. [GSoC][PATCH 1/2] clone: extract function from copy_or_link_directoryMatheus Tavares, Feb 15, 2019
  3. Christian CouderFeb 16, 2019
  4. Matheus Tavares BernardinoFeb 18, 2019
  5. [GSoC][PATCH 2/2] clone: use dir-iterator to avoid explicit dir traversalMatheus Tavares, Feb 15, 2019
  6. Christian CouderFeb 16, 2019
  7. Thomas GummererFeb 16, 2019
  8. Matheus Tavares BernardinoFeb 18, 2019
  9. Thomas GummererFeb 18, 2019
  10. Matheus Tavares BernardinoFeb 19, 2019
  11. Thomas GummererFeb 19, 2019
  12. Matheus Tavares BernardinoFeb 21, 2019
  13. Thomas GummererFeb 21, 2019
  14. Daniel Ferreira (theiostream)Feb 22, 2019

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.