{"thread":{"id":"7485","subject":"Re: git-add has gone lstat() mad","startedAt":"2007-03-30T19:55:10Z","lastAt":"2007-04-01T08:25:24Z","messageCount":10,"participants":["Junio C Hamano","Andy Parkins","Linus Torvalds","Randal L. Schwartz","Tom Prince"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"38411","messageId":"200703302055.13619.andyparkins@gmail.com","threadId":"7485","inReplyTo":null,"subject":"git-add has gone lstat() mad","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-30T19:55:10Z","receivedAt":"2007-03-30T19:55:10Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"Hello,\n\nI was interested in trying out the GIT_WORK_DIR stuff, but ended up \nbeing unable to.  The thing that stopped me is present in master as \nwell:\n\n $ git --version\n git version 1.5.1.rc3.20.gaa453\n $ cd $HOME\n $ git init\n $ git add .bashrc\n\nAt this point the CPU pegs at 100% systime.  An strace shows that git is \ncalling lstat64() on every file in my home directory.  I killed git \nbefore it scanned everything I've ever done.\n\nI only want to track one file; is git meant to scan every file in the \ndirectory even though I'm not adding any of them?\n\n\n\nAndy\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"38413","messageId":"200703302120.23713.andyparkins@gmail.com","threadId":"7485","inReplyTo":"200703302055.13619.andyparkins@gmail.com","subject":"Re: git-add has gone lstat() mad","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-30T20:20:22Z","receivedAt":"2007-03-30T20:20:22Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Friday 2007, March 30, Andy Parkins wrote:\n\n> At this point the CPU pegs at 100% systime.  An strace shows that git\n> is calling lstat64() on every file in my home directory.  I killed\n> git before it scanned everything I've ever done.\n\nOkay.  I've tracked down the culprit function, but I have no idea what \nthe fix is.\n\nbuiltin-add.c:fill_directory() calls\ndir.c:read_directory() which calls\ndir.c:read_directory_recursive()\n\nI can't see why git feels that it has to recurse the entire subtree.  It \nseems to be something to do with the gitignore stuff.  Surely there is \nno need to use a recursive search when no directories are being added?\n\nIf git-add were given\n\n file1\n dir1/file2\n dir2/dir3/file3\n\nThen only the directories \".\"; \"dir1/\"; \"dir2\"; and \"dir2/dir3\" need \nchecking for .gitignore files; and in none of those cases does the \nsearch need to be recursive.\n\n\n\nAndy\n\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"38402","messageId":"7vslbmxkcv.fsf@assigned-by-dhcp.cox.net","threadId":"7485","inReplyTo":"200703302120.23713.andyparkins@gmail.com","subject":"Re: git-add has gone lstat() mad","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-31T01:38:56Z","receivedAt":"2007-03-31T01:38:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Parkins <andyparkins@gmail.com> writes:\n\n> I can't see why git feels that it has to recurse the entire subtree.  It \n> seems to be something to do with the gitignore stuff.  Surely there is \n> no need to use a recursive search when no directories are being added?\n\nI do not think this is anything new.\n\n> If git-add were given\n>\n>  file1\n>  dir1/file2\n>  dir2/dir3/file3\n\nThe thing is, you are not giving the above three pathnames,\nalthough you might think you are.\n\nYou are giving three path *patterns* and asking git-add: \"please\nrun 'git ls-files --others' and add the ones that match these\npatterns\".\n\nYou can teach it to detect cases where you do not have wildcard\n(that is both shell glob wildcard and directory names; the\nlatter means \"grab everything in that named directory\") to limit\nthe set of directories to descend into.\n\nPatches are welcome, but applying them to 'master' needs to wait\npost 1.5.1.\n"},{"id":"38417","messageId":"Pine.LNX.4.64.0703302020510.6730@woody.linux-foundation.org","threadId":"7485","inReplyTo":"7vslbmxkcv.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-add has gone lstat() mad","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-03-31T03:39:30Z","receivedAt":"2007-03-31T03:39:30Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 30 Mar 2007, Junio C Hamano wrote:\n\n> Andy Parkins <andyparkins@gmail.com> writes:\n> \n> > I can't see why git feels that it has to recurse the entire subtree.  It \n> > seems to be something to do with the gitignore stuff.  Surely there is \n> > no need to use a recursive search when no directories are being added?\n> \n> I do not think this is anything new.\n\nYeah, it's probably old. That said, it's still ugly.\n\n> Patches are welcome, but applying them to 'master' needs to wait\n> post 1.5.1.\n\nHere's a patch. It passes all tests. It's not that complex. But people \nshould double-check. ESPECIALLY the list of special characters (currently \n'?' '*' '\\\\' and '[').\n\nAndy, does it work for you?\n\nNOTE! It changes the \"const char **pathspec\" into an array of \"struct \npath_simplify\", because that way it doesn't need to check for the magic \nshell expansion characters over and over and over and over again, and can \njust do it once up-front. All the real meat of the patch is really that \nconversion, and somebody should double-check that I actually got all the \nspecial characters..\n\nThe way things are set up, you can now pass a \"pathspec\" to the \n\"read_directory()\" function. If you pass NULL, it acts exactly like it \nused to do (read everything). If you pass a non-NULL pointer, it will \nsimplify it into a \"these are the prefixes without any special \ncharacters\", and stop any readdir() early if the path in question doesn't \nmatch any of the prefixes.\n\nNOTE! This does *not* obviate the need for the caller to do the *exact* \npathspec match later. It's a first-level filter on \"read_directory()\", but \nit does not do the full pathspec thing. Maybe it should. But in the \nmeantime, builtin-add.c really does need to do first\n\n\tread_directory(dir, .., pathspec);\n\tif (pathspec)\n\t\tprune_directory(dir, pathspec, baselen);\n\nie the \"prune_directory()\" part will do the *exact* pathspec pruning, \nwhile the \"read_directory()\" will use the pathspec just to do some quick \nhigh-level pruning of the directories it will recurse into.\n\nDoes this matter? I can say that:\n\n\tgit ls-files -o Makefile~\n\non the kernel took 0.110s for me before, and it now takes 0.014s. And \nmaybe Andy's case more noticeable. Andy?\n\n\t\tLinus\n---\n builtin-add.c      |    2 +-\n builtin-ls-files.c |    2 +-\n dir.c              |   96 +++++++++++++++++++++++++++++++++++++++++++++++++---\n dir.h              |    2 +-\n wt-status.c        |    2 +-\n 5 files changed, 95 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 9fcf514..871e23f 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -87,7 +87,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)\n \t}\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, path, base, baselen);\n+\tread_directory(dir, path, base, baselen, pathspec);\n \tif (pathspec)\n \t\tprune_directory(dir, pathspec, baselen);\n }\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 4e1d5af..74a6aca 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -216,7 +216,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)\n \n \t\tif (baselen)\n \t\t\tpath = base = prefix;\n-\t\tread_directory(dir, path, base, baselen);\n+\t\tread_directory(dir, path, base, baselen, pathspec);\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\ndiff --git a/dir.c b/dir.c\nindex b48e19d..f1cf278 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -8,6 +8,11 @@\n #include \"cache.h\"\n #include \"dir.h\"\n \n+struct path_simplify {\n+\tint len;\n+\tconst char *path;\n+};\n+\n int common_prefix(const char **pathspec)\n {\n \tconst char *path, *slash, *next;\n@@ -293,6 +298,31 @@ static int dir_exists(const char *dirname, int len)\n }\n \n /*\n+ * This is an inexact early pruning of any recursive directory\n+ * reading - if the path cannot possibly be in the pathspec,\n+ * return true, and we'll skip it early.\n+ */\n+static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)\n+{\n+\tif (simplify) {\n+\t\tfor (;;) {\n+\t\t\tconst char *match = simplify->path;\n+\t\t\tint len = simplify->len;\n+\n+\t\t\tif (!match)\n+\t\t\t\tbreak;\n+\t\t\tif (len > pathlen)\n+\t\t\t\tlen = pathlen;\n+\t\t\tif (!memcmp(path, match, len))\n+\t\t\t\treturn 0;\n+\t\t\tsimplify++;\n+\t\t}\n+\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n  * Read a directory tree. We currently ignore anything but\n  * directories, regular files and symlinks. That's because git\n  * doesn't handle them at all yet. Maybe that will change some\n@@ -301,7 +331,7 @@ static int dir_exists(const char *dirname, int len)\n  * Also, we ignore the name \".git\" (even if it is not a directory).\n  * That likely will not change.\n  */\n-static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only)\n+static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)\n {\n \tDIR *fdir = opendir(path);\n \tint contents = 0;\n@@ -324,6 +354,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co\n \t\t\t\tcontinue;\n \t\t\tlen = strlen(de->d_name);\n \t\t\tmemcpy(fullname + baselen, de->d_name, len+1);\n+\t\t\tif (simplify_away(fullname, baselen + len, simplify))\n+\t\t\t\tcontinue;\n \t\t\tif (excluded(dir, fullname) != dir->show_ignored) {\n \t\t\t\tif (!dir->show_ignored || DTYPE(de) != DT_DIR) {\n \t\t\t\t\tcontinue;\n@@ -350,13 +382,13 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co\n \t\t\t\t\tif (dir->hide_empty_directories &&\n \t\t\t\t\t    !read_directory_recursive(dir,\n \t\t\t\t\t\t    fullname, fullname,\n-\t\t\t\t\t\t    baselen + len, 1))\n+\t\t\t\t\t\t    baselen + len, 1, simplify))\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \n \t\t\t\tcontents += read_directory_recursive(dir,\n-\t\t\t\t\tfullname, fullname, baselen + len, 0);\n+\t\t\t\t\tfullname, fullname, baselen + len, 0, simplify);\n \t\t\t\tcontinue;\n \t\t\tcase DT_REG:\n \t\t\tcase DT_LNK:\n@@ -386,8 +418,61 @@ static int cmp_name(const void *p1, const void *p2)\n \t\t\t\t  e2->name, e2->len);\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen)\n+/*\n+ * Return the length of the \"simple\" part of a path match limiter.\n+ */\n+static int simple_length(const char *match)\n {\n+\tconst char special[256] = {\n+\t\t[0] = 1, ['?'] = 1,\n+\t\t['\\\\'] = 1, ['*'] = 1,\n+\t\t['['] = 1\n+\t};\n+\tint len = -1;\n+\n+\tfor (;;) {\n+\t\tunsigned char c = *match++;\n+\t\tlen++;\n+\t\tif (special[c])\n+\t\t\treturn len;\n+\t}\n+}\n+\n+static struct path_simplify *create_simplify(const char **pathspec)\n+{\n+\tint nr, alloc = 0;\n+\tstruct path_simplify *simplify = NULL;\n+\n+\tif (!pathspec)\n+\t\treturn NULL;\n+\n+\tfor (nr = 0 ; ; nr++) {\n+\t\tconst char *match;\n+\t\tif (nr >= alloc) {\n+\t\t\talloc = alloc_nr(alloc);\n+\t\t\tsimplify = xrealloc(simplify, alloc * sizeof(*simplify));\n+\t\t}\n+\t\tmatch = *pathspec++;\n+\t\tif (!match)\n+\t\t\tbreak;\n+\t\tsimplify[nr].path = match;\n+\t\tsimplify[nr].len = simple_length(match);\n+\t}\n+\tsimplify[nr].path = NULL;\n+\tsimplify[nr].len = 0;\n+\treturn simplify;\n+}\n+\n+static void free_simplify(struct path_simplify *simplify)\n+{\n+\tif (simplify)\n+\t\tfree(simplify);\n+}\n+\n+int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)\n+{\n+\tstruct path_simplify *simplify = create_simplify(pathspec);\n+\n \t/*\n \t * Make sure to do the per-directory exclude for all the\n \t * directories leading up to our base.\n@@ -414,7 +499,8 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i\n \t\t}\n \t}\n \n-\tread_directory_recursive(dir, path, base, baselen, 0);\n+\tread_directory_recursive(dir, path, base, baselen, 0, simplify);\n+\tfree_simplify(simplify);\n \tqsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);\n \treturn dir->nr;\n }\ndiff --git a/dir.h b/dir.h\nindex 7233d65..33c31f2 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -48,7 +48,7 @@ extern int common_prefix(const char **pathspec);\n #define MATCHED_EXACTLY 3\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n \n-extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen);\n+extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);\n extern int push_exclude_per_directory(struct dir_struct *, const char *, int);\n extern void pop_exclude_per_directory(struct dir_struct *, int);\n \ndiff --git a/wt-status.c b/wt-status.c\nindex a25632b..a055990 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -260,7 +260,7 @@ static void wt_status_print_untracked(struct wt_status *s)\n \tif (file_exists(x))\n \t\tadd_excludes_from_file(&dir, x);\n \n-\tread_directory(&dir, \".\", \"\", 0);\n+\tread_directory(&dir, \".\", \"\", 0, NULL);\n \tfor(i = 0; i < dir.nr; i++) {\n \t\t/* check for matching entry, which is unmerged; lifted from\n \t\t * builtin-ls-files:show_other_files */\n"},{"id":"38421","messageId":"200703311119.10581.andyparkins@gmail.com","threadId":"7485","inReplyTo":"Pine.LNX.4.64.0703302020510.6730@woody.linux-foundation.org","subject":"Re: git-add has gone lstat() mad","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-31T10:18:58Z","receivedAt":"2007-03-31T10:18:58Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Saturday 2007, March 31, Linus Torvalds wrote:\n\n> on the kernel took 0.110s for me before, and it now takes 0.014s. And\n> maybe Andy's case more noticeable. Andy?\n\nBlindingly fast.\n\nPreviously, I never completed a git add .bashrc as it was taking so \nlong.  Now it's instant.  This is back to true git form - I wasn't \nentirely sure git-add had done anything :-).  git-status confirmed that \nit had worked successfully though.\n\nI've not done any extensive tests for regressions, but I've done\n\n cd $HOME\n git init\n git add .bashrc\n git add somedirectory/\n\nAnd they work fine.  So - it's works for me from me, and a big happy \ngrin.\n\n\n\nAndy\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"38438","messageId":"86lkhdqx8y.fsf@blue.stonehenge.com","threadId":"7485","inReplyTo":"200703311119.10581.andyparkins@gmail.com","subject":"Re: git-add has gone lstat() mad","fromName":"Randal L. Schwartz","fromEmail":"merlyn@stonehenge.com","sentAt":"2007-03-31T14:54:37Z","receivedAt":"2007-03-31T14:54:37Z","isPatch":false,"sender":{"key":"merlyn@stonehenge.com","avatar":"https://gravatar.com/avatar/dc528d210743ff0333e6213f9ee7b33b23f1b7bc1f3c5a8c2d819074ecd7ab19?d=mp&s=160"},"body":">>>>> \"Andy\" == Andy Parkins <andyparkins@gmail.com> writes:\n\nAndy> I've not done any extensive tests for regressions, but I've done\n\nAndy>  cd $HOME\nAndy>  git init\nAndy>  git add .bashrc\nAndy>  git add somedirectory/\n\nAndy> And they work fine.  So - it's works for me from me, and a big happy \nAndy> grin.\n\nGiven that git currently doesn't maintain any metadata other than +x/-x, how\nare you maintaining the metadata for your homedir items?  I know some schemes\nwere discussed here in the past, but I'm curious as to what you settled on.\nFor example, your .netrc file needs to be 600, but git won't track that.\n\n-- \nRandal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095\n<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>\nPerl/Unix/security consulting, Technical writing, Comedy, etc. etc.\nSee PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!\n"},{"id":"38439","messageId":"200703311609.23309.andyparkins@gmail.com","threadId":"7485","inReplyTo":"86lkhdqx8y.fsf@blue.stonehenge.com","subject":"Re: git-add has gone lstat() mad","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-31T15:09:21Z","receivedAt":"2007-03-31T15:09:21Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Saturday 2007, March 31, Randal L. Schwartz wrote:\n\n> Given that git currently doesn't maintain any metadata other than\n> +x/-x, how are you maintaining the metadata for your homedir items? \n> I know some schemes were discussed here in the past, but I'm curious\n> as to what you settled on. For example, your .netrc file needs to be\n> 600, but git won't track that.\n\nI'm not maintaining anything as yet; the experiment so far consists \nof .bashrc only :-)\n\nJust storing my .inputrc, .bashrc, .vimrc and .gitconfig in a repository \nis probably going to give me all that I want.  There aren't many other \nconfig files that I regularly update, and certainly not many that I \nupdate differently on different machines.\n\nHowever, I plan to use a script to wrap the git calls so that I don't \nhave to type GIT_WORK_DIR and GIT_DIR for every file I want to track.  \nI plan to make it so that if you run this script with a checkout or \nother working tree changing command then I will run a function within \nit that reads the metadata out of a file that is stored in the \nrepository which will restore those settings.\n\nIdeally this functionality would be in hooks for pre-update-index and \npost-checkout-index or similar.  But I have a feeling that the \npotential for conflicts makes it hard to do in reality.\n\n\n\nAndy\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"38446","messageId":"20070331192835.GA25016@hermes","threadId":"7485","inReplyTo":"86lkhdqx8y.fsf@blue.stonehenge.com","subject":"Re: git-add has gone lstat() mad","fromName":"Tom Prince","fromEmail":"tom.prince@ualberta.net","sentAt":"2007-03-31T19:28:37Z","receivedAt":"2007-03-31T19:28:37Z","isPatch":false,"sender":{"key":"tom.prince@ualberta.net","avatar":"https://gravatar.com/avatar/a0ad19caee7618876339485106ec994f5202505eecd210ba5c0bd869feaa555a?d=mp&s=160"},"body":"On Sat, Mar 31, 2007 at 07:54:37AM -0700, Randal L. Schwartz wrote:\n> Given that git currently doesn't maintain any metadata other than +x/-x, how\n> are you maintaining the metadata for your homedir items?  I know some\n> schemes\n> were discussed here in the past, but I'm curious as to what you settled on.\n> For example, your .netrc file needs to be 600, but git won't track that.\n\nI personally just don't track files that have sensitive data. I tend to have\ncopies of my home dir on somewhat public servers, so I don't want that data\ncopied around anyway.\n\n  Tom\n"},{"id":"38457","messageId":"7vy7ld3p33.fsf@assigned-by-dhcp.cox.net","threadId":"7485","inReplyTo":"Pine.LNX.4.64.0703302020510.6730@woody.linux-foundation.org","subject":"Re: git-add has gone lstat() mad","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-04-01T00:39:28Z","receivedAt":"2007-04-01T00:39:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> Here's a patch. It passes all tests. It's not that complex. But people \n> should double-check. ESPECIALLY the list of special characters (currently \n> '?' '*' '\\\\' and '[').\n\nI think the above is a good set.\n\nThis is an optimization different from what I was thinking\nabout.  I was hoping that we do not even need to call into\nread_directory() if all the pathspec[] elements succeeds to\nlstat() and they are not directories; in such a case we can just\nstuff them to dir structure by hand, and use the remainder for\ndirectory walk.\n\nBut I like this patch better.  We need to look at .gitignore to\nwarn about adding ignored files, so we cannot just stuff what\nare found to dir without checking if they are ignored.\n"},{"id":"38465","messageId":"200704010925.26590.andyparkins@gmail.com","threadId":"7485","inReplyTo":"7vy7ld3p33.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-add has gone lstat() mad","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-04-01T08:25:24Z","receivedAt":"2007-04-01T08:25:24Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Sunday 2007, April 01, Junio C Hamano wrote:\n\n> But I like this patch better.  We need to look at .gitignore to\n> warn about adding ignored files, so we cannot just stuff what\n> are found to dir without checking if they are ignored.\n\nI needed the following needed on top of current pu:\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex fa36495..d4f7589 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -521,7 +521,7 @@ static void verify_clean_subdirectory(const char *path, const char *action,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, path, pathbuf, namelen+1);\n+\ti = read_directory(&d, path, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\tdie(\"Updating '%s' would lose untracked files in it\",\n \t\t    path);\n"}]}