summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/git-daemon.txt15
-rw-r--r--Makefile5
-rw-r--r--daemon.c76
-rwxr-xr-xgit-whatchanged.sh18
-rw-r--r--http-fetch.c13
-rw-r--r--http.c3
-rw-r--r--rev-parse.c16
8 files changed, 118 insertions, 29 deletions
diff --git a/.gitignore b/.gitignore
index 5382e74271..513f22eb1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,7 @@ git-send-pack
git-sh-setup
git-shell
git-shortlog
+git-show
git-show-branch
git-show-index
git-ssh-fetch
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index a20e0533fc..2cc6075fb0 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -10,7 +10,8 @@ SYNOPSIS
[verse]
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
[--timeout=n] [--init-timeout=n] [--strict-paths]
- [--base-path=path] [directory...]
+ [--base-path=path] [--user-path | --user-path=path]
+ [directory...]
DESCRIPTION
-----------
@@ -42,8 +43,7 @@ OPTIONS
This is sort of "GIT root" - if you run git-daemon with
'--base-path=/srv/git' on example.com, then if you later try to pull
'git://example.com/hello.git', `git-daemon` will interpret the path
- as '/srv/git/hello.git'. Home directories (the '~login' notation)
- access is disabled.
+ as '/srv/git/hello.git'.
--export-all::
Allow pulling from all directories that look like GIT repositories
@@ -70,6 +70,15 @@ OPTIONS
Log to syslog instead of stderr. Note that this option does not imply
--verbose, thus by default only error conditions will be logged.
+--user-path, --user-path=path::
+ Allow ~user notation to be used in requests. When
+ specified with no parameter, requests to
+ git://host/~alice/foo is taken as a request to access
+ 'foo' repository in the home directory of user `alice`.
+ If `--user-path=path` is specified, the same request is
+ taken as a request to access `path/foo` repository in
+ the home directory of user `alice`.
+
--verbose::
Log details about the incoming connections and requested files.
diff --git a/Makefile b/Makefile
index 2aa2385b6b..dfd765115c 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@ SCRIPT_PYTHON = \
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
- git-cherry-pick
+ git-cherry-pick git-show
# The ones that do not have to link with lcrypto nor lz.
SIMPLE_PROGRAMS = \
@@ -440,6 +440,9 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
git-cherry-pick: git-revert
cp $< $@
+git-show: git-whatchanged
+ cp $< $@
+
# These can record GIT_VERSION
git$X git.spec \
$(patsubst %.sh,%,$(SCRIPT_SH)) \
diff --git a/daemon.c b/daemon.c
index 532bb0c325..a1ccda30e2 100644
--- a/daemon.c
+++ b/daemon.c
@@ -13,11 +13,13 @@
static int log_syslog;
static int verbose;
+static int reuseaddr;
static const char daemon_usage[] =
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
" [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
-" [--base-path=path] [directory...]";
+" [--base-path=path] [--user-path | --user-path=path]\n"
+" [--reuseaddr] [directory...]";
/* List of acceptable pathname prefixes */
static char **ok_paths = NULL;
@@ -29,6 +31,12 @@ static int export_all_trees = 0;
/* Take all paths relative to this one if non-NULL */
static char *base_path = NULL;
+/* If defined, ~user notation is allowed and the string is inserted
+ * after ~user/. E.g. a request to git://host/~alice/frotz would
+ * go to /home/alice/pub_git/frotz with --user-path=pub_git.
+ */
+static char *user_path = NULL;
+
/* Timeout, and initial timeout */
static unsigned int timeout = 0;
static unsigned int init_timeout = 0;
@@ -136,6 +144,7 @@ static int avoid_alias(char *p)
static char *path_ok(char *dir)
{
+ static char rpath[PATH_MAX];
char *path;
if (avoid_alias(dir)) {
@@ -143,15 +152,38 @@ static char *path_ok(char *dir)
return NULL;
}
- if (base_path) {
- static char rpath[PATH_MAX];
+ if (*dir == '~') {
+ if (!user_path) {
+ logerror("'%s': User-path not allowed", dir);
+ return NULL;
+ }
+ if (*user_path) {
+ /* Got either "~alice" or "~alice/foo";
+ * rewrite them to "~alice/%s" or
+ * "~alice/%s/foo".
+ */
+ int namlen, restlen = strlen(dir);
+ char *slash = strchr(dir, '/');
+ if (!slash)
+ slash = dir + restlen;
+ namlen = slash - dir;
+ restlen -= namlen;
+ loginfo("userpath <%s>, request <%s>, namlen %d, restlen %d, slash <%s>", user_path, dir, namlen, restlen, slash);
+ snprintf(rpath, PATH_MAX, "%.*s/%s%.*s",
+ namlen, dir, user_path, restlen, slash);
+ dir = rpath;
+ }
+ }
+ else if (base_path) {
if (*dir != '/') {
- /* Forbid possible base-path evasion using ~paths. */
+ /* Allow only absolute */
logerror("'%s': Non-absolute path denied (base-path active)", dir);
return NULL;
}
- snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
- dir = rpath;
+ else {
+ snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
+ dir = rpath;
+ }
}
path = enter_repo(dir, strict_paths);
@@ -447,6 +479,16 @@ static void child_handler(int signo)
}
}
+static int set_reuse_addr(int sockfd)
+{
+ int on = 1;
+
+ if (!reuseaddr)
+ return 0;
+ return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on));
+}
+
#ifndef NO_IPV6
static int socksetup(int port, int **socklist_p)
@@ -491,6 +533,11 @@ static int socksetup(int port, int **socklist_p)
}
#endif
+ if (set_reuse_addr(sockfd)) {
+ close(sockfd);
+ return 0; /* not fatal */
+ }
+
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
close(sockfd);
continue; /* not fatal */
@@ -533,6 +580,11 @@ static int socksetup(int port, int **socklist_p)
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
+ if (set_reuse_addr(sockfd)) {
+ close(sockfd);
+ return 0;
+ }
+
if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
close(sockfd);
return 0;
@@ -659,6 +711,18 @@ int main(int argc, char **argv)
base_path = arg+12;
continue;
}
+ if (!strcmp(arg, "--reuseaddr")) {
+ reuseaddr = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--user-path")) {
+ user_path = "";
+ continue;
+ }
+ if (!strncmp(arg, "--user-path=", 12)) {
+ user_path = arg + 12;
+ continue;
+ }
if (!strcmp(arg, "--")) {
ok_paths = &argv[i+1];
break;
diff --git a/git-whatchanged.sh b/git-whatchanged.sh
index d4f985b5eb..574fc3558e 100755
--- a/git-whatchanged.sh
+++ b/git-whatchanged.sh
@@ -5,14 +5,24 @@ SUBDIRECTORY_OK='Yes'
. git-sh-setup
diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit
+case "$0" in
+*whatchanged)
+ count=
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+ diff_tree_default_flags='-M --abbrev' ;;
+*show)
+ count=-n1
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get show.difftree)
+ diff_tree_default_flags='--cc --always' ;;
+esac
test -z "$diff_tree_flags" &&
- diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
-test -z "$diff_tree_flags" &&
- diff_tree_flags='-M --abbrev'
+ diff_tree_flags="$diff_tree_default_flags"
rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
-eval "git-rev-list $rev_list_args" |
+eval "git-rev-list $count $rev_list_args" |
eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
LESS="$LESS -S" ${PAGER:-less}
diff --git a/http-fetch.c b/http-fetch.c
index 72edf28b00..bddbd6b100 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -311,7 +311,7 @@ void fill_active_slots(void)
while (active_requests < max_requests && obj_req != NULL) {
if (obj_req->state == WAITING) {
if (has_sha1_file(obj_req->sha1))
- release_object_request(obj_req);
+ obj_req->state = COMPLETE;
else
start_object_request(obj_req);
curl_multi_perform(curlm, &num_transfers);
@@ -468,13 +468,11 @@ static void process_alternates_response(void *callback_data)
alt_req->url);
active_requests++;
slot->in_use = 1;
- if (start_active_slot(slot)) {
- return;
- } else {
+ if (!start_active_slot(slot)) {
got_alternates = -1;
slot->in_use = 0;
- return;
}
+ return;
}
} else if (slot->curl_result != CURLE_OK) {
if (slot->http_code != 404 &&
@@ -822,9 +820,8 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
} else if (memcmp(obj_req->sha1, obj_req->real_sha1, 20)) {
ret = error("File %s has bad hash\n", hex);
} else if (obj_req->rename < 0) {
- ret = error("unable to write sha1 filename %s: %s",
- obj_req->filename,
- strerror(obj_req->rename));
+ ret = error("unable to write sha1 filename %s",
+ obj_req->filename);
}
release_object_request(obj_req);
diff --git a/http.c b/http.c
index eefb0f03d2..632c2c5c2f 100644
--- a/http.c
+++ b/http.c
@@ -192,6 +192,9 @@ static CURL* get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
+ if (getenv("GIT_CURL_VERBOSE"))
+ curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
+
return result;
}
diff --git a/rev-parse.c b/rev-parse.c
index 9cec33b8c0..b82f294a78 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -150,11 +150,14 @@ static void show_datestring(const char *flag, const char *datestr)
show(buffer);
}
-static void show_file(const char *arg)
+static int show_file(const char *arg)
{
show_default();
- if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV))
+ if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
show(arg);
+ return 1;
+ }
+ return 0;
}
int main(int argc, char **argv)
@@ -329,14 +332,13 @@ int main(int argc, char **argv)
show_rev(REVERSED, sha1, arg+1);
continue;
}
+ as_is = 1;
+ if (!show_file(arg))
+ continue;
if (verify)
die("Needed a single revision");
- if ((filter & DO_REVS) &&
- (filter & DO_NONFLAGS) && /* !def && */
- lstat(arg, &st) < 0)
+ if (lstat(arg, &st) < 0)
die("'%s': %s", arg, strerror(errno));
- as_is = 1;
- show_file(arg);
}
show_default();
if (verify && revs_count != 1)