{"thread":{"id":"18268","subject":"[PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","startedAt":"2009-03-11T15:17:27Z","lastAt":"2009-03-20T22:27:44Z","messageCount":14,"participants":["Johan Sørensen","Johannes Sixt","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"107699","messageId":"1236784647-71388-1-git-send-email-johan@johansorensen.com","threadId":"18268","inReplyTo":null,"subject":"[PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-11T15:17:27Z","receivedAt":"2009-03-11T15:17:27Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"The argument is an executable script that will receive the path to the repos\nthe client wishes to clone as an argument. It is then the responsibility of the\nscript to return a zero-terminated string on its stdout with the real path of\nthe target repository.\n\nThis buys us a lot of flexibility when it comes to managing different\nrepositories, possibly located in many different dirs, but with a uniform\nurl-structure to the outside world.\n---\n Documentation/git-daemon.txt |    7 ++++\n daemon.c                     |   75 +++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 81 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex 36f00ae..1eca344 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -13,6 +13,7 @@ SYNOPSIS\n \t     [--strict-paths] [--base-path=path] [--base-path-relaxed]\n \t     [--user-path | --user-path=path]\n \t     [--interpolated-path=pathtemplate]\n+\t     [--path-filter=executable]\n \t     [--reuseaddr] [--detach] [--pid-file=file]\n \t     [--enable=service] [--disable=service]\n \t     [--allow-override=service] [--forbid-override=service]\n@@ -71,6 +72,12 @@ OPTIONS\n \tAfter interpolation, the path is validated against the directory\n \twhitelist.\n \n+--path-filter=executable::\n+\tTo support a more flexible directory layout a path filter script \n+\tcan be used. The executable will receive the requested path from\n+\tthe client as arg0. The executable must return a zero-terminated\n+\tstring on stdout which is the real path 'git-daemon' should serve.\n+\n --export-all::\n \tAllow pulling from all directories that look like GIT repositories\n \t(have the 'objects' and 'refs' subdirectories), even if they\ndiff --git a/daemon.c b/daemon.c\nindex d93cf96..b2571df 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -22,6 +22,7 @@ static const char daemon_usage[] =\n \"           [--strict-paths] [--base-path=path] [--base-path-relaxed]\\n\"\n \"           [--user-path | --user-path=path]\\n\"\n \"           [--interpolated-path=path]\\n\"\n+\"           [--path-filter=path]\\n\"\n \"           [--reuseaddr] [--detach] [--pid-file=file]\\n\"\n \"           [--[enable|disable|allow-override|forbid-override]=service]\\n\"\n \"           [--inetd | [--listen=host_or_ipaddr] [--port=n]\\n\"\n@@ -58,6 +59,10 @@ static char *canon_hostname;\n static char *ip_address;\n static char *tcp_port;\n \n+/* if defined, the script will be executed with the requested path on stdin\n+ * and _must_ return with a successful exitcode and the new path on stdout */\n+static char *path_filter_script;\n+\n static void logreport(int priority, const char *err, va_list params)\n {\n \tif (log_syslog) {\n@@ -287,9 +292,62 @@ static int git_daemon_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+static char *run_path_filter_script(char *requested_dir) {\n+\tpid_t pid;\n+\tchar result[256]; /* arbitary */\n+\tchar *real_path;\n+\tint pipe_out[2];\n+\tint exit_code = 1;\n+\n+\tpipe(pipe_out);\n+\n+\tloginfo(\"Executing path filter script: '%s %s'\", path_filter_script, requested_dir);\n+\n+\tswitch ((pid = fork())) {\n+\t\tcase -1:\n+\t\t\tlogerror(\"path filter script fork() failed: %s\", strerror(errno));\n+\t\t\treturn NULL;\n+\t\tcase 0:\n+\t\tclose(pipe_out[0]);\n+\t\tdup2(pipe_out[1], 1);\n+\t\tclose(pipe_out[1]);\n+\n+\t\texecl(path_filter_script, path_filter_script, requested_dir, NULL);\n+\n+\t\t/* execl failed if we got here */\n+\t\tlogerror(\"path filter script execl() failed: %s\", strerror(errno));\n+\t\treturn NULL;\n+\tdefault:\n+\t\tclose(pipe_out[1]);\n+\t\n+\t\twhile(waitpid(pid, &exit_code, 0) < 0) {\n+\t\t\tswitch(errno) {\n+\t\t\tcase EINTR:\n+\t\t\tcontinue;\n+\t\t\tdefault:\n+\t\t\t\tlogerror(\"path filter script waitpid() fail: %s\", strerror(errno));\n+\t\t\t\tgoto waitpid_error;\n+\t\t\t}\n+\t\t}\n+\t\tif (WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0) {\n+\t\t\tread(pipe_out[0], result, sizeof(result) - 1);\n+\t\t\tloginfo(\"path filter script result: %s\", result);\n+\t\t}\n+\t\twaitpid_error:\n+\t\tclose(pipe_out[0]);\n+\t}\n+\n+\tif (result) {\n+\t\treal_path = result;\n+\t\treturn real_path;\n+\t}\n+\treturn NULL;\n+}\n+\n static int run_service(char *dir, struct daemon_service *service)\n {\n \tconst char *path;\n+\tchar *real_dir;\n \tint enabled = service->enabled;\n \n \tloginfo(\"Request %s for '%s'\", service->name, dir);\n@@ -299,8 +357,19 @@ static int run_service(char *dir, struct daemon_service *service)\n \t\terrno = EACCES;\n \t\treturn -1;\n \t}\n+\tloginfo(\"path_filter_script %s\", path_filter_script);\n+\tif (!path_filter_script) {\n+\t\treal_dir = dir;\n+\t} else {\n+\t\tchar *tdir;\n+\t\tif ((tdir = run_path_filter_script(dir))) {\n+\t\t\treal_dir = tdir;\n+\t\t} else {\n+\t\t\treal_dir = dir;\n+\t\t}\n+\t}\n \n-\tif (!(path = path_ok(dir)))\n+\tif (!(path = path_ok(real_dir)))\n \t\treturn -1;\n \n \t/*\n@@ -1018,6 +1087,10 @@ int main(int argc, char **argv)\n \t\t\tpid_file = arg + 11;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--path-filter=\")) {\n+\t\t\tpath_filter_script = arg + 14;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--detach\")) {\n \t\t\tdetach = 1;\n \t\t\tlog_syslog = 1;\n-- \n1.6.1\n"},{"id":"107707","messageId":"49B7DFA1.4030409@viscovery.net","threadId":"18268","inReplyTo":"1236784647-71388-1-git-send-email-johan@johansorensen.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-03-11T15:58:25Z","receivedAt":"2009-03-11T15:58:25Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johan Sørensen schrieb:\n> The argument is an executable script that will receive the path to the repos\n> the client wishes to clone as an argument. It is then the responsibility of the\n> script to return a zero-terminated string on its stdout with the real path of\n> the target repository.\n> \n> This buys us a lot of flexibility when it comes to managing different\n> repositories, possibly located in many different dirs, but with a uniform\n> url-structure to the outside world.\n\nIt's the first time that I see a deamon with this feature - except perhaps\nApache's ModRewrite. Are you sure you are not working around your problem\nat the wrong place?\n\nDoesn't --interpolated-path already solve your problem? If not, then you\nat least you must describe in the documentation the use-cases when\n--path-filter should be preferred.\n\nYour implementation does not pass the target hostname to the script, but\nit should; otherwise you lose flexibility (for virtual hosting).\n\n> +static char *run_path_filter_script(char *requested_dir) {\n> +\tpid_t pid;\n> +\tchar result[256]; /* arbitary */\n> +\tchar *real_path;\n> +\tint pipe_out[2];\n> +\tint exit_code = 1;\n> +\n> +\tpipe(pipe_out);\n> +\n> +\tloginfo(\"Executing path filter script: '%s %s'\", path_filter_script, requested_dir);\n> +\n> +\tswitch ((pid = fork())) {\n> +\t\tcase -1:\n> +\t\t\tlogerror(\"path filter script fork() failed: %s\", strerror(errno));\n> +\t\t\treturn NULL;\n> +\t\tcase 0:\n> +\t\tclose(pipe_out[0]);\n> +\t\tdup2(pipe_out[1], 1);\n> +\t\tclose(pipe_out[1]);\n> +\n> +\t\texecl(path_filter_script, path_filter_script, requested_dir, NULL);\n\nUse start_command()/finish_command() instead of rolling your own fork/exec\ncombo.\n\n-- Hannes\n"},{"id":"107795","messageId":"1236852820-12980-1-git-send-email-johan@johansorensen.com","threadId":"18268","inReplyTo":"49B7DFA1.4030409@viscovery.net","subject":"[PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-12T10:13:40Z","receivedAt":"2009-03-12T10:13:40Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"The parameter for filter-path is an executable that will receive the service\nname, the client hostname and path to the repos the client requests as as\narguments. It is then the responsibility of the script to return a zero\nterminated string on its stdout with the real path of the target repository.\n---\n Documentation/git-daemon.txt |   13 ++++++++++\n daemon.c                     |   53 +++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 65 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex 36f00ae..efd1687 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -13,6 +13,7 @@ SYNOPSIS\n \t     [--strict-paths] [--base-path=path] [--base-path-relaxed]\n \t     [--user-path | --user-path=path]\n \t     [--interpolated-path=pathtemplate]\n+\t     [--path-filter=executable]\n \t     [--reuseaddr] [--detach] [--pid-file=file]\n \t     [--enable=service] [--disable=service]\n \t     [--allow-override=service] [--forbid-override=service]\n@@ -71,6 +72,18 @@ OPTIONS\n \tAfter interpolation, the path is validated against the directory\n \twhitelist.\n \n+--path-filter=executable::\n+\tTo support a more flexible directory layout a path filter script \n+\tcan be used. The executable will receive the service name (upload-pack, \n+\tupload-archive or receive-pack), the client hostname and the request git \n+\tdirectory as arguments. The executable must return a zero-terminated string\n+\ton stdout which is the real path 'git-daemon' should serve. This is useful\n+\twhen --interpolated-path doesn't buy you enough flexibility. You could for\n+\tinstance keep support for old clone urls if you rename your repository, or\n+\tfetch a custom url-mapping from a third-party repo manager application, or\n+\tmap deeply nested repository directories to a more sensible layout for the \n+\toutside world.\n+\n --export-all::\n \tAllow pulling from all directories that look like GIT repositories\n \t(have the 'objects' and 'refs' subdirectories), even if they\ndiff --git a/daemon.c b/daemon.c\nindex d93cf96..e6777c6 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"pkt-line.h\"\n #include \"exec_cmd.h\"\n+#include \"run-command.h\"\n \n #include <syslog.h>\n \n@@ -22,6 +23,7 @@ static const char daemon_usage[] =\n \"           [--strict-paths] [--base-path=path] [--base-path-relaxed]\\n\"\n \"           [--user-path | --user-path=path]\\n\"\n \"           [--interpolated-path=path]\\n\"\n+\"           [--path-filter=path]\\n\"\n \"           [--reuseaddr] [--detach] [--pid-file=file]\\n\"\n \"           [--[enable|disable|allow-override|forbid-override]=service]\\n\"\n \"           [--inetd | [--listen=host_or_ipaddr] [--port=n]\\n\"\n@@ -58,6 +60,10 @@ static char *canon_hostname;\n static char *ip_address;\n static char *tcp_port;\n \n+/* if defined, the script will be executed with the requested path on stdin\n+ * and _must_ return with a successful exitcode and the new path on stdout */\n+static char *path_filter_script;\n+\n static void logreport(int priority, const char *err, va_list params)\n {\n \tif (log_syslog) {\n@@ -287,6 +293,37 @@ static int git_daemon_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+static char *run_path_filter_script(struct daemon_service *s, char *host, char *dir) {\n+\tchar result[256]; /* arbitary */\n+\tchar *real_path;\n+\tstruct child_process filter_cmd;\n+\tconst char *args[] = { path_filter_script, s->name, host, dir, NULL };\n+\n+\tloginfo(\"Executing path filter script: '%s %s'\", path_filter_script, dir);\n+\tmemset(&filter_cmd, 0, sizeof(filter_cmd));\n+\tfilter_cmd.argv = args;\n+\tfilter_cmd.out = -1;\n+\t\n+\tif (start_command(&filter_cmd)) {\n+\t\tlogerror(\"path filter: unable to fork path_filter_script\");\n+\t\treturn NULL;\n+\t}\n+\t\n+\tread(filter_cmd.out, result, sizeof(result) - 1);\n+\t\n+\tclose(filter_cmd.out);\n+\tif (finish_command(&filter_cmd)) {\n+\t\tlogerror(\"path filter died with strange error\");\n+\t\treturn NULL;\n+\t}\n+\n+\tif (result) {\n+\t\treal_path = result;\n+\t\treturn real_path;\n+\t}\n+\treturn NULL;\n+}\n+\n static int run_service(char *dir, struct daemon_service *service)\n {\n \tconst char *path;\n@@ -495,6 +532,7 @@ static void parse_extra_args(char *extra_args, int buflen)\n static int execute(struct sockaddr *addr)\n {\n \tstatic char line[1000];\n+\tchar *path;\n \tint pktlen, len, i;\n \n \tif (addr) {\n@@ -553,11 +591,20 @@ static int execute(struct sockaddr *addr)\n \t\tif (!prefixcmp(line, \"git-\") &&\n \t\t    !strncmp(s->name, line + 4, namelen) &&\n \t\t    line[namelen + 4] == ' ') {\n+\t\t\tpath = line + namelen + 5;\n+\t\t\tif (path_filter_script) {\n+\t\t\t\tloginfo(\"path_filter_script %s for path %s\", path_filter_script, path);\n+\t\t\t\tchar *tdir;\n+\t\t\t\tif ((tdir = run_path_filter_script(s, hostname, path))) {\n+\t\t\t\t\tpath = tdir;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\t\n \t\t\t/*\n \t\t\t * Note: The directory here is probably context sensitive,\n \t\t\t * and might depend on the actual service being performed.\n \t\t\t */\n-\t\t\treturn run_service(line + namelen + 5, s);\n+\t\t\treturn run_service(path, s);\n \t\t}\n \t}\n \n@@ -1018,6 +1065,10 @@ int main(int argc, char **argv)\n \t\t\tpid_file = arg + 11;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--path-filter=\")) {\n+\t\t\tpath_filter_script = arg + 14;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--detach\")) {\n \t\t\tdetach = 1;\n \t\t\tlog_syslog = 1;\n-- \n1.6.1\n"},{"id":"107798","messageId":"9e0f31700903120326s28acbc67ufefff344c9098ca@mail.gmail.com","threadId":"18268","inReplyTo":"49B7DFA1.4030409@viscovery.net","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-12T10:26:12Z","receivedAt":"2009-03-12T10:26:12Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"On Wed, Mar 11, 2009 at 4:58 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Johan Sørensen schrieb:\n>> This buys us a lot of flexibility when it comes to managing different\n>> repositories, possibly located in many different dirs, but with a uniform\n>> url-structure to the outside world.\n>\n> It's the first time that I see a deamon with this feature - except perhaps\n> Apache's ModRewrite. Are you sure you are not working around your problem\n> at the wrong place?\n>\n> Doesn't --interpolated-path already solve your problem? If not, then you\n> at least you must describe in the documentation the use-cases when\n> --path-filter should be preferred.\n\nMaybe I am barking up the wrong tree, but here's my real-world use\ncase: I'm currently working on some bigger changes for gitorious.org,\nwhere the repository url-structure could potentially change over time,\nas a consequence of various features. Using the path-filter script I\ncan keep the old urls around and still working, and I can map any url\nto a on-disk uniquely hashed path, so I don't have to move the files\naround, maintain symlinks and so forth for information the gitorious\napplication already has nicely structured and easy to lookup.\n\nI know these may be highly specialized needs, but so is\ninterpolated-path for the common user. I think this patch could be\nuseful for anyone else wanting to set up a flexible repo hosting\nsystem. I think the url-structure is a major part of the UI for any\napp exposing them, even for a git-daemon, so the mod_rewrite\ncomparison isn't too far fetched in my opinion...\n\n> Your implementation does not pass the target hostname to the script, but\n> it should; otherwise you lose flexibility (for virtual hosting).\n\nGood point. I've added the hostname as well as the service name as\narguments for the script.\n\n>> +     switch ((pid = fork())) {\n[snip]\n>\n> Use start_command()/finish_command() instead of rolling your own fork/exec\n> combo.\n\nAh nice! I'm sending an updated patch.\n\n\n>\n> -- Hannes\n>\n\nCheers,\nJS\n"},{"id":"107803","messageId":"alpine.DEB.1.00.0903121218000.10279@pacific.mpi-cbg.de","threadId":"18268","inReplyTo":"1236852820-12980-1-git-send-email-johan@johansorensen.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-03-12T11:29:35Z","receivedAt":"2009-03-12T11:29:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nDisclaimer: if you are offended by constructive criticism, or likely to\nanswer with insults to the comments I offer, please stop reading this mail\nnow (and please do not answer my mail, either). :-)\n\nStill with me?  Good.  Nice to meet you.\n\nJust for the record: responding to a patch is my strongest way of saying\nthat I appreciate your work.\n\nOn Thu, 12 Mar 2009, Johan Sørensen wrote:\n\n> The parameter for filter-path is an executable that will receive the \n> service name, the client hostname and path to the repos the client \n> requests as as arguments. It is then the responsibility of the script to \n> return a zero terminated string on its stdout with the real path of the \n> target repository.\n> ---\n\nA sign-off is missing...\n\nMore importantly, you might want to point out the security concerns of \nrunning a script with the full permissions of git-daemon.  (AFAICT from \nyour patch you are not dropping any privileges at any point.)\n\nWhich brings me to another idea: we have quite a few places in Git where \nwe use regular expressions.  Would they not be enough for your use case?\n\n> diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\n> index 36f00ae..efd1687 100644\n> --- a/Documentation/git-daemon.txt\n> +++ b/Documentation/git-daemon.txt\n> @@ -71,6 +72,18 @@ OPTIONS\n>  \tAfter interpolation, the path is validated against the directory\n>  \twhitelist.\n>  \n> +--path-filter=executable::\n> +\tTo support a more flexible directory layout a path filter script \n> +\tcan be used. The executable will receive the service name (upload-pack, \n> +\tupload-archive or receive-pack), the client hostname and the request git \n> +\tdirectory as arguments. The executable must return a zero-terminated string\n> +\ton stdout which is the real path 'git-daemon' should serve. This is useful\n> +\twhen --interpolated-path doesn't buy you enough flexibility. You could for\n> +\tinstance keep support for old clone urls if you rename your repository, or\n> +\tfetch a custom url-mapping from a third-party repo manager application, or\n> +\tmap deeply nested repository directories to a more sensible layout for the \n> +\toutside world.\n\nPlease keep the lines shorter than 81 characters.\n\n> diff --git a/daemon.c b/daemon.c\n> index d93cf96..e6777c6 100644\n> --- a/daemon.c\n> +++ b/daemon.c\n> @@ -287,6 +293,37 @@ static int git_daemon_config(const char *var, const char *value, void *cb)\n>  \treturn 0;\n>  }\n>  \n> +static char *run_path_filter_script(struct daemon_service *s, char *host, char *dir) {\n\nAgain, pretty long line.  (I will refrain from saying that for every long \nline, but please cooperate by pretending I did ;-)\n\nBut there is more: what about concurrent accesses?\n\n> +\tchar result[256]; /* arbitary */\n\nWhy not PATH_MAX?\n\n> +\tchar *real_path;\n> +\tstruct child_process filter_cmd;\n> +\tconst char *args[] = { path_filter_script, s->name, host, dir, NULL };\n> +\n> +\tloginfo(\"Executing path filter script: '%s %s'\", path_filter_script, dir);\n> +\tmemset(&filter_cmd, 0, sizeof(filter_cmd));\n> +\tfilter_cmd.argv = args;\n> +\tfilter_cmd.out = -1;\n> +\t\n> +\tif (start_command(&filter_cmd)) {\n> +\t\tlogerror(\"path filter: unable to fork path_filter_script\");\n> +\t\treturn NULL;\n> +\t}\n> +\t\n> +\tread(filter_cmd.out, result, sizeof(result) - 1);\n\nNo error checking?\n\nBTW we do have strbuf_read(), which would solve your \"static char *\" \nproblem nicely.\n\n> +\tclose(filter_cmd.out);\n> +\tif (finish_command(&filter_cmd)) {\n> +\t\tlogerror(\"path filter died with strange error\");\n> +\t\treturn NULL;\n> +\t}\n> +\n> +\tif (result) {\n> +\t\treal_path = result;\n> +\t\treturn real_path;\n> +\t}\n> +\treturn NULL;\n\nWhat would be the difference if you wrote\n\n\treturn result;\n\ninstead?\n\n> @@ -495,6 +532,7 @@ static void parse_extra_args(char *extra_args, int buflen)\n>  static int execute(struct sockaddr *addr)\n>  {\n>  \tstatic char line[1000];\n> +\tchar *path;\n\nIs it not rather \"const char *\"?  But that point would be moot should you \ndecide to use strbufs.\n\n> @@ -553,11 +591,20 @@ static int execute(struct sockaddr *addr)\n>  \t\tif (!prefixcmp(line, \"git-\") &&\n>  \t\t    !strncmp(s->name, line + 4, namelen) &&\n>  \t\t    line[namelen + 4] == ' ') {\n> +\t\t\tpath = line + namelen + 5;\n> +\t\t\tif (path_filter_script) {\n> +\t\t\t\tloginfo(\"path_filter_script %s for path %s\", path_filter_script, path);\n> +\t\t\t\tchar *tdir;\n\nDeclaration after a call to a function.\n\n> +\t\t\t\tif ((tdir = run_path_filter_script(s, hostname, path))) {\n> +\t\t\t\t\tpath = tdir;\n> +\t\t\t\t}\n\nUnnecessary curly brackets.\n\nAnd your code would be even easier to read if your \nrun_path_filter_script() would never return NULL, but the unchanged path \ninstead.\n\nCiao,\nDscho\n"},{"id":"107842","messageId":"1236872914-43327-1-git-send-email-johan@johansorensen.com","threadId":"18268","inReplyTo":"alpine.DEB.1.00.0903121218000.10279@pacific.mpi-cbg.de","subject":"[PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-12T15:48:34Z","receivedAt":"2009-03-12T15:48:34Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"The parameter for filter-path is an executable that will receive the service\nname, the client hostname and path to the repos the client requests as as\narguments. It is then the responsibility of the script to return a zero\nterminated string on its stdout with the real path of the target repository.\n\nSigned-off-by: Johan Sørensen <johan@johansorensen.com>\n---\n Documentation/git-daemon.txt |   15 +++++++++++\n daemon.c                     |   54 +++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 68 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex 36f00ae..bf8d31f 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -13,6 +13,7 @@ SYNOPSIS\n \t     [--strict-paths] [--base-path=path] [--base-path-relaxed]\n \t     [--user-path | --user-path=path]\n \t     [--interpolated-path=pathtemplate]\n+\t     [--path-filter=executable]\n \t     [--reuseaddr] [--detach] [--pid-file=file]\n \t     [--enable=service] [--disable=service]\n \t     [--allow-override=service] [--forbid-override=service]\n@@ -71,6 +72,20 @@ OPTIONS\n \tAfter interpolation, the path is validated against the directory\n \twhitelist.\n \n+--path-filter=executable::\n+\tTo support a more flexible directory layout a path filter script\n+\tcan be used. The executable will receive the service name (upload-pack,\n+\tupload-archive or receive-pack), the client hostname and the request git\n+\tdirectory as arguments. The executable must return a zero-terminated\n+\tstring on stdout which is the real path 'git-daemon' should serve. This\n+\tis useful when --interpolated-path doesn't buy you enough flexibility.\n+\tYou could for instance keep support for old clone urls if you rename your\n+\trepository, or fetch a custom url-mapping from a third-party repo manager\n+\tapplication, or\tmap deeply nested repository directories to a more\n+\tsensible layout for the outside world.\n+\tPlease be aware that the executable spawned will have the same privileges\n+\tas the user you are running the git-daemon under.\n+\n --export-all::\n \tAllow pulling from all directories that look like GIT repositories\n \t(have the 'objects' and 'refs' subdirectories), even if they\ndiff --git a/daemon.c b/daemon.c\nindex d93cf96..e865e78 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"pkt-line.h\"\n #include \"exec_cmd.h\"\n+#include \"run-command.h\"\n \n #include <syslog.h>\n \n@@ -22,6 +23,7 @@ static const char daemon_usage[] =\n \"           [--strict-paths] [--base-path=path] [--base-path-relaxed]\\n\"\n \"           [--user-path | --user-path=path]\\n\"\n \"           [--interpolated-path=path]\\n\"\n+\"           [--path-filter=path]\\n\"\n \"           [--reuseaddr] [--detach] [--pid-file=file]\\n\"\n \"           [--[enable|disable|allow-override|forbid-override]=service]\\n\"\n \"           [--inetd | [--listen=host_or_ipaddr] [--port=n]\\n\"\n@@ -58,6 +60,11 @@ static char *canon_hostname;\n static char *ip_address;\n static char *tcp_port;\n \n+/* if defined, the script will be executed with the service name, hostname,\n+ * and requested path on stdin and _must_ return with a successful exitcode\n+ * and the new path on stdout */\n+static char *path_filter_script;\n+\n static void logreport(int priority, const char *err, va_list params)\n {\n \tif (log_syslog) {\n@@ -287,6 +294,42 @@ static int git_daemon_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+static char *run_path_filter_script(struct daemon_service *s, char *host,\n+\t\t\t    char *dir) {\n+\tstruct strbuf result_buf = STRBUF_INIT;\n+\tstruct child_process filter_cmd;\n+\tconst char *args[] = { path_filter_script, s->name, host, dir, NULL };\n+\n+\tloginfo(\"Executing path filter script: '%s %s %s %s'\",\n+\t\t\t\t\tpath_filter_script, s->name, host, dir);\n+\tmemset(&filter_cmd, 0, sizeof(filter_cmd));\n+\tfilter_cmd.argv = args;\n+\tfilter_cmd.out = -1;\n+\n+\tif (start_command(&filter_cmd)) {\n+\t\tlogerror(\"path filter: unable to fork path_filter_script\");\n+\t\treturn dir;\n+\t}\n+\n+\tif (strbuf_read(&result_buf, filter_cmd.out, PATH_MAX) < 0) {\n+\t\tstrbuf_release(&result_buf);\n+\t\tclose(filter_cmd.out);\n+\t\tlogerror(\"path filter: script read returned %s\", strerror(errno));\n+\t\treturn dir;\n+\t}\n+\n+\tclose(filter_cmd.out);\n+\tif (finish_command(&filter_cmd)) {\n+\t\tlogerror(\"path filter script died with strange error\");\n+\t\treturn dir;\n+\t}\n+\n+\tif (result_buf.len > 0)\n+\t\tdir = strbuf_detach(&result_buf, NULL);\n+\n+\treturn dir;\n+}\n+\n static int run_service(char *dir, struct daemon_service *service)\n {\n \tconst char *path;\n@@ -557,7 +600,12 @@ static int execute(struct sockaddr *addr)\n \t\t\t * Note: The directory here is probably context sensitive,\n \t\t\t * and might depend on the actual service being performed.\n \t\t\t */\n-\t\t\treturn run_service(line + namelen + 5, s);\n+\t\t\tif (path_filter_script) {\n+\t\t\t\treturn run_service(run_path_filter_script(s, hostname,\n+\t\t\t\t                   line + namelen + 5), s);\n+\t\t\t} else {\n+\t\t\t\treturn run_service(line + namelen + 5, s);\n+\t\t\t}\n \t\t}\n \t}\n \n@@ -1018,6 +1066,10 @@ int main(int argc, char **argv)\n \t\t\tpid_file = arg + 11;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--path-filter=\")) {\n+\t\t\tpath_filter_script = arg + 14;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--detach\")) {\n \t\t\tdetach = 1;\n \t\t\tlog_syslog = 1;\n-- \n1.6.1\n"},{"id":"107848","messageId":"alpine.DEB.1.00.0903121748550.6335@intel-tinevez-2-302","threadId":"18268","inReplyTo":"1236872914-43327-1-git-send-email-johan@johansorensen.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-03-12T16:50:01Z","receivedAt":"2009-03-12T16:50:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 12 Mar 2009, Johan Sørensen wrote:\n\n> The parameter for filter-path is an executable that will receive the service\n> name, the client hostname and path to the repos the client requests as as\n> arguments. It is then the responsibility of the script to return a zero\n> terminated string on its stdout with the real path of the target repository.\n> \n> Signed-off-by: Johan Sørensen <johan@johansorensen.com>\n\nI see that you addressed some, but not all of my concerns.  Do you think \nthat I am wrong?  Then please, by all means, increase my knowledge.\n\nCiao,\nDscho"},{"id":"107866","messageId":"9e0f31700903121206m3adbabacra655c5d340365f43@mail.gmail.com","threadId":"18268","inReplyTo":"alpine.DEB.1.00.0903121218000.10279@pacific.mpi-cbg.de","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-12T19:06:25Z","receivedAt":"2009-03-12T19:06:25Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"On Thu, Mar 12, 2009 at 12:29 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n\n(all my comments below refer to my latest patch)\n\n> More importantly, you might want to point out the security concerns of\n> running a script with the full permissions of git-daemon.  (AFAICT from\n> your patch you are not dropping any privileges at any point.)\n\nDo you really think this is needed? It doesn't seem like running the\nhook scripts does anything more than trusting the script author and\npermissions of the hook scripts (?). I see the path-filter script\nexactly the same way, with the exception of having to double-check the\nuser supplied path the script receives.\n\n> Which brings me to another idea: we have quite a few places in Git where\n> we use regular expressions.  Would they not be enough for your use case?\n\nHmm, please do elaborate on your idea. If you mean being able to\nsupply a bunch of regexp mappings when starting the daemon then it\nwouldn't cut it for me; I'm in need of something more dynamic.\n\n>> diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\n>> index 36f00ae..efd1687 100644\n>> --- a/Documentation/git-daemon.txt\n>> +++ b/Documentation/git-daemon.txt\n>> @@ -71,6 +72,18 @@ OPTIONS\n[snip]\n> Please keep the lines shorter than 81 characters.\n\nI believe the longest line I've added in the docs is 77.\n\n> But there is more: what about concurrent accesses?\n\nThe external path-filter script is run from the execute(), which is\nforked+exec'ed for each incoming connection to the daemon, so that\nwould mean a concurrency of one in that child-process, unless I've\nmissed something in the code path?\n\n>> +     read(filter_cmd.out, result, sizeof(result) - 1);\n>\n> No error checking?\n>\n> BTW we do have strbuf_read(), which would solve your \"static char *\"\n> problem nicely.\n\nI'm using strbuf_read() now, but this being my very first git patch, I\nmay have misunderstood the api slightly?\n\n> And your code would be even easier to read if your\n> run_path_filter_script() would never return NULL, but the unchanged path\n> instead.\n\nDone.\n\nThanks for giving my patch the run-through. I'm still curious to hear\nwhat people think about the idea in general though!\n\n>\n> Ciao,\n> Dscho\n>\n\nCheers,\nJS\n"},{"id":"107999","messageId":"7vvdqcd1zh.fsf@gitster.siamese.dyndns.org","threadId":"18268","inReplyTo":"9e0f31700903121206m3adbabacra655c5d340365f43@mail.gmail.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-03-14T06:58:58Z","receivedAt":"2009-03-14T06:58:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Sørensen <johan@johansorensen.com> writes:\n\n>> More importantly, you might want to point out the security concerns of\n>> running a script with the full permissions of git-daemon.  (AFAICT from\n>> your patch you are not dropping any privileges at any point.)\n>\n> Do you really think this is needed? It doesn't seem like running the\n> hook scripts does anything more than trusting the script author and\n> permissions of the hook scripts (?). I see the path-filter script\n> exactly the same way, with the exception of having to double-check the\n> user supplied path the script receives.\n\nIf I am not misreading the patch (I only skimmed it), the script is what\nis given to the git-daemon process from its command line, so it is under\ntotal control of the site owner.  It is much much much less problematic\nthan the security worry of allowing random hook scripts to be installed in\nthe repositories hosted at a hosting site.  I think Dscho is being a bit\ntoo paranoid in this particular case.\n\nHowever, being paranoid is a good thing when we talk about instructions we\ngive to the end users.  The site owner who uses this facility needs to be\naware that the script is run as the same user that runs git-daemon, and\nthat more than one instances of the script can be run at the same time.\nThe script writer needs to be careful about using the same scratchpad\nlocation for the temporary files the script uses and not letting multiple\ninstances of scripts stomping on each other's toes.  These things need to\nbe documented.\n\nDo you run git-daemon from inetd, or standalone, by the way?  I am\nwondering how well it would scale if you spawn an external \"filter path\"\nscript (by the way, \"filter path\" sounds as if it checks and conditionally\ndenies access to, or something like that, which is not what you are using\nit for.  It is more about rewriting paths, a la mod_rewrite, and I think\nthe option is misnamed) every time you get a request.\n"},{"id":"108013","messageId":"9e0f31700903140739g26be7981lb0fa411cdd8029e6@mail.gmail.com","threadId":"18268","inReplyTo":"7vvdqcd1zh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-14T14:39:24Z","receivedAt":"2009-03-14T14:39:24Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"On Sat, Mar 14, 2009 at 7:58 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> However, being paranoid is a good thing when we talk about instructions we\n> give to the end users.  The site owner who uses this facility needs to be\n> aware that the script is run as the same user that runs git-daemon, and\n> that more than one instances of the script can be run at the same time.\n> The script writer needs to be careful about using the same scratchpad\n> location for the temporary files the script uses and not letting multiple\n> instances of scripts stomping on each other's toes.  These things need to\n> be documented.\n\nWill expand the docs further.\n\n> Do you run git-daemon from inetd, or standalone, by the way?\n\nStandalone.\n\n> I am wondering how well it would scale if you spawn an external \"filter path\"\n> script every time you get a request.\n\nA quick test of 250 consecutive requests with ls-remote to localhost\n(all without the --verbose flag), slowest run:\n- Baseline (no --filter-path agument): 3.39s\n\n$ cat filter.c\n#import \"stdio.h\"\nint main (int argc, char const *argv[]) {\n\tprintf(\"%s\", \"/existing.git\\0\");\n\treturn 0;\n}\n- 3.84s\n\n$ cat filter.rb\n#!/usr/bin/ruby\nprint \"/existing.git\\0\"\n- 4.76s\n\nSo, obviously highly dependent on how long it takes the script to\nlaunch and how much work it does. And yes, neither of the above really\ndoes anything :) nor takes any increased cpu load into account\n\nAnother approach is to keep the external script running and feed it on\nstdin, but that would involve a bit more micro-management of the\nexternal process. I will revisit that idea if I find out that's\nneeded.\n\n> (by the way, \"filter path\" sounds as if it checks and conditionally\n> denies access to, or something like that, which is not what you are using\n> it for.  It is more about rewriting paths, a la mod_rewrite, and I think\n> the option is misnamed)\n\nMaybe --rewrite-script or --rewrite-command  instead?\n\nCheers,\nJS\n"},{"id":"108014","messageId":"7vprgkarq5.fsf@gitster.siamese.dyndns.org","threadId":"18268","inReplyTo":"9e0f31700903140739g26be7981lb0fa411cdd8029e6@mail.gmail.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-03-14T18:23:30Z","receivedAt":"2009-03-14T18:23:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Sørensen <johan@johansorensen.com> writes:\n\n>> Do you run git-daemon from inetd, or standalone, by the way?\n>\n> Standalone.\n>\n>> I am wondering how well it would scale if you spawn an external \"filter path\"\n>> script every time you get a request.\n>\n> A quick test of 250 consecutive requests with ls-remote to localhost\n> (all without the --verbose flag), slowest run:\n> - Baseline (no --filter-path agument): 3.39s\n>\n> $ cat filter.c\n> #import \"stdio.h\"\n> int main (int argc, char const *argv[]) {\n> \tprintf(\"%s\", \"/existing.git\\0\");\n> \treturn 0;\n> }\n> - 3.84s\n>\n> $ cat filter.rb\n> #!/usr/bin/ruby\n> print \"/existing.git\\0\"\n> - 4.76s\n>\n> So, obviously highly dependent on how long it takes the script to\n> launch and how much work it does. And yes, neither of the above really\n> does anything :) nor takes any increased cpu load into account\n>\n> Another approach is to keep the external script running and feed it on\n> stdin, but that would involve a bit more micro-management of the\n> external process. I will revisit that idea if I find out that's\n> needed.\n\nI actually was hoping (especially we have Dscho on Cc: list) that somebody\nlike you would start suggesting a \"plug in\" approach to load .so files,\nwhich would lead to a easy-to-port dso support with the help from msysgit\nfolks we can use later in other parts of the system (e.g. customizable\nfilters used for diff textconv, clean/smudge, etc.)\n\n>> (by the way, \"filter path\" sounds as if it checks and conditionally\n>> denies access to, or something like that, which is not what you are using\n>> it for.  It is more about rewriting paths, a la mod_rewrite, and I think\n>> the option is misnamed)\n>\n> Maybe --rewrite-script or --rewrite-command  instead?\n\nPerhaps.\n"},{"id":"108464","messageId":"alpine.DEB.1.00.0903190107001.10279@pacific.mpi-cbg.de","threadId":"18268","inReplyTo":"7vprgkarq5.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-03-19T00:15:28Z","receivedAt":"2009-03-19T00:15:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 14 Mar 2009, Junio C Hamano wrote:\n\n> Johan Sørensen <johan@johansorensen.com> writes:\n> \n> >> Do you run git-daemon from inetd, or standalone, by the way?\n> >\n> > Standalone.\n> >\n> >> I am wondering how well it would scale if you spawn an external \n> >>\"filter path\" script every time you get a request.\n> >\n> > A quick test of 250 consecutive requests with ls-remote to localhost\n> > (all without the --verbose flag), slowest run:\n> > - Baseline (no --filter-path agument): 3.39s\n> >\n> > $ cat filter.c\n> > #import \"stdio.h\"\n> > int main (int argc, char const *argv[]) {\n> > \tprintf(\"%s\", \"/existing.git\\0\");\n> > \treturn 0;\n> > }\n> > - 3.84s\n> >\n> > $ cat filter.rb\n> > #!/usr/bin/ruby\n> > print \"/existing.git\\0\"\n> > - 4.76s\n> >\n> > So, obviously highly dependent on how long it takes the script to \n> > launch and how much work it does. And yes, neither of the above really \n> > does anything :) nor takes any increased cpu load into account\n> >\n> > Another approach is to keep the external script running and feed it on \n> > stdin, but that would involve a bit more micro-management of the \n> > external process. I will revisit that idea if I find out that's \n> > needed.\n> \n> I actually was hoping (especially we have Dscho on Cc: list) that somebody\n> like you would start suggesting a \"plug in\" approach to load .so files,\n> which would lead to a easy-to-port dso support with the help from msysgit\n> folks we can use later in other parts of the system (e.g. customizable\n> filters used for diff textconv, clean/smudge, etc.)\n\nI do not like that at all.  Dynamic libraries -- especially on Windows -- \nare a major hassle.\n\nHowever, I cannot think of anything Johan might want to do that would not \nbe possible using a bunch of regular expressions together with \nsubstitions.\n\nFWIW I have experimental code in my personal tree that sports \nstrbuf_regsub(), a function to replace matches of a regular expression \n(possibly with groups) by a given string (which may contain \\0 .. \\9, \nbeing replaced with the respective group's contents).\n\nCiao,\nDscho\n"},{"id":"108524","messageId":"9e0f31700903190602h569a3d18y30477c7a136d875e@mail.gmail.com","threadId":"18268","inReplyTo":"alpine.DEB.1.00.0903190107001.10279@pacific.mpi-cbg.de","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johan Sørensen","fromEmail":"johan@johansorensen.com","sentAt":"2009-03-19T13:02:41Z","receivedAt":"2009-03-19T13:02:41Z","isPatch":true,"sender":{"key":"johan@johansorensen.com","avatar":"https://gravatar.com/avatar/dad7869db9d9711098ad213108d1b09967181bb51b667d5a5088c7634ce46616?d=mp&s=160"},"body":"2009/3/19 Johannes Schindelin <Johannes.Schindelin@gmx.de>:\n>> I actually was hoping (especially we have Dscho on Cc: list) that somebody\n>> like you would start suggesting a \"plug in\" approach to load .so files,\n>> which would lead to a easy-to-port dso support with the help from msysgit\n>> folks we can use later in other parts of the system (e.g. customizable\n>> filters used for diff textconv, clean/smudge, etc.)\n>\n> I do not like that at all.  Dynamic libraries -- especially on Windows --\n> are a major hassle.\n>\n> However, I cannot think of anything Johan might want to do that would not\n> be possible using a bunch of regular expressions together with\n> substitions.\n\nLet me reiterate my use-case then: I need to dynamically substitute\none path with another. Perhaps \"map\" paints a better picture than\n\"substitute\" here. Please refer to my second mail in this thread for\nmore details.\n\nThe only way I can see regexps work, is that if they're read, on a\nper-request basis (reloading git-daemon every time they change is just\nsilly), from somewhere outside the git-daemon. Then, you might as well\ntake the full-on approach this patch provides.\n\nCheers,\nJS\n\n\n>\n> FWIW I have experimental code in my personal tree that sports\n> strbuf_regsub(), a function to replace matches of a regular expression\n> (possibly with groups) by a given string (which may contain \\0 .. \\9,\n> being replaced with the respective group's contents).\n>\n> Ciao,\n> Dscho\n>\n"},{"id":"108767","messageId":"alpine.DEB.1.00.0903202321150.6865@intel-tinevez-2-302","threadId":"18268","inReplyTo":"9e0f31700903190602h569a3d18y30477c7a136d875e@mail.gmail.com","subject":"Re: [PATCH] Introduce a filter-path argument to git-daemon, for doing custom path transformations","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-03-20T22:27:44Z","receivedAt":"2009-03-20T22:27:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 19 Mar 2009, Johan Sørensen wrote:\n\n> 2009/3/19 Johannes Schindelin <Johannes.Schindelin@gmx.de>:\n> >> I actually was hoping (especially we have Dscho on Cc: list) that \n> >> somebody like you would start suggesting a \"plug in\" approach to load \n> >> .so files, which would lead to a easy-to-port dso support with the \n> >> help from msysgit folks we can use later in other parts of the system \n> >> (e.g. customizable filters used for diff textconv, clean/smudge, \n> >> etc.)\n> >\n> > I do not like that at all.  Dynamic libraries -- especially on Windows \n> > -- are a major hassle.\n> >\n> > However, I cannot think of anything Johan might want to do that would \n> > not be possible using a bunch of regular expressions together with \n> > substitions.\n> \n> Let me reiterate my use-case then: I need to dynamically substitute one \n> path with another. Perhaps \"map\" paints a better picture than \n> \"substitute\" here. Please refer to my second mail in this thread for \n> more details.\n> \n> The only way I can see regexps work, is that if they're read, on a \n> per-request basis (reloading git-daemon every time they change is just \n> silly), from somewhere outside the git-daemon. Then, you might as well \n> take the full-on approach this patch provides.\n>\n> > FWIW I have experimental code in my personal tree that sports \n> > strbuf_regsub(), a function to replace matches of a regular expression \n> > (possibly with groups) by a given string (which may contain \\0 .. \\9, \n> > being replaced with the respective group's contents).\n\nDo not get me wrong, I can see your use case.\n\nBut I have been cautioning against other possibly regrettably things, and \nit gave me _no_ pleasure at all to be proven correct in hindsight.\n\nI'd rather be called grumpy old Git, be ridiculed and insulted, but at the \nsame time have precautions in git.git that prevent having to admit \nmournfully that some change was not so brilliant after all.\n\nSo if some rules consisting of regular expressions with appropriate \nsubstitutions, even if they will have to be updated from time to time, \nsolve your case, I'd rather have that than allow a server to run external \nprograms that are not exactly well audited against all kinds of attacks.\n\nCiao,\nDscho\n"}]}