Skip to content

Commit

Permalink
Sync with v1.8.5.6
Browse files Browse the repository at this point in the history
* maint-1.8.5:
  Git 1.8.5.6
  fsck: complain about NTFS ".git" aliases in trees
  read-cache: optionally disallow NTFS .git variants
  path: add is_ntfs_dotgit() helper
  fsck: complain about HFS+ ".git" aliases in trees
  read-cache: optionally disallow HFS+ .git variants
  utf8: add is_hfs_dotgit() helper
  fsck: notice .git case-insensitively
  t1450: refactor ".", "..", and ".git" fsck tests
  verify_dotfile(): reject .git case-insensitively
  read-tree: add tests for confusing paths like ".." and ".git"
  unpack-trees: propagate errors adding entries to the index
  • Loading branch information
Junio C Hamano committed Dec 17, 2014
2 parents 9181365 + 5c8213a commit 6898b79
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 39 deletions.
34 changes: 34 additions & 0 deletions Documentation/RelNotes/1.8.5.6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Git v1.8.5.6 Release Notes
==========================

Fixes since v1.8.5.5
--------------------

* We used to allow committing a path ".Git/config" with Git that is
running on a case sensitive filesystem, but an attempt to check out
such a path with Git that runs on a case insensitive filesystem
would have clobbered ".git/config", which is definitely not what
the user would have expected. Git now prevents you from tracking
a path with ".Git" (in any case combination) as a path component.

* On Windows, certain path components that are different from ".git"
are mapped to ".git", e.g. "git~1/config" is treated as if it were
".git/config". HFS+ has a similar issue, where certain unicode
codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
it were ".git/config". Pathnames with these potential issues are
rejected on the affected systems. Git on systems that are not
affected by this issue (e.g. Linux) can also be configured to
reject them to ensure cross platform interoperability of the hosted
projects.

* "git fsck" notices a tree object that records such a path that can
be confused with ".git", and with receive.fsckObjects configuration
set to true, an attempt to "git push" such a tree object will be
rejected. Such a path may not be a problem on a well behaving
filesystem but in order to protect those on HFS+ and on case
insensitive filesystems, this check is enabled on all platforms.

A big "thanks!" for bringing this issue to us goes to our friends in
the Mercurial land, namely, Matt Mackall and Augie Fackler.

Also contains typofixes, documentation updates and trivial code clean-ups.
11 changes: 11 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,17 @@ core.precomposeunicode::
When false, file names are handled fully transparent by Git,
which is backward compatible with older versions of Git.

core.protectHFS::
If set to true, do not allow checkout of paths that would
be considered equivalent to `.git` on an HFS+ filesystem.
Defaults to `true` on Mac OS, and `false` elsewhere.

core.protectNTFS::
If set to true, do not allow checkout of paths that would
cause problems with the NTFS filesystem, e.g. conflict with
8.3 "short" names.
Defaults to `true` on Windows, and `false` elsewhere.

core.trustctime::
If false, the ctime differences between the index and the
working tree are ignored; useful when the inode change time
Expand Down
3 changes: 2 additions & 1 deletion Documentation/git.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ Documentation for older releases are available here:
link:RelNotes/1.9.1.txt[1.9.1],
link:RelNotes/1.9.0.txt[1.9.0].

* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
* link:v1.8.5.6/git.html[documentation for release 1.8.5.6]

* release notes for
link:RelNotes/1.8.5.6.txt[1.8.5.6],
link:RelNotes/1.8.5.5.txt[1.8.5.5],
link:RelNotes/1.8.5.4.txt[1.8.5.4],
link:RelNotes/1.8.5.3.txt[1.8.5.3],
Expand Down
3 changes: 3 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ extern int fsync_object_files;
extern int core_preload_index;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
extern int protect_hfs;
extern int protect_ntfs;

/*
* The character that begins a commented line in user-editable file
Expand Down Expand Up @@ -782,6 +784,7 @@ int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
int offset_1st_component(const char *path);
extern int is_ntfs_dotgit(const char *name);

/* object replacement */
#define LOOKUP_REPLACE_OBJECT 1
Expand Down
10 changes: 10 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,16 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}

if (!strcmp(var, "core.protecthfs")) {
protect_hfs = git_config_bool(var, value);
return 0;
}

if (!strcmp(var, "core.protectntfs")) {
protect_ntfs = git_config_bool(var, value);
return 0;
}

/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
Expand Down
3 changes: 3 additions & 0 deletions config.mak.uname
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ ifeq ($(uname_S),Darwin)
HAVE_DEV_TTY = YesPlease
COMPAT_OBJS += compat/precompose_utf8.o
BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
Expand Down Expand Up @@ -369,6 +370,7 @@ ifeq ($(uname_S),Windows)
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
PTHREAD_LIBS =
lib =
BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
ifndef DEBUG
BASIC_CFLAGS += -GL -Os -MT
BASIC_LDFLAGS += -LTCG
Expand Down Expand Up @@ -513,6 +515,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
BASIC_LDFLAGS += -Wl,--large-address-aware
EXTLIBS += -lws2_32
GITLIBS += git.res
Expand Down
10 changes: 10 additions & 0 deletions environment.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
struct startup_info *startup_info;
unsigned long pack_size_limit_cfg;

#ifndef PROTECT_HFS_DEFAULT
#define PROTECT_HFS_DEFAULT 0
#endif
int protect_hfs = PROTECT_HFS_DEFAULT;

#ifndef PROTECT_NTFS_DEFAULT
#define PROTECT_NTFS_DEFAULT 0
#endif
int protect_ntfs = PROTECT_NTFS_DEFAULT;

/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
Expand Down
4 changes: 3 additions & 1 deletion fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "commit.h"
#include "tag.h"
#include "fsck.h"
#include "utf8.h"

static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
{
Expand Down Expand Up @@ -175,7 +176,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
has_dot = 1;
if (!strcmp(name, ".."))
has_dotdot = 1;
if (!strcmp(name, ".git"))
if (!strcasecmp(name, ".git") || is_hfs_dotgit(name) ||
is_ntfs_dotgit(name))
has_dotgit = 1;
has_zero_pad |= *(char *)desc.buffer == '0';
update_tree_entry(&desc);
Expand Down
33 changes: 33 additions & 0 deletions path.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,3 +830,36 @@ int offset_1st_component(const char *path)
return 2 + is_dir_sep(path[2]);
return is_dir_sep(path[0]);
}

static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
{
if (len < skip)
return 0;
len -= skip;
path += skip;
while (len-- > 0) {
char c = *(path++);
if (c != ' ' && c != '.')
return 0;
}
return 1;
}

int is_ntfs_dotgit(const char *name)
{
int len;

for (len = 0; ; len++)
if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
if (only_spaces_and_periods(name, len, 4) &&
!strncasecmp(name, ".git", 4))
return 1;
if (only_spaces_and_periods(name, len, 5) &&
!strncasecmp(name, "git~1", 5))
return 1;
if (name[len] != '\\')
return 0;
name += len + 1;
len = -1;
}
}
10 changes: 8 additions & 2 deletions read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "resolve-undo.h"
#include "strbuf.h"
#include "varint.h"
#include "utf8.h"

static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options);
Expand Down Expand Up @@ -752,9 +753,10 @@ static int verify_dotfile(const char *rest)
* shares the path end test with the ".." case.
*/
case 'g':
if (rest[1] != 'i')
case 'G':
if (rest[1] != 'i' && rest[1] != 'I')
break;
if (rest[2] != 't')
if (rest[2] != 't' && rest[2] != 'T')
break;
rest += 2;
/* fallthrough */
Expand All @@ -778,6 +780,10 @@ int verify_path(const char *path)
return 1;
if (is_dir_sep(c)) {
inside:
if (protect_hfs && is_hfs_dotgit(path))
return 0;
if (protect_ntfs && is_ntfs_dotgit(path))
return 0;
c = *path++;
if ((c == '.' && !verify_dotfile(path)) ||
is_dir_sep(c) || c == '\0')
Expand Down
62 changes: 62 additions & 0 deletions t/t1014-read-tree-confusing.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/sh

test_description='check that read-tree rejects confusing paths'
. ./test-lib.sh

test_expect_success 'create base tree' '
echo content >file &&
git add file &&
git commit -m base &&
blob=$(git rev-parse HEAD:file) &&
tree=$(git rev-parse HEAD^{tree})
'

test_expect_success 'enable core.protectHFS for rejection tests' '
git config core.protectHFS true
'

test_expect_success 'enable core.protectNTFS for rejection tests' '
git config core.protectNTFS true
'

while read path pretty; do
: ${pretty:=$path}
case "$path" in
*SPACE)
path="${path%SPACE} "
;;
esac
test_expect_success "reject $pretty at end of path" '
printf "100644 blob %s\t%s" "$blob" "$path" >tree &&
bogus=$(git mktree <tree) &&
test_must_fail git read-tree $bogus
'

test_expect_success "reject $pretty as subtree" '
printf "040000 tree %s\t%s" "$tree" "$path" >tree &&
bogus=$(git mktree <tree) &&
test_must_fail git read-tree $bogus
'
done <<-EOF
.
..
.git
.GIT
${u200c}.Git {u200c}.Git
.gI${u200c}T .gI{u200c}T
.GiT${u200c} .GiT{u200c}
git~1
.git.SPACE .git.{space}
.\\\\.GIT\\\\foobar backslashes
.git\\\\foobar backslashes2
EOF

test_expect_success 'utf-8 paths allowed with core.protectHFS off' '
test_when_finished "git read-tree HEAD" &&
test_config core.protectHFS false &&
printf "100644 blob %s\t%s" "$blob" ".gi${u200c}t" >tree &&
ok=$(git mktree <tree) &&
git read-tree $ok
'

test_done
65 changes: 35 additions & 30 deletions t/t1450-fsck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -251,35 +251,40 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' '
)
'

test_expect_success 'fsck notices "." and ".." in trees' '
(
git init dots &&
cd dots &&
blob=$(echo foo | git hash-object -w --stdin) &&
tab=$(printf "\\t") &&
git mktree <<-EOF &&
100644 blob $blob$tab.
100644 blob $blob$tab..
EOF
git fsck 2>out &&
cat out &&
grep "warning.*\\." out
)
'

test_expect_success 'fsck notices ".git" in trees' '
(
git init dotgit &&
cd dotgit &&
blob=$(echo foo | git hash-object -w --stdin) &&
tab=$(printf "\\t") &&
git mktree <<-EOF &&
100644 blob $blob$tab.git
EOF
git fsck 2>out &&
cat out &&
grep "warning.*\\.git" out
)
'
while read name path pretty; do
while read mode type; do
: ${pretty:=$path}
test_expect_success "fsck notices $pretty as $type" '
(
git init $name-$type &&
cd $name-$type &&
echo content >file &&
git add file &&
git commit -m base &&
blob=$(git rev-parse :file) &&
tree=$(git rev-parse HEAD^{tree}) &&
value=$(eval "echo \$$type") &&
printf "$mode $type %s\t%s" "$value" "$path" >bad &&
bad_tree=$(git mktree <bad) &&
git fsck 2>out &&
cat out &&
grep "warning.*tree $bad_tree" out
)'
done <<-\EOF
100644 blob
040000 tree
EOF
done <<-EOF
dot .
dotdot ..
dotgit .git
dotgit-case .GIT
dotgit-unicode .gI${u200c}T .gI{u200c}T
dotgit-case2 .Git
git-tilde1 git~1
dotgitdot .git.
dot-backslash-case .\\\\.GIT\\\\foobar
dotgit-case-backslash .git\\\\foobar
EOF

test_done
6 changes: 5 additions & 1 deletion t/test-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ _z40=0000000000000000000000000000000000000000
LF='
'

export _x05 _x40 _z40 LF
# UTF-8 ZERO WIDTH NON-JOINER, which HFS+ ignores
# when case-folding filenames
u200c=$(printf '\342\200\214')

export _x05 _x40 _z40 LF u200c

# Each test should start with something like this, after copyright notices:
#
Expand Down
Loading

0 comments on commit 6898b79

Please sign in to comment.