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

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

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Feb 23, 2019, 21:48 UTC
Message-ID
<20190223214856.GQ6085@hank.intra.tgummerer.com>
In-Reply-To
<20190223190309.6728-4-matheus.bernardino@usp.br>
On 02/23, Matheus Tavares wrote:
Show 27 quoted lines
> Replace usage of opendir/readdir/closedir API to traverse directories
> recursively, at copy_or_link_directory function, by the dir-iterator
> API. This simplifies the code and avoid recursive calls to
> copy_or_link_directory.
> 
> This process also brings some safe behaviour changes to
> copy_or_link_directory:
>  - It will no longer follows symbolic links. This is not a problem,
>    since the function is only used to copy .git/objects directory, and
>    symbolic links are not expected there.
>  - Hidden directories won't be skipped anymore. In fact, it is odd that
>    the function currently skip hidden directories but not hidden files.
>    The reason for that could be unintentional: probably the intention
>    was to skip '.' and '..' only, but it ended up accidentally skipping
>    all directories starting with '.'. Again, it must not be a problem
>    not to skip hidden dirs since hidden dirs/files are not expected at
>    .git/objects.
>  - Now, copy_or_link_directory will call die() in case of an error on
>    openddir, readdir or lstat, inside dir_iterator_advance. That means
>    it will abort in case of an error trying to fetch any iteration
>    entry.
> 
> Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
> ---
> Changes in v2:
>  - Improved patch message
>  - Removed a now unused variable
s/variable/parameter/ I believe?
>  - Put warning on stat error back
>  - Added pedantic option to dir-iterator initialization
>  - Modified copy_or_link_directory not to skip hidden paths

Thanks, these descriptions are very useful for reviewers that had a look at previous rounds.

Show 59 quoted lines
>  builtin/clone.c | 47 ++++++++++++++++++++++++++++-------------------
>  1 file changed, 28 insertions(+), 19 deletions(-)
> 
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 862d2ea69c..515dc91d63 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"
> @@ -411,42 +413,45 @@ 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)
> +				   const char *src_repo)
>  {
> -	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;
> +	struct stat st;
>  
>  	mkdir_if_missing(dest->buf, 0777);
>  
> +	iter = dir_iterator_begin(src->buf, 1);
> +
>  	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)) {
> +		strbuf_addstr(dest, iter->relative_path);
> +
> +		/*
> +		 * dir_iterator_advance already calls lstat to populate iter->st
> +		 * but, unlike stat, lstat does not checks for permissions on
> +		 * the given path.
> +		 */

Hmm, lstat does check the permissions on the path, it just doesn't follow symlinks. I think I actually mislead you in my previous review here, and was reading the code in dir-iterator.c all wrong.

I thought it said "if (errno == ENOENT) warning(...)", however the condition is "errno != ENOENT", which is why I thought we were loosing warnings when errno == EACCES for example.

As we decided that we would no longer follow symlinks now, I think we can actually get rid of the stat call here. Sorry about the confusion.

Show 45 quoted lines
> +		if (stat(src->buf, &st)) {
>  			warning (_("failed to stat %s\n"), src->buf);
>  			continue;
>  		}
> -		if (S_ISDIR(buf.st_mode)) {
> -			if (de->d_name[0] != '.')
> -				copy_or_link_directory(src, dest,
> -						       src_repo, src_baselen);
> +
> +		if (S_ISDIR(iter->st.st_mode)) {
> +			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 +468,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);
> +	}
>  }
>  
>  static void clone_local(const char *src_repo, const char *dest_repo)
> @@ -481,7 +490,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
>  		get_common_dir(&dest, dest_repo);
>  		strbuf_addstr(&src, "/objects");
>  		strbuf_addstr(&dest, "/objects");
> -		copy_or_link_directory(&src, &dest, src_repo, src.len);
> +		copy_or_link_directory(&src, &dest, src_repo);
>  		strbuf_release(&src);
>  		strbuf_release(&dest);
>  	}
> -- 
> 2.20.1
> 
Previous: Matheus TavaresNext: Matheus Tavares Bernardino
Message 10 of 35 in “clone: convert explicit dir traversal to dir-iterator”
  1. Matheus TavaresFeb 23, 2019
  2. [GSoC][PATCH 1/3] dir-iterator: add pedantic option to dir_iterator_beginMatheus Tavares, Feb 23, 2019
  3. Thomas GummererFeb 23, 2019
  4. Christian CouderFeb 24, 2019
  5. Matheus Tavares BernardinoFeb 24, 2019
  6. Thomas GummererFeb 24, 2019
  7. [GSoC][PATCH 2/3] clone: extract function from copy_or_link_directoryMatheus Tavares, Feb 23, 2019
  8. Christian CouderFeb 24, 2019
  9. [GSoC][PATCH 3/3] clone: use dir-iterator to avoid explicit dir traversalMatheus Tavares, Feb 23, 2019
  10. Thomas GummererFeb 23, 2019
  11. Matheus Tavares BernardinoFeb 24, 2019
  12. Ævar Arnfjörð BjarmasonFeb 23, 2019
  13. Christian CouderFeb 24, 2019
  14. Ævar Arnfjörð BjarmasonFeb 24, 2019
  15. Duy NguyenFeb 25, 2019
  16. 0/7 clone: dir iterator refactoring with testsÆvar Arnfjörð Bjarmason, Feb 26, 2019
  17. 1/7 dir-iterator: add pedantic option to dir_iterator_beginÆvar Arnfjörð Bjarmason, Feb 26, 2019
  18. 2/7 dir-iterator: use stat() instead of lstat()Ævar Arnfjörð Bjarmason, Feb 26, 2019
  19. Matheus Tavares BernardinoFeb 26, 2019
  20. 3/7 clone: extract function from copy_or_link_directoryÆvar Arnfjörð Bjarmason, Feb 26, 2019
  21. 4/7 clone: test for our behavior on odd objects/* contentÆvar Arnfjörð Bjarmason, Feb 26, 2019
  22. 5/7 clone: use dir-iterator to avoid explicit dir traversalÆvar Arnfjörð Bjarmason, Feb 26, 2019
  23. Matheus Tavares BernardinoFeb 26, 2019
  24. Ævar Arnfjörð BjarmasonFeb 26, 2019
  25. 7/7 clone: break cloning repos that have symlinks in themÆvar Arnfjörð Bjarmason, Feb 26, 2019
  26. 6/7 clone: stop ignoring dotdirs in --local etc. cloneÆvar Arnfjörð Bjarmason, Feb 26, 2019
  27. Matheus Tavares BernardinoFeb 25, 2019
  28. Ævar Arnfjörð BjarmasonFeb 25, 2019
  29. Christian CouderFeb 25, 2019
  30. Christian CouderFeb 26, 2019
  31. Matheus Tavares BernardinoFeb 23, 2019
  32. Ævar Arnfjörð BjarmasonFeb 23, 2019
  33. Thomas GummererFeb 23, 2019
  34. Matheus Tavares BernardinoFeb 24, 2019
  35. Thomas GummererFeb 24, 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.