Sync with v2.0.5
* maint-2.0: Git 2.0.5 Git 1.9.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
This commit is contained in:
commit
58f1d950e3
34
Documentation/RelNotes/1.8.5.6.txt
Normal file
34
Documentation/RelNotes/1.8.5.6.txt
Normal file
@ -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.
|
34
Documentation/RelNotes/1.9.5.txt
Normal file
34
Documentation/RelNotes/1.9.5.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Git v1.9.5 Release Notes
|
||||
========================
|
||||
|
||||
Fixes since v1.9.4
|
||||
------------------
|
||||
|
||||
* 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.
|
34
Documentation/RelNotes/2.0.5.txt
Normal file
34
Documentation/RelNotes/2.0.5.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Git v2.0.5 Release Notes
|
||||
========================
|
||||
|
||||
Fixes since v2.0.4
|
||||
------------------
|
||||
|
||||
* 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.
|
@ -233,6 +233,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
|
||||
|
@ -51,27 +51,30 @@ Documentation for older releases are available here:
|
||||
link:RelNotes/2.1.1.txt[2.1.1],
|
||||
link:RelNotes/2.1.0.txt[2.1].
|
||||
|
||||
* link:v2.0.4/git.html[documentation for release 2.0.4]
|
||||
* link:v2.0.5/git.html[documentation for release 2.0.5]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes/2.0.5.txt[2.0.5],
|
||||
link:RelNotes/2.0.4.txt[2.0.4],
|
||||
link:RelNotes/2.0.3.txt[2.0.3],
|
||||
link:RelNotes/2.0.2.txt[2.0.2],
|
||||
link:RelNotes/2.0.1.txt[2.0.1],
|
||||
link:RelNotes/2.0.0.txt[2.0.0].
|
||||
|
||||
* link:v1.9.4/git.html[documentation for release 1.9.4]
|
||||
* link:v1.9.5/git.html[documentation for release 1.9.5]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes/1.9.5.txt[1.9.5],
|
||||
link:RelNotes/1.9.4.txt[1.9.4],
|
||||
link:RelNotes/1.9.3.txt[1.9.3],
|
||||
link:RelNotes/1.9.2.txt[1.9.2],
|
||||
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],
|
||||
|
3
cache.h
3
cache.h
@ -633,6 +633,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
|
||||
@ -847,6 +849,7 @@ int normalize_path_copy(char *dst, const char *src);
|
||||
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);
|
||||
extern int is_ntfs_dotgit(const char *name);
|
||||
|
||||
/* object replacement */
|
||||
#define LOOKUP_REPLACE_OBJECT 1
|
||||
|
10
config.c
10
config.c
@ -880,6 +880,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;
|
||||
}
|
||||
|
@ -100,6 +100,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
|
||||
@ -368,6 +369,7 @@ ifeq ($(uname_S),Windows)
|
||||
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj
|
||||
PTHREAD_LIBS =
|
||||
lib =
|
||||
BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
|
||||
ifndef DEBUG
|
||||
BASIC_CFLAGS += -GL -Os -MD
|
||||
BASIC_LDFLAGS += -LTCG
|
||||
@ -509,6 +511,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
|
||||
|
@ -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.
|
||||
|
5
fsck.c
5
fsck.c
@ -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)
|
||||
{
|
||||
@ -170,7 +171,9 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
|
||||
has_empty_name |= !*name;
|
||||
has_dot |= !strcmp(name, ".");
|
||||
has_dotdot |= !strcmp(name, "..");
|
||||
has_dotgit |= !strcmp(name, ".git");
|
||||
has_dotgit |= (!strcmp(name, ".git") ||
|
||||
is_hfs_dotgit(name) ||
|
||||
is_ntfs_dotgit(name));
|
||||
has_zero_pad |= *(char *)desc.buffer == '0';
|
||||
update_tree_entry(&desc);
|
||||
|
||||
|
33
path.c
33
path.c
@ -821,3 +821,36 @@ int daemon_avoid_alias(const char *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
read-cache.c
10
read-cache.c
@ -16,6 +16,7 @@
|
||||
#include "varint.h"
|
||||
#include "split-index.h"
|
||||
#include "sigchain.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
|
||||
unsigned int options);
|
||||
@ -775,9 +776,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 */
|
||||
@ -801,6 +803,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')
|
||||
|
62
t/t1014-read-tree-confusing.sh
Executable file
62
t/t1014-read-tree-confusing.sh
Executable file
@ -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
|
@ -271,36 +271,41 @@ 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
|
||||
|
||||
# create a static test repo which is broken by omitting
|
||||
# one particular object ($1, which is looked up via rev-parse
|
||||
|
@ -169,7 +169,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:
|
||||
#
|
||||
|
@ -98,7 +98,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
|
||||
opts->unpack_rejects[i].strdup_strings = 1;
|
||||
}
|
||||
|
||||
static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
|
||||
static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
clear |= CE_HASHED;
|
||||
@ -107,8 +107,8 @@ static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
|
||||
set |= CE_WT_REMOVE;
|
||||
|
||||
ce->ce_flags = (ce->ce_flags & ~clear) | set;
|
||||
add_index_entry(&o->result, ce,
|
||||
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
|
||||
return add_index_entry(&o->result, ce,
|
||||
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
|
||||
}
|
||||
|
||||
static struct cache_entry *dup_entry(const struct cache_entry *ce)
|
||||
@ -609,7 +609,9 @@ static int unpack_nondirectories(int n, unsigned long mask,
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (src[i] && src[i] != o->df_conflict_entry)
|
||||
do_add_entry(o, src[i], 0, 0);
|
||||
if (do_add_entry(o, src[i], 0, 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
64
utf8.c
64
utf8.c
@ -565,3 +565,67 @@ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding)
|
||||
|
||||
return chrlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick the next char from the stream, folding as an HFS+ filename comparison
|
||||
* would. Note that this is _not_ complete by any means. It's just enough
|
||||
* to make is_hfs_dotgit() work, and should not be used otherwise.
|
||||
*/
|
||||
static ucs_char_t next_hfs_char(const char **in)
|
||||
{
|
||||
while (1) {
|
||||
ucs_char_t out = pick_one_utf8_char(in, NULL);
|
||||
/*
|
||||
* check for malformed utf8. Technically this
|
||||
* gets converted to a percent-sequence, but
|
||||
* returning 0 is good enough for is_hfs_dotgit
|
||||
* to realize it cannot be .git
|
||||
*/
|
||||
if (!*in)
|
||||
return 0;
|
||||
|
||||
/* these code points are ignored completely */
|
||||
switch (out) {
|
||||
case 0x200c: /* ZERO WIDTH NON-JOINER */
|
||||
case 0x200d: /* ZERO WIDTH JOINER */
|
||||
case 0x200e: /* LEFT-TO-RIGHT MARK */
|
||||
case 0x200f: /* RIGHT-TO-LEFT MARK */
|
||||
case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
|
||||
case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
|
||||
case 0x202c: /* POP DIRECTIONAL FORMATTING */
|
||||
case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
|
||||
case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
|
||||
case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
|
||||
case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
|
||||
case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
|
||||
case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
|
||||
case 0x206e: /* NATIONAL DIGIT SHAPES */
|
||||
case 0x206f: /* NOMINAL DIGIT SHAPES */
|
||||
case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* there's a great deal of other case-folding that occurs,
|
||||
* but this is enough to catch anything that will convert
|
||||
* to ".git"
|
||||
*/
|
||||
return tolower(out);
|
||||
}
|
||||
}
|
||||
|
||||
int is_hfs_dotgit(const char *path)
|
||||
{
|
||||
ucs_char_t c;
|
||||
|
||||
if (next_hfs_char(&path) != '.' ||
|
||||
next_hfs_char(&path) != 'g' ||
|
||||
next_hfs_char(&path) != 'i' ||
|
||||
next_hfs_char(&path) != 't')
|
||||
return 0;
|
||||
c = next_hfs_char(&path);
|
||||
if (c && !is_dir_sep(c))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
8
utf8.h
8
utf8.h
@ -42,4 +42,12 @@ static inline char *reencode_string(const char *in,
|
||||
|
||||
int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
|
||||
|
||||
/*
|
||||
* Returns true if the the path would match ".git" after HFS case-folding.
|
||||
* The path should be NUL-terminated, but we will match variants of both ".git\0"
|
||||
* and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
|
||||
* and verify_path().
|
||||
*/
|
||||
int is_hfs_dotgit(const char *path);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user