{"thread":{"id":"3973","subject":"[PATCH] C version of git-count-objects","startedAt":"2006-04-27T10:12:55Z","lastAt":"2006-04-28T00:25:38Z","messageCount":12,"participants":["Peter Hagervall","Morten Welinder","Nicolas Pitre","Junio C Hamano","Linus Torvalds"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"19175","messageId":"20060427101254.GA22769@peppar.cs.umu.se","threadId":"3973","inReplyTo":null,"subject":"[PATCH] C version of git-count-objects","fromName":"Peter Hagervall","fromEmail":"hager@cs.umu.se","sentAt":"2006-04-27T10:12:55Z","receivedAt":"2006-04-27T10:12:55Z","isPatch":true,"sender":{"key":"hager@cs.umu.se","avatar":null},"body":"Answering the call Linus made[1], sort of, but for a completely\ndifferent program.\n\nAnyway, it ought to be at least as portable as the shell script, and a\nwhole lot faster, however much that matters.\n\nSigned-off-by: Peter Hagervall <hager@cs.umu.se>\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/19073\n\n---\n\n Makefile             |    5 +--\n count-objects.c      |   56 +++++++++++++++++++++++++++++++++++++\n git-count-objects.sh |   31 --------------------\n 3 files changed, 59 insertions(+), 33 deletions(-)\n\n\ndiff --git a/Makefile b/Makefile\nindex 8ce27a6..53e7591 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -115,7 +115,7 @@ ### --- END CONFIGURATION SECTION ---\n SCRIPT_SH = \\\n \tgit-add.sh git-bisect.sh git-branch.sh git-checkout.sh \\\n \tgit-cherry.sh git-clean.sh git-clone.sh git-commit.sh \\\n-\tgit-count-objects.sh git-diff.sh git-fetch.sh \\\n+\tgit-diff.sh git-fetch.sh \\\n \tgit-format-patch.sh git-ls-remote.sh \\\n \tgit-merge-one-file.sh git-parse-remote.sh \\\n \tgit-prune.sh git-pull.sh git-push.sh git-rebase.sh \\\n@@ -165,7 +165,8 @@ PROGRAMS = \\\n \tgit-upload-pack$X git-verify-pack$X git-write-tree$X \\\n \tgit-update-ref$X git-symbolic-ref$X git-check-ref-format$X \\\n \tgit-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \\\n-\tgit-describe$X git-merge-tree$X git-blame$X git-imap-send$X\n+\tgit-describe$X git-merge-tree$X git-blame$X git-imap-send$X \\\n+\tgit-count-objects$X\n \n BUILT_INS = git-log$X\n \ndiff --git a/count-objects.c b/count-objects.c\nnew file mode 100644\nindex 0000000..67ab6f0\n--- /dev/null\n+++ b/count-objects.c\n@@ -0,0 +1,56 @@\n+#include \"cache.h\"\n+#include \"git-compat-util.h\"\n+\n+static char pathname[PATH_MAX + 1];\n+static int numobjects, numblocks;\n+static const char hex_digits[] = \"0123456789abcdef\";\n+\n+void count_objects(void)\n+{\n+\tchar subdir[3];\n+\tint i, j;\n+\tstruct stat statbuf;\n+\tstruct dirent *dirp;\n+\tDIR *dp;\n+\tsubdir[2] = '\\0';\n+\tfor (i = 0; i < 16; i++) {\n+\t\tsubdir[0] = hex_digits[i];\n+\t\tfor (j = 0; j < 16; j++) {\n+\t\t\tsubdir[1] = hex_digits[j];\n+\t\t\tif (access(subdir, R_OK | X_OK))\n+\t\t\t\tcontinue;\n+\t\t\tchdir(subdir);\n+\t\t\tif (!(dp = opendir(\".\"))) {\n+\t\t\t\terror(\"can't open subdir %s\", subdir);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\twhile ((dirp = readdir(dp))) {\n+\t\t\t\tif (!strcmp(dirp->d_name, \".\") ||\n+\t\t\t\t\t!strcmp(dirp->d_name, \"..\"))\n+\t\t\t\t\tcontinue;\n+\t\t\t\tif (lstat(dirp->d_name, &statbuf)) {\n+\t\t\t\t\terror(\"can't stat file %s\", dirp->d_name);\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tnumblocks += statbuf.st_blocks;\n+\t\t\t\tnumobjects++;\n+\t\t\t}\n+\t\t\tclosedir(dp);\n+\t\t\tchdir(\"..\");\n+\t\t}\n+\t}\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tsetup_git_directory();\n+\n+\tif (chdir(\".git/objects\"))\n+\t\tdie(\"%s\", strerror(errno));\n+\n+\tcount_objects();\n+\n+\tprintf(\"%d objects, %d kilobytes\\n\", numobjects, numblocks / 2);\n+\n+\treturn 0;\n+}\ndiff --git a/git-count-objects.sh b/git-count-objects.sh\ndeleted file mode 100755\nindex 40c58ef..0000000\n--- a/git-count-objects.sh\n+++ /dev/null\n@@ -1,31 +0,0 @@\n-#!/bin/sh\n-#\n-# Copyright (c) 2005 Junio C Hamano\n-#\n-\n-GIT_DIR=`git-rev-parse --git-dir` || exit $?\n-\n-dc </dev/null 2>/dev/null || {\n-\t# This is not a real DC at all -- it just knows how\n-\t# this script feeds DC and does the computation itself.\n-\tdc () {\n-\t\twhile read a b\n-\t\tdo\n-\t\t\tcase $a,$b in\n-\t\t\t0,)\tacc=0 ;;\n-\t\t\t*,+)\tacc=$(($acc + $a)) ;;\n-\t\t\tp,)\techo \"$acc\" ;;\n-\t\t\tesac\n-\t\tdone\n-\t}\n-}\n-\n-echo $(find \"$GIT_DIR/objects\"/?? -type f -print 2>/dev/null | wc -l) objects, \\\n-$({\n-    echo 0\n-    # \"no-such\" is to help Darwin folks by not using xargs -r.\n-    find \"$GIT_DIR/objects\"/?? -type f -print 2>/dev/null |\n-    xargs du -k \"$GIT_DIR/objects/no-such\" 2>/dev/null |\n-    sed -e 's/[ \t].*/ +/'\n-    echo p\n-} | dc) kilobytes\n"},{"id":"19178","messageId":"118833cc0604270616u2961ab10waef5807c429be784@mail.gmail.com","threadId":"3973","inReplyTo":"20060427101254.GA22769@peppar.cs.umu.se","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Morten Welinder","fromEmail":"mwelinder@gmail.com","sentAt":"2006-04-27T13:16:32Z","receivedAt":"2006-04-27T13:16:32Z","isPatch":true,"sender":{"key":"mwelinder@gmail.com","avatar":null},"body":"> +                       if (access(subdir, R_OK | X_OK))\n> +                               continue;\n> +                       chdir(subdir);\n\nYou've got yourself a needless race condition right there.  Just\ndo the chdir and check the return value.  (And besides, access\nchecks with the wrong set of permissions, should this ever end\nup in set[ug]id context.)\n\nMorten\n"},{"id":"19179","messageId":"Pine.LNX.4.64.0604270914570.18816@localhost.localdomain","threadId":"3973","inReplyTo":"20060427101254.GA22769@peppar.cs.umu.se","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2006-04-27T13:23:47Z","receivedAt":"2006-04-27T13:23:47Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Thu, 27 Apr 2006, Peter Hagervall wrote:\n\n> Answering the call Linus made[1], sort of, but for a completely\n> different program.\n> \n> Anyway, it ought to be at least as portable as the shell script, and a\n> whole lot faster, however much that matters.\n> \n[...]\n> +\tfor (i = 0; i < 16; i++) {\n> +\t\tsubdir[0] = hex_digits[i];\n> +\t\tfor (j = 0; j < 16; j++) {\n> +\t\t\tsubdir[1] = hex_digits[j];\n> +\t\t\tif (access(subdir, R_OK | X_OK))\n> +\t\t\t\tcontinue;\n> +\t\t\tchdir(subdir);\n> +\t\t\tif (!(dp = opendir(\".\"))) {\n> +\t\t\t\terror(\"can't open subdir %s\", subdir);\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n\nLooks like you're missing a chdir(\"..\"); there.\n\n\nNicolas\n"},{"id":"19184","messageId":"20060427140718.GA19993@brainysmurf.cs.umu.se","threadId":"3973","inReplyTo":"Pine.LNX.4.64.0604270914570.18816@localhost.localdomain","subject":"[PATCH] C version of git-count-objects, second try","fromName":"Peter Hagervall","fromEmail":"hager@cs.umu.se","sentAt":"2006-04-27T14:07:18Z","receivedAt":"2006-04-27T14:07:18Z","isPatch":true,"sender":{"key":"hager@cs.umu.se","avatar":null},"body":"On Thu, Apr 27, 2006 at 09:23:47AM -0400, Nicolas Pitre wrote:\n> On Thu, 27 Apr 2006, Peter Hagervall wrote:\n> \n> > Answering the call Linus made[1], sort of, but for a completely\n> > different program.\n> > \n> > Anyway, it ought to be at least as portable as the shell script, and a\n> > whole lot faster, however much that matters.\n> > \n> [...]\n> > +\tfor (i = 0; i < 16; i++) {\n> > +\t\tsubdir[0] = hex_digits[i];\n> > +\t\tfor (j = 0; j < 16; j++) {\n> > +\t\t\tsubdir[1] = hex_digits[j];\n> > +\t\t\tif (access(subdir, R_OK | X_OK))\n> > +\t\t\t\tcontinue;\n> > +\t\t\tchdir(subdir);\n> > +\t\t\tif (!(dp = opendir(\".\"))) {\n> > +\t\t\t\terror(\"can't open subdir %s\", subdir);\n> > +\t\t\t\tcontinue;\n> > +\t\t\t}\n> \n> Looks like you're missing a chdir(\"..\"); there.\n> \n\nThanks, I overlooked that one (and the race condition pointed out by\nMorten). Anyway, fixed those now, and removed an unused array.\n\nSigned-off-by: Peter Hagervall <hager@cs.umu.se>\n\n---\n\n Makefile             |    5 ++-\n count-objects.c      |   55 +++++++++++++++++++++++++++++++++++++\n git-count-objects.sh |   31 --------------------\n 3 files changed, 58 insertions(+), 33 deletions(-)\n\n\ndiff --git a/Makefile b/Makefile\nindex 8ce27a6..53e7591 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -115,7 +115,7 @@ ### --- END CONFIGURATION SECTION ---\n SCRIPT_SH = \\\n \tgit-add.sh git-bisect.sh git-branch.sh git-checkout.sh \\\n \tgit-cherry.sh git-clean.sh git-clone.sh git-commit.sh \\\n-\tgit-count-objects.sh git-diff.sh git-fetch.sh \\\n+\tgit-diff.sh git-fetch.sh \\\n \tgit-format-patch.sh git-ls-remote.sh \\\n \tgit-merge-one-file.sh git-parse-remote.sh \\\n \tgit-prune.sh git-pull.sh git-push.sh git-rebase.sh \\\n@@ -165,7 +165,8 @@ PROGRAMS = \\\n \tgit-upload-pack$X git-verify-pack$X git-write-tree$X \\\n \tgit-update-ref$X git-symbolic-ref$X git-check-ref-format$X \\\n \tgit-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \\\n-\tgit-describe$X git-merge-tree$X git-blame$X git-imap-send$X\n+\tgit-describe$X git-merge-tree$X git-blame$X git-imap-send$X \\\n+\tgit-count-objects$X\n \n BUILT_INS = git-log$X\n \ndiff --git a/count-objects.c b/count-objects.c\nnew file mode 100644\nindex 0000000..beaa4d9\n--- /dev/null\n+++ b/count-objects.c\n@@ -0,0 +1,55 @@\n+#include \"cache.h\"\n+#include \"git-compat-util.h\"\n+\n+static int numobjects, numblocks;\n+static const char hex_digits[] = \"0123456789abcdef\";\n+\n+void count_objects(void)\n+{\n+\tchar subdir[3];\n+\tint i, j;\n+\tstruct stat statbuf;\n+\tstruct dirent *dirp;\n+\tDIR *dp;\n+\tsubdir[2] = '\\0';\n+\tfor (i = 0; i < 16; i++) {\n+\t\tsubdir[0] = hex_digits[i];\n+\t\tfor (j = 0; j < 16; j++) {\n+\t\t\tsubdir[1] = hex_digits[j];\n+\t\t\tif (chdir(subdir))\n+\t\t\t\tcontinue;\n+\t\t\tif (!(dp = opendir(\".\"))) {\n+\t\t\t\terror(\"can't open subdir %s\", subdir);\n+\t\t\t\tchdir(\"..\");\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\twhile ((dirp = readdir(dp))) {\n+\t\t\t\tif (!strcmp(dirp->d_name, \".\") ||\n+\t\t\t\t\t!strcmp(dirp->d_name, \"..\"))\n+\t\t\t\t\tcontinue;\n+\t\t\t\tif (lstat(dirp->d_name, &statbuf)) {\n+\t\t\t\t\terror(\"can't stat file %s\", dirp->d_name);\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tnumblocks += statbuf.st_blocks;\n+\t\t\t\tnumobjects++;\n+\t\t\t}\n+\t\t\tclosedir(dp);\n+\t\t\tchdir(\"..\");\n+\t\t}\n+\t}\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tsetup_git_directory();\n+\n+\tif (chdir(\".git/objects\"))\n+\t\tdie(\"%s\", strerror(errno));\n+\n+\tcount_objects();\n+\n+\tprintf(\"%d objects, %d kilobytes\\n\", numobjects, numblocks / 2);\n+\n+\treturn 0;\n+}\ndiff --git a/git-count-objects.sh b/git-count-objects.sh\ndeleted file mode 100755\nindex 40c58ef..0000000\n--- a/git-count-objects.sh\n+++ /dev/null\n@@ -1,31 +0,0 @@\n-#!/bin/sh\n-#\n-# Copyright (c) 2005 Junio C Hamano\n-#\n-\n-GIT_DIR=`git-rev-parse --git-dir` || exit $?\n-\n-dc </dev/null 2>/dev/null || {\n-\t# This is not a real DC at all -- it just knows how\n-\t# this script feeds DC and does the computation itself.\n-\tdc () {\n-\t\twhile read a b\n-\t\tdo\n-\t\t\tcase $a,$b in\n-\t\t\t0,)\tacc=0 ;;\n-\t\t\t*,+)\tacc=$(($acc + $a)) ;;\n-\t\t\tp,)\techo \"$acc\" ;;\n-\t\t\tesac\n-\t\tdone\n-\t}\n-}\n-\n-echo $(find \"$GIT_DIR/objects\"/?? -type f -print 2>/dev/null | wc -l) objects, \\\n-$({\n-    echo 0\n-    # \"no-such\" is to help Darwin folks by not using xargs -r.\n-    find \"$GIT_DIR/objects\"/?? -type f -print 2>/dev/null |\n-    xargs du -k \"$GIT_DIR/objects/no-such\" 2>/dev/null |\n-    sed -e 's/[ \t].*/ +/'\n-    echo p\n-} | dc) kilobytes\n"},{"id":"19188","messageId":"7vhd4ekfu1.fsf@assigned-by-dhcp.cox.net","threadId":"3973","inReplyTo":"Pine.LNX.4.64.0604270914570.18816@localhost.localdomain","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-27T18:56:22Z","receivedAt":"2006-04-27T18:56:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nicolas Pitre <nico@cam.org> writes:\n\n> On Thu, 27 Apr 2006, Peter Hagervall wrote:\n>\n>> Answering the call Linus made[1], sort of, but for a completely\n>> different program.\n>> \n>> Anyway, it ought to be at least as portable as the shell script, and a\n>> whole lot faster, however much that matters.\n>> \n> [...]\n>> +\tfor (i = 0; i < 16; i++) {\n>> +\t\tsubdir[0] = hex_digits[i];\n>> +\t\tfor (j = 0; j < 16; j++) {\n>> +\t\t\tsubdir[1] = hex_digits[j];\n>> +\t\t\tif (access(subdir, R_OK | X_OK))\n>> +\t\t\t\tcontinue;\n>> +\t\t\tchdir(subdir);\n>> +\t\t\tif (!(dp = opendir(\".\"))) {\n>> +\t\t\t\terror(\"can't open subdir %s\", subdir);\n>> +\t\t\t\tcontinue;\n>> +\t\t\t}\n>\n> Looks like you're missing a chdir(\"..\"); there.\n\nWhy would you even _need_ to chdir() anywhere, anyway?\n"},{"id":"19189","messageId":"Pine.LNX.4.64.0604271535460.18816@localhost.localdomain","threadId":"3973","inReplyTo":"7vhd4ekfu1.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2006-04-27T19:39:14Z","receivedAt":"2006-04-27T19:39:14Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Thu, 27 Apr 2006, Junio C Hamano wrote:\n\n> Nicolas Pitre <nico@cam.org> writes:\n> \n> > On Thu, 27 Apr 2006, Peter Hagervall wrote:\n> >\n> >> Answering the call Linus made[1], sort of, but for a completely\n> >> different program.\n> >> \n> >> Anyway, it ought to be at least as portable as the shell script, and a\n> >> whole lot faster, however much that matters.\n> >> \n> > [...]\n> >> +\tfor (i = 0; i < 16; i++) {\n> >> +\t\tsubdir[0] = hex_digits[i];\n> >> +\t\tfor (j = 0; j < 16; j++) {\n> >> +\t\t\tsubdir[1] = hex_digits[j];\n> >> +\t\t\tif (access(subdir, R_OK | X_OK))\n> >> +\t\t\t\tcontinue;\n> >> +\t\t\tchdir(subdir);\n> >> +\t\t\tif (!(dp = opendir(\".\"))) {\n> >> +\t\t\t\terror(\"can't open subdir %s\", subdir);\n> >> +\t\t\t\tcontinue;\n> >> +\t\t\t}\n> >\n> > Looks like you're missing a chdir(\"..\"); there.\n> \n> Why would you even _need_ to chdir() anywhere, anyway?\n\nTo avoid appending the filename to the path before each lstat() I'd \nguess.\n\n\nNicolas\n"},{"id":"19190","messageId":"20060427194559.GA26386@brainysmurf.cs.umu.se","threadId":"3973","inReplyTo":"Pine.LNX.4.64.0604271535460.18816@localhost.localdomain","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Peter Hagervall","fromEmail":"hager@cs.umu.se","sentAt":"2006-04-27T19:46:00Z","receivedAt":"2006-04-27T19:46:00Z","isPatch":true,"sender":{"key":"hager@cs.umu.se","avatar":null},"body":"On Thu, Apr 27, 2006 at 03:39:14PM -0400, Nicolas Pitre wrote:\n> On Thu, 27 Apr 2006, Junio C Hamano wrote:\n> \n> > Nicolas Pitre <nico@cam.org> writes:\n> > \n> > > On Thu, 27 Apr 2006, Peter Hagervall wrote:\n> > >\n> > >> Answering the call Linus made[1], sort of, but for a completely\n> > >> different program.\n> > >> \n> > >> Anyway, it ought to be at least as portable as the shell script, and a\n> > >> whole lot faster, however much that matters.\n> > >> \n> > > [...]\n> > >> +\tfor (i = 0; i < 16; i++) {\n> > >> +\t\tsubdir[0] = hex_digits[i];\n> > >> +\t\tfor (j = 0; j < 16; j++) {\n> > >> +\t\t\tsubdir[1] = hex_digits[j];\n> > >> +\t\t\tif (access(subdir, R_OK | X_OK))\n> > >> +\t\t\t\tcontinue;\n> > >> +\t\t\tchdir(subdir);\n> > >> +\t\t\tif (!(dp = opendir(\".\"))) {\n> > >> +\t\t\t\terror(\"can't open subdir %s\", subdir);\n> > >> +\t\t\t\tcontinue;\n> > >> +\t\t\t}\n> > >\n> > > Looks like you're missing a chdir(\"..\"); there.\n> > \n> > Why would you even _need_ to chdir() anywhere, anyway?\n> \n> To avoid appending the filename to the path before each lstat() I'd \n> guess.\n\nYes, that's pretty much the reason.\n\n\tPeter\n"},{"id":"19191","messageId":"Pine.LNX.4.64.0604271257010.3701@g5.osdl.org","threadId":"3973","inReplyTo":"20060427194559.GA26386@brainysmurf.cs.umu.se","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-04-27T20:07:27Z","receivedAt":"2006-04-27T20:07:27Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 27 Apr 2006, Peter Hagervall wrote:\n> > \n> > To avoid appending the filename to the path before each lstat() I'd \n> > guess.\n> \n> Yes, that's pretty much the reason.\n\nIt's a bad reason, though.\n\nFor one thing, it just doesn't work. You'll have to chdir() back, and you \ncan't use \"..\" in case the user has set up some symlink thing. So you end \nup doing other really strange things.\n\nYou can do this much more efficiently with something like this:\n\n\tconst char *obj = git_object_directory();\n\tint len = strlen(obj);\n\tchar *dir = malloc(len + 300);\n\n\tmemcpy(dir, obj, len);\n\tif (len && obj[len-1] != '/')\n\t\tdir[len++] = '/';\n\tdir[len+2] = 0;\n\tfor (i = 0; i < 16; i++) {\n\t\tdir[len] = hexdigit[i];\n\t\tfor (j = 0; j < 16; j+) {\n\t\t\tdir[len+1] = hexdigit[j];\n\t\t\tdir[len+2] = 0;\n\t\t\tDIR *d = opendir(dir);\n\t\t\tif (!d)\n\t\t\t\tcontinue;\n\t\t\tnr += count(d, dir, len+2);\n\t\t\tclosedir(d);\n\t\t}\n\t}\n\nwhere the \"count()\" function just ends up doing something like\n\n\tint count(DIR *d, const char *prefix, int len)\n\t{\n\t\tint nr = 0;\n\t\tstruct dirent *de;\n\n\t\tprefix[len++] = '/';\n\t\twhile ((de = readdir(d)) != NULL) {\n\t\t\tint fd;\n\t\t\tif (de->d_name[0] == '.')\n\t\t\t\tcontinue;\n\t\t\tstrcpy(prefix + len, de->d_name);\n\t\t\tfd = open(prefix, O_RDONLY);\n\t\t\t.. check if it's ok, perhaps.. ?\n\t\t\tif (ok)\n\t\t\t\tnr++;\n\t\t\tclose(fd);\n\t\t}\n\t\treturn nr;\n\t}\n\nand you're done. Efficient, and it's easy to add the endign to the \npathname, because you're passing in a buffer that is big enough, and \nyou're telling people where they should put their suffixes..\n\nAnd no, the above has never been compiled or tested, and I wrote it with \none eye closed, while drinking heavily and experimenting with some funky \n'shrooms. So caveat emptor.\n\n\t\tLinus\n"},{"id":"19192","messageId":"20060427205155.GA26856@brainysmurf.cs.umu.se","threadId":"3973","inReplyTo":"Pine.LNX.4.64.0604271257010.3701@g5.osdl.org","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Peter Hagervall","fromEmail":"hager@cs.umu.se","sentAt":"2006-04-27T20:51:56Z","receivedAt":"2006-04-27T20:51:56Z","isPatch":true,"sender":{"key":"hager@cs.umu.se","avatar":null},"body":"On Thu, Apr 27, 2006 at 01:07:27PM -0700, Linus Torvalds wrote:\n> \n> \n> On Thu, 27 Apr 2006, Peter Hagervall wrote:\n> > > \n> > > To avoid appending the filename to the path before each lstat() I'd \n> > > guess.\n> > \n> > Yes, that's pretty much the reason.\n> \n> It's a bad reason, though.\n> \n> For one thing, it just doesn't work. You'll have to chdir() back, and you \n> can't use \"..\" in case the user has set up some symlink thing. So you end \n> up doing other really strange things.\n> \n> You can do this much more efficiently with something like this:\n> \n> \tconst char *obj = git_object_directory();\n> \tint len = strlen(obj);\n\n<snip>\n\n> \t\t\t\tcontinue;\n> \t\t\tstrcpy(prefix + len, de->d_name);\n> \t\t\tfd = open(prefix, O_RDONLY);\n> \t\t\t.. check if it's ok, perhaps.. ?\n> \t\t\tif (ok)\n> \t\t\t\tnr++;\n> \t\t\tclose(fd);\n> \t\t}\n> \t\treturn nr;\n> \t}\n> \n> and you're done. Efficient, and it's easy to add the endign to the \n> pathname, because you're passing in a buffer that is big enough, and \n> you're telling people where they should put their suffixes..\n\nThanks, I'll make a third stab at it tomorrow, if anyone is interested\nthat is?\n\n\tPeter\n"},{"id":"19194","messageId":"7vaca6k6za.fsf@assigned-by-dhcp.cox.net","threadId":"3973","inReplyTo":"20060427205155.GA26856@brainysmurf.cs.umu.se","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-27T22:07:37Z","receivedAt":"2006-04-27T22:07:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Peter Hagervall <hager@cs.umu.se> writes:\n\n> Thanks, I'll make a third stab at it tomorrow, if anyone is interested\n> that is?\n\nHow about something like this instead?\n\n-- >8 --\n\n Makefile        |    2 -\n builtin-count.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n builtin.h       |    1 \n git.c           |    1 \n 4 files changed, 127 insertions(+), 1 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8ce27a6..14193aa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -214,7 +214,7 @@ LIB_OBJS = \\\n \t$(DIFF_OBJS)\n \n BUILTIN_OBJS = \\\n-\tbuiltin-log.o builtin-help.o\n+\tbuiltin-log.o builtin-help.o builtin-count.o\n \n GITLIBS = $(LIB_FILE) $(XDIFF_LIB)\n LIBS = $(GITLIBS) -lz\ndiff --git a/builtin-count.c b/builtin-count.c\nnew file mode 100644\nindex 0000000..cbbb7dd\n--- /dev/null\n+++ b/builtin-count.c\n@@ -0,0 +1,124 @@\n+/*\n+ * Builtin \"git count-objects\".\n+ *\n+ * Copyright (c) 2006 Junio C Hamano\n+ */\n+\n+#include \"cache.h\"\n+\n+static const char count_objects_usage[] = \"git-count-objects [-v]\";\n+\n+static void count_objects(DIR *d, char *path, int len, int verbose, \n+\t\t\t  unsigned long *loose,\n+\t\t\t  unsigned long *loose_size,\n+\t\t\t  unsigned long *packed_loose,\n+\t\t\t  unsigned long *garbage)\n+{\n+\tstruct dirent *ent;\n+\twhile ((ent = readdir(d)) != NULL) {\n+\t\tchar hex[41];\n+\t\tunsigned char sha1[20];\n+\t\tconst char *cp;\n+\t\tint bad = 0;\n+\n+\t\tif ((ent->d_name[0] == '.') &&\n+\t\t    (ent->d_name[1] == 0 ||\n+\t\t     ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))))\n+\t\t\tcontinue;\n+\t\tfor (cp = ent->d_name; *cp; cp++) {\n+\t\t\tint ch = *cp;\n+\t\t\tif (('0' <= ch && ch <= '9') ||\n+\t\t\t    ('a' <= ch && ch <= 'f'))\n+\t\t\t\tcontinue;\n+\t\t\tbad = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (cp - ent->d_name != 38)\n+\t\t\tbad = 1;\n+\t\telse {\n+\t\t\tstruct stat st;\n+\t\t\tmemcpy(path + len + 3, ent->d_name, 38);\n+\t\t\tpath[len + 2] = '/';\n+\t\t\tpath[len + 41] = 0;\n+\t\t\tif (stat(path, &st)) {\n+\t\t\t\tdie(\"OOPS <%s>\", path);\n+\t\t\t\tbad = 1;\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\t(*loose_size) += st.st_blocks;\n+\t\t}\n+\t\tif (bad) {\n+\t\t\tif (verbose) {\n+\t\t\t\terror(\"garbage found: %.*s/%s\",\n+\t\t\t\t      len + 2, path, ent->d_name);\n+\t\t\t\t(*garbage)++;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\t(*loose)++;\n+\t\tif (!verbose)\n+\t\t\tcontinue;\n+\t\tmemcpy(hex, path+len, 2);\n+\t\tmemcpy(hex+2, ent->d_name, 38);\n+\t\thex[40] = 0;\n+\t\tif (get_sha1_hex(hex, sha1))\n+\t\t\tdie(\"internal error\");\n+\t\tif (has_sha1_pack(sha1))\n+\t\t\t(*packed_loose)++;\n+\t}\n+}\n+\n+int cmd_count_objects(int ac, const char **av, char *ep)\n+{\n+\tint i;\n+\tint verbose = 0;\n+\tconst char *objdir = get_object_directory();\n+\tint len = strlen(objdir);\n+\tchar *path = xmalloc(len + 50);\n+\tunsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;\n+\tunsigned long loose_size = 0;\n+\n+\tfor (i = 1; i < ac; i++) {\n+\t\tconst char *arg = av[i];\n+\t\tif (*arg != '-')\n+\t\t\tbreak;\n+\t\telse if (!strcmp(arg, \"-v\"))\n+\t\t\tverbose = 1;\n+\t\telse\n+\t\t\tusage(count_objects_usage);\n+\t}\n+\n+\t/* we do not take arguments other than flags for now */\n+\tif (i < ac)\n+\t\tusage(count_objects_usage);\n+\tmemcpy(path, objdir, len);\n+\tif (len && objdir[len-1] != '/')\n+\t\tpath[len++] = '/';\n+\tfor (i = 0; i < 256; i++) {\n+\t\tDIR *d;\n+\t\tsprintf(path + len, \"%02x\", i);\n+\t\td = opendir(path);\n+\t\tif (!d)\n+\t\t\tcontinue;\n+\t\tcount_objects(d, path, len, verbose,\n+\t\t\t      &loose, &loose_size, &packed_loose, &garbage);\n+\t\tclosedir(d);\n+\t}\n+\tif (verbose) {\n+\t\tstruct packed_git *p;\n+\t\tfor (p = packed_git; p; p = p->next) {\n+\t\t\tif (!p->pack_local)\n+\t\t\t\tcontinue;\n+\t\t\tpacked += num_packed_objects(p);\n+\t\t}\n+\t\tprintf(\"count: %lu\\n\", loose);\n+\t\tprintf(\"size: %lu\\n\", loose_size / 2);\n+\t\tprintf(\"in-pack: %lu\\n\", packed);\n+\t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n+\t\tprintf(\"garbage: %lu\\n\", garbage);\n+\t}\n+\telse\n+\t\tprintf(\"%lu objects, %lu kilobytes\\n\",\n+\t\t       loose, loose_size / 2);\n+\treturn 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 47408a0..76169e3 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -19,5 +19,6 @@ extern int cmd_version(int argc, const c\n extern int cmd_whatchanged(int argc, const char **argv, char **envp);\n extern int cmd_show(int argc, const char **argv, char **envp);\n extern int cmd_log(int argc, const char **argv, char **envp);\n+extern int cmd_count_objects(int argc, const char **argv, char **envp);\n \n #endif\ndiff --git a/git.c b/git.c\nindex 01b7e28..00fb399 100644\n--- a/git.c\n+++ b/git.c\n@@ -46,6 +46,7 @@ static void handle_internal_command(int \n \t\t{ \"log\", cmd_log },\n \t\t{ \"whatchanged\", cmd_whatchanged },\n \t\t{ \"show\", cmd_show },\n+\t\t{ \"count-objects\", cmd_count_objects },\n \t};\n \tint i;\n \n"},{"id":"19205","messageId":"20060428001049.GA28347@brainysmurf.cs.umu.se","threadId":"3973","inReplyTo":"7vaca6k6za.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Peter Hagervall","fromEmail":"hager@cs.umu.se","sentAt":"2006-04-28T00:10:50Z","receivedAt":"2006-04-28T00:10:50Z","isPatch":true,"sender":{"key":"hager@cs.umu.se","avatar":null},"body":"On Thu, Apr 27, 2006 at 03:07:37PM -0700, Junio C Hamano wrote:\n\n...\n\n> +int cmd_count_objects(int ac, const char **av, char *ep)\n                                                       ^\n...\n\n> +extern int cmd_count_objects(int argc, const char **argv, char **envp);\n                                                                  ^^\nLooks like we have a type mismatch here, no?\n\n\tPeter\n"},{"id":"19206","messageId":"7vu08eim0t.fsf@assigned-by-dhcp.cox.net","threadId":"3973","inReplyTo":"20060428001049.GA28347@brainysmurf.cs.umu.se","subject":"Re: [PATCH] C version of git-count-objects","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-28T00:25:38Z","receivedAt":"2006-04-28T00:25:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Peter Hagervall <hager@cs.umu.se> writes:\n\n> On Thu, Apr 27, 2006 at 03:07:37PM -0700, Junio C Hamano wrote:\n>\n> ...\n>\n>> +int cmd_count_objects(int ac, const char **av, char *ep)\n>                                                        ^\n> ...\n>\n>> +extern int cmd_count_objects(int argc, const char **argv, char **envp);\n>                                                                   ^^\n> Looks like we have a type mismatch here, no?\n\nInteresting.  Lack of #include <builtin.h> was causing the\ncompiler not to notice X-<.\n"}]}