summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2016-12-21 14:55:02 -0800
committerJunio C Hamano <gitster@pobox.com>2016-12-21 14:55:02 -0800
commitfe050334074c5132d01e1df2c1b9a82c9b8d394c (patch)
treea5d4136c6aa15eae56ff19c3fffb94acad289757
parent1123026f0bf6cd6c63e0711ef19567e0048d0b6a (diff)
parent5e74824fac646e2ebe335a00bcecd91641a7f7ca (diff)
downloadgit-fe050334074c5132d01e1df2c1b9a82c9b8d394c.tar.gz
Merge branch 'jk/quote-env-path-list-component'
A recent update to receive-pack to make it easier to drop garbage objects made it clear that GIT_ALTERNATE_OBJECT_DIRECTORIES cannot have a pathname with a colon in it (no surprise!), and this in turn made it impossible to push into a repository at such a path. This has been fixed by introducing a quoting mechanism used when appending such a path to the colon-separated list. * jk/quote-env-path-list-component: t5615-alternate-env: double-quotes in file names do not work on Windows t5547-push-quarantine: run the path separator test on Windows, too tmp-objdir: quote paths we add to alternates alternates: accept double-quoted paths
-rw-r--r--Documentation/git.txt6
-rw-r--r--sha1_file.c47
-rwxr-xr-xt/t5547-push-quarantine.sh25
-rwxr-xr-xt/t5615-alternate-env.sh18
-rw-r--r--tmp-objdir.c18
5 files changed, 102 insertions, 12 deletions
diff --git a/Documentation/git.txt b/Documentation/git.txt
index af191c51b1..98033302bb 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -871,6 +871,12 @@ Git so take care if using a foreign front-end.
specifies a ":" separated (on Windows ";" separated) list
of Git object directories which can be used to search for Git
objects. New objects will not be written to these directories.
++
+ Entries that begin with `"` (double-quote) will be interpreted
+ as C-style quoted paths, removing leading and trailing
+ double-quotes and respecting backslash escapes. E.g., the value
+ `"path-with-\"-and-:-in-it":vanilla-path` has two paths:
+ `path-with-"-and-:-in-it` and `vanilla-path`.
`GIT_DIR`::
If the `GIT_DIR` environment variable is set then it
diff --git a/sha1_file.c b/sha1_file.c
index 9c86d1924a..1173071859 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -26,6 +26,7 @@
#include "mru.h"
#include "list.h"
#include "mergesort.h"
+#include "quote.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -329,13 +330,40 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
return 0;
}
+static const char *parse_alt_odb_entry(const char *string,
+ int sep,
+ struct strbuf *out)
+{
+ const char *end;
+
+ strbuf_reset(out);
+
+ if (*string == '#') {
+ /* comment; consume up to next separator */
+ end = strchrnul(string, sep);
+ } else if (*string == '"' && !unquote_c_style(out, string, &end)) {
+ /*
+ * quoted path; unquote_c_style has copied the
+ * data for us and set "end". Broken quoting (e.g.,
+ * an entry that doesn't end with a quote) falls
+ * back to the unquoted case below.
+ */
+ } else {
+ /* normal, unquoted path */
+ end = strchrnul(string, sep);
+ strbuf_add(out, string, end - string);
+ }
+
+ if (*end)
+ end++;
+ return end;
+}
+
static void link_alt_odb_entries(const char *alt, int len, int sep,
const char *relative_base, int depth)
{
- struct string_list entries = STRING_LIST_INIT_NODUP;
- char *alt_copy;
- int i;
struct strbuf objdirbuf = STRBUF_INIT;
+ struct strbuf entry = STRBUF_INIT;
if (depth > 5) {
error("%s: ignoring alternate object stores, nesting too deep.",
@@ -348,16 +376,13 @@ static void link_alt_odb_entries(const char *alt, int len, int sep,
die("unable to normalize object directory: %s",
objdirbuf.buf);
- alt_copy = xmemdupz(alt, len);
- string_list_split_in_place(&entries, alt_copy, sep, -1);
- for (i = 0; i < entries.nr; i++) {
- const char *entry = entries.items[i].string;
- if (entry[0] == '\0' || entry[0] == '#')
+ while (*alt) {
+ alt = parse_alt_odb_entry(alt, sep, &entry);
+ if (!entry.len)
continue;
- link_alt_odb_entry(entry, relative_base, depth, objdirbuf.buf);
+ link_alt_odb_entry(entry.buf, relative_base, depth, objdirbuf.buf);
}
- string_list_clear(&entries, 0);
- free(alt_copy);
+ strbuf_release(&entry);
strbuf_release(&objdirbuf);
}
diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index 1e5d32d068..af9fcd833a 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -33,4 +33,29 @@ test_expect_success 'rejected objects are removed' '
test_cmp expect actual
'
+test_expect_success 'push to repo path with path separator (colon)' '
+ # The interesting failure case here is when the
+ # receiving end cannot access its original object directory,
+ # so make it likely for us to generate a delta by having
+ # a non-trivial file with multiple versions.
+
+ test-genrandom foo 4096 >file.bin &&
+ git add file.bin &&
+ git commit -m bin &&
+
+ if test_have_prereq MINGW
+ then
+ pathsep=";"
+ else
+ pathsep=":"
+ fi &&
+ git clone --bare . "xxx${pathsep}yyy.git" &&
+
+ echo change >>file.bin &&
+ git commit -am change &&
+ # Note that we have to use the full path here, or it gets confused
+ # with the ssh host:path syntax.
+ git push "$(pwd)/xxx${pathsep}yyy.git" HEAD
+'
+
test_done
diff --git a/t/t5615-alternate-env.sh b/t/t5615-alternate-env.sh
index eec4137ca5..26ebb0375d 100755
--- a/t/t5615-alternate-env.sh
+++ b/t/t5615-alternate-env.sh
@@ -68,4 +68,22 @@ test_expect_success 'access alternate via relative path (subdir)' '
EOF
'
+# set variables outside test to avoid quote insanity; the \057 is '/',
+# which doesn't need quoting, but just confirms that de-quoting
+# is working.
+quoted='"one.git\057objects"'
+unquoted='two.git/objects'
+test_expect_success 'mix of quoted and unquoted alternates' '
+ check_obj "$quoted:$unquoted" <<-EOF
+ $one blob
+ $two blob
+'
+
+test_expect_success !MINGW 'broken quoting falls back to interpreting raw' '
+ mv one.git \"one.git &&
+ check_obj \"one.git/objects <<-EOF
+ $one blob
+ EOF
+'
+
test_done
diff --git a/tmp-objdir.c b/tmp-objdir.c
index 64435f23a4..b2d9280f10 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -5,6 +5,7 @@
#include "string-list.h"
#include "strbuf.h"
#include "argv-array.h"
+#include "quote.h"
struct tmp_objdir {
struct strbuf path;
@@ -79,12 +80,27 @@ static void remove_tmp_objdir_on_signal(int signo)
*/
static void env_append(struct argv_array *env, const char *key, const char *val)
{
- const char *old = getenv(key);
+ struct strbuf quoted = STRBUF_INIT;
+ const char *old;
+ /*
+ * Avoid quoting if it's not necessary, for maximum compatibility
+ * with older parsers which don't understand the quoting.
+ */
+ if (*val == '"' || strchr(val, PATH_SEP)) {
+ strbuf_addch(&quoted, '"');
+ quote_c_style(val, &quoted, NULL, 1);
+ strbuf_addch(&quoted, '"');
+ val = quoted.buf;
+ }
+
+ old = getenv(key);
if (!old)
argv_array_pushf(env, "%s=%s", key, val);
else
argv_array_pushf(env, "%s=%s%c%s", key, old, PATH_SEP, val);
+
+ strbuf_release(&quoted);
}
static void env_replace(struct argv_array *env, const char *key, const char *val)