rugged 1.3.2.3 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/rugged/extconf.rb +1 -1
- data/ext/rugged/rugged_config.c +7 -2
- data/ext/rugged/rugged_remote.c +17 -0
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +103 -276
- data/vendor/libgit2/COPYING +36 -19
- data/vendor/libgit2/cmake/AddCFlagIfSupported.cmake +21 -21
- data/vendor/libgit2/cmake/DefaultCFlags.cmake +154 -0
- data/vendor/libgit2/cmake/EnableWarnings.cmake +13 -13
- data/vendor/libgit2/cmake/FindCoreFoundation.cmake +13 -13
- data/vendor/libgit2/cmake/FindGSSAPI.cmake +171 -287
- data/vendor/libgit2/cmake/FindGSSFramework.cmake +13 -13
- data/vendor/libgit2/cmake/{FindHTTP_Parser.cmake → FindHTTPParser.cmake} +17 -17
- data/vendor/libgit2/cmake/FindIconv.cmake +27 -27
- data/vendor/libgit2/cmake/FindLibSSH2.cmake +5 -5
- data/vendor/libgit2/cmake/FindPCRE.cmake +13 -13
- data/vendor/libgit2/cmake/FindPCRE2.cmake +12 -12
- data/vendor/libgit2/cmake/FindPkgLibraries.cmake +19 -19
- data/vendor/libgit2/cmake/FindSecurity.cmake +14 -14
- data/vendor/libgit2/cmake/FindStatNsec.cmake +12 -18
- data/vendor/libgit2/cmake/Findfutimens.cmake +8 -8
- data/vendor/libgit2/cmake/FindmbedTLS.cmake +63 -70
- data/vendor/libgit2/cmake/IdeSplitSources.cmake +18 -18
- data/vendor/libgit2/cmake/PkgBuildConfig.cmake +60 -60
- data/vendor/libgit2/cmake/SanitizeBool.cmake +20 -20
- data/vendor/libgit2/cmake/SelectGSSAPI.cmake +37 -37
- data/vendor/libgit2/cmake/SelectHTTPParser.cmake +19 -0
- data/vendor/libgit2/cmake/SelectHTTPSBackend.cmake +100 -100
- data/vendor/libgit2/cmake/SelectHashes.cmake +39 -49
- data/vendor/libgit2/cmake/SelectRegex.cmake +51 -0
- data/vendor/libgit2/cmake/SelectSSH.cmake +41 -0
- data/vendor/libgit2/cmake/SelectWinHTTP.cmake +17 -0
- data/vendor/libgit2/cmake/SelectZlib.cmake +34 -0
- data/vendor/libgit2/deps/chromium-zlib/CMakeLists.txt +6 -6
- data/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +31 -31
- data/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +1 -1
- data/vendor/libgit2/deps/ntlmclient/ntlm.c +4 -4
- data/vendor/libgit2/deps/ntlmclient/ntlm.h +4 -4
- data/vendor/libgit2/deps/ntlmclient/ntlmclient.h +2 -2
- data/vendor/libgit2/deps/pcre/CMakeLists.txt +88 -88
- data/vendor/libgit2/deps/winhttp/CMakeLists.txt +14 -16
- data/vendor/libgit2/deps/zlib/adler32.c +0 -7
- data/vendor/libgit2/deps/zlib/crc32.c +288 -975
- data/vendor/libgit2/deps/zlib/crc32.h +436 -9441
- data/vendor/libgit2/deps/zlib/deflate.c +31 -83
- data/vendor/libgit2/deps/zlib/deflate.h +15 -12
- data/vendor/libgit2/deps/zlib/gzguts.h +2 -3
- data/vendor/libgit2/deps/zlib/infback.c +1 -2
- data/vendor/libgit2/deps/zlib/inffast.c +14 -14
- data/vendor/libgit2/deps/zlib/inflate.c +8 -39
- data/vendor/libgit2/deps/zlib/inflate.h +2 -3
- data/vendor/libgit2/deps/zlib/inftrees.c +3 -3
- data/vendor/libgit2/deps/zlib/trees.c +48 -27
- data/vendor/libgit2/deps/zlib/zlib.h +100 -126
- data/vendor/libgit2/deps/zlib/zutil.c +2 -2
- data/vendor/libgit2/deps/zlib/zutil.h +9 -12
- data/vendor/libgit2/include/git2/apply.h +16 -2
- data/vendor/libgit2/include/git2/attr.h +11 -2
- data/vendor/libgit2/include/git2/blame.h +4 -1
- data/vendor/libgit2/include/git2/blob.h +14 -1
- data/vendor/libgit2/include/git2/branch.h +2 -0
- data/vendor/libgit2/include/git2/buffer.h +18 -78
- data/vendor/libgit2/include/git2/cert.h +2 -2
- data/vendor/libgit2/include/git2/checkout.h +5 -2
- data/vendor/libgit2/include/git2/clone.h +3 -3
- data/vendor/libgit2/include/git2/commit.h +2 -0
- data/vendor/libgit2/include/git2/common.h +5 -12
- data/vendor/libgit2/include/git2/config.h +19 -3
- data/vendor/libgit2/include/git2/credential.h +2 -1
- data/vendor/libgit2/include/git2/credential_helpers.h +1 -0
- data/vendor/libgit2/include/git2/deprecated.h +1 -1
- data/vendor/libgit2/include/git2/describe.h +7 -2
- data/vendor/libgit2/include/git2/diff.h +17 -9
- data/vendor/libgit2/include/git2/email.h +1 -1
- data/vendor/libgit2/include/git2/errors.h +1 -2
- data/vendor/libgit2/include/git2/filter.h +7 -2
- data/vendor/libgit2/include/git2/graph.h +1 -0
- data/vendor/libgit2/include/git2/ignore.h +1 -1
- data/vendor/libgit2/include/git2/index.h +11 -5
- data/vendor/libgit2/include/git2/indexer.h +19 -0
- data/vendor/libgit2/include/git2/merge.h +23 -3
- data/vendor/libgit2/include/git2/message.h +2 -0
- data/vendor/libgit2/include/git2/object.h +23 -0
- data/vendor/libgit2/include/git2/odb.h +37 -7
- data/vendor/libgit2/include/git2/odb_backend.h +1 -1
- data/vendor/libgit2/include/git2/pack.h +24 -8
- data/vendor/libgit2/include/git2/patch.h +8 -0
- data/vendor/libgit2/include/git2/pathspec.h +1 -1
- data/vendor/libgit2/include/git2/proxy.h +1 -1
- data/vendor/libgit2/include/git2/rebase.h +9 -1
- data/vendor/libgit2/include/git2/refdb.h +3 -0
- data/vendor/libgit2/include/git2/reflog.h +1 -1
- data/vendor/libgit2/include/git2/refs.h +2 -2
- data/vendor/libgit2/include/git2/remote.h +184 -37
- data/vendor/libgit2/include/git2/repository.h +14 -9
- data/vendor/libgit2/include/git2/reset.h +2 -2
- data/vendor/libgit2/include/git2/revparse.h +1 -1
- data/vendor/libgit2/include/git2/revwalk.h +4 -1
- data/vendor/libgit2/include/git2/signature.h +1 -1
- data/vendor/libgit2/include/git2/stash.h +3 -3
- data/vendor/libgit2/include/git2/status.h +9 -3
- data/vendor/libgit2/include/git2/submodule.h +7 -2
- data/vendor/libgit2/include/git2/sys/commit_graph.h +1 -1
- data/vendor/libgit2/include/git2/sys/odb_backend.h +2 -5
- data/vendor/libgit2/include/git2/sys/remote.h +31 -0
- data/vendor/libgit2/include/git2/sys/stream.h +1 -1
- data/vendor/libgit2/include/git2/sys/transport.h +25 -34
- data/vendor/libgit2/include/git2/tag.h +1 -0
- data/vendor/libgit2/include/git2/tree.h +4 -3
- data/vendor/libgit2/include/git2/types.h +7 -7
- data/vendor/libgit2/include/git2/version.h +3 -3
- data/vendor/libgit2/include/git2/worktree.h +12 -2
- data/vendor/libgit2/src/CMakeLists.txt +189 -315
- data/vendor/libgit2/src/annotated_commit.h +1 -1
- data/vendor/libgit2/src/apply.c +18 -18
- data/vendor/libgit2/src/apply.h +2 -2
- data/vendor/libgit2/src/attr.c +18 -18
- data/vendor/libgit2/src/attr_file.c +17 -17
- data/vendor/libgit2/src/attr_file.h +4 -4
- data/vendor/libgit2/src/attrcache.c +17 -12
- data/vendor/libgit2/src/blame_git.c +1 -1
- data/vendor/libgit2/src/blob.c +33 -26
- data/vendor/libgit2/src/blob.h +1 -1
- data/vendor/libgit2/src/branch.c +150 -109
- data/vendor/libgit2/src/branch.h +15 -3
- data/vendor/libgit2/src/buf.c +126 -0
- data/vendor/libgit2/src/buf.h +50 -0
- data/vendor/libgit2/src/cc-compat.h +1 -1
- data/vendor/libgit2/src/checkout.c +74 -68
- data/vendor/libgit2/src/cherrypick.c +10 -10
- data/vendor/libgit2/src/clone.c +66 -66
- data/vendor/libgit2/src/commit.c +128 -58
- data/vendor/libgit2/src/commit.h +24 -1
- data/vendor/libgit2/src/commit_graph.c +68 -53
- data/vendor/libgit2/src/commit_graph.h +10 -3
- data/vendor/libgit2/src/commit_list.c +2 -3
- data/vendor/libgit2/src/common.h +10 -3
- data/vendor/libgit2/src/config.c +99 -77
- data/vendor/libgit2/src/config.h +15 -2
- data/vendor/libgit2/src/config_file.c +103 -91
- data/vendor/libgit2/src/config_mem.c +9 -9
- data/vendor/libgit2/src/config_parse.c +27 -23
- data/vendor/libgit2/src/crlf.c +24 -21
- data/vendor/libgit2/src/date.c +10 -17
- data/vendor/libgit2/src/date.h +33 -0
- data/vendor/libgit2/src/describe.c +27 -19
- data/vendor/libgit2/src/diff.c +25 -8
- data/vendor/libgit2/src/diff.h +2 -4
- data/vendor/libgit2/src/diff_driver.c +34 -36
- data/vendor/libgit2/src/diff_driver.h +3 -3
- data/vendor/libgit2/src/diff_file.c +29 -20
- data/vendor/libgit2/src/diff_generate.c +30 -6
- data/vendor/libgit2/src/diff_generate.h +5 -3
- data/vendor/libgit2/src/diff_print.c +102 -95
- data/vendor/libgit2/src/diff_stats.c +40 -29
- data/vendor/libgit2/src/{message.h → diff_stats.h} +7 -6
- data/vendor/libgit2/src/diff_tform.c +9 -8
- data/vendor/libgit2/src/diff_xdiff.c +3 -8
- data/vendor/libgit2/src/email.c +54 -38
- data/vendor/libgit2/src/email.h +1 -1
- data/vendor/libgit2/src/errors.c +18 -18
- data/vendor/libgit2/src/features.h.in +6 -1
- data/vendor/libgit2/src/fetch.c +69 -24
- data/vendor/libgit2/src/fetch.h +1 -1
- data/vendor/libgit2/src/fetchhead.c +19 -19
- data/vendor/libgit2/src/filebuf.c +28 -28
- data/vendor/libgit2/src/filebuf.h +1 -1
- data/vendor/libgit2/src/filter.c +96 -52
- data/vendor/libgit2/src/filter.h +26 -5
- data/vendor/libgit2/src/fs_path.c +1912 -0
- data/vendor/libgit2/src/fs_path.h +752 -0
- data/vendor/libgit2/src/futils.c +91 -85
- data/vendor/libgit2/src/futils.h +26 -14
- data/vendor/libgit2/src/hash/sha1/collisiondetect.c +2 -2
- data/vendor/libgit2/src/hash/sha1/common_crypto.c +2 -2
- data/vendor/libgit2/src/hash/sha1/generic.c +2 -2
- data/vendor/libgit2/src/hash/sha1/mbedtls.c +2 -2
- data/vendor/libgit2/src/hash/sha1/openssl.c +2 -2
- data/vendor/libgit2/src/hash/sha1/sha1dc/sha1.c +1 -1
- data/vendor/libgit2/src/hash/sha1/win32.c +6 -6
- data/vendor/libgit2/src/hash/sha1.h +3 -1
- data/vendor/libgit2/src/hash.c +67 -35
- data/vendor/libgit2/src/hash.h +12 -12
- data/vendor/libgit2/src/ident.c +18 -18
- data/vendor/libgit2/src/ignore.c +35 -34
- data/vendor/libgit2/src/ignore.h +2 -2
- data/vendor/libgit2/src/index.c +79 -80
- data/vendor/libgit2/src/index.h +6 -3
- data/vendor/libgit2/src/indexer.c +75 -57
- data/vendor/libgit2/src/iterator.c +64 -56
- data/vendor/libgit2/src/iterator.h +5 -5
- data/vendor/libgit2/src/khash.h +1 -1
- data/vendor/libgit2/src/libgit2.c +22 -19
- data/vendor/libgit2/src/mailmap.c +38 -36
- data/vendor/libgit2/src/merge.c +27 -27
- data/vendor/libgit2/src/merge.h +1 -14
- data/vendor/libgit2/src/merge_driver.c +2 -2
- data/vendor/libgit2/src/merge_file.c +13 -3
- data/vendor/libgit2/src/message.c +21 -10
- data/vendor/libgit2/src/midx.c +83 -66
- data/vendor/libgit2/src/midx.h +3 -3
- data/vendor/libgit2/src/mwindow.c +1 -1
- data/vendor/libgit2/src/net.c +278 -68
- data/vendor/libgit2/src/net.h +10 -3
- data/vendor/libgit2/src/netops.c +1 -1
- data/vendor/libgit2/src/netops.h +1 -1
- data/vendor/libgit2/src/notes.c +20 -29
- data/vendor/libgit2/src/object.c +49 -9
- data/vendor/libgit2/src/object.h +1 -1
- data/vendor/libgit2/src/odb.c +35 -32
- data/vendor/libgit2/src/odb.h +1 -1
- data/vendor/libgit2/src/odb_loose.c +68 -68
- data/vendor/libgit2/src/odb_mempack.c +18 -5
- data/vendor/libgit2/src/odb_pack.c +43 -43
- data/vendor/libgit2/src/oid.c +11 -4
- data/vendor/libgit2/src/oid.h +15 -0
- data/vendor/libgit2/src/pack-objects.c +41 -26
- data/vendor/libgit2/src/pack-objects.h +11 -6
- data/vendor/libgit2/src/pack.c +10 -10
- data/vendor/libgit2/src/patch.c +3 -3
- data/vendor/libgit2/src/patch.h +1 -0
- data/vendor/libgit2/src/patch_generate.c +27 -11
- data/vendor/libgit2/src/patch_generate.h +5 -5
- data/vendor/libgit2/src/patch_parse.c +24 -24
- data/vendor/libgit2/src/path.c +76 -1951
- data/vendor/libgit2/src/path.h +34 -741
- data/vendor/libgit2/src/pathspec.c +6 -6
- data/vendor/libgit2/src/pathspec.h +2 -2
- data/vendor/libgit2/src/posix.c +3 -3
- data/vendor/libgit2/src/posix.h +1 -0
- data/vendor/libgit2/src/pqueue.h +1 -1
- data/vendor/libgit2/src/proxy.c +4 -1
- data/vendor/libgit2/src/proxy.h +1 -1
- data/vendor/libgit2/src/push.c +30 -35
- data/vendor/libgit2/src/push.h +4 -16
- data/vendor/libgit2/src/rand.c +226 -0
- data/vendor/libgit2/src/rand.h +37 -0
- data/vendor/libgit2/src/reader.c +8 -8
- data/vendor/libgit2/src/reader.h +2 -2
- data/vendor/libgit2/src/rebase.c +89 -88
- data/vendor/libgit2/src/refdb_fs.c +447 -173
- data/vendor/libgit2/src/refs.c +32 -32
- data/vendor/libgit2/src/refs.h +2 -2
- data/vendor/libgit2/src/refspec.c +32 -37
- data/vendor/libgit2/src/refspec.h +5 -2
- data/vendor/libgit2/src/regexp.c +1 -1
- data/vendor/libgit2/src/remote.c +713 -419
- data/vendor/libgit2/src/remote.h +15 -10
- data/vendor/libgit2/src/repository.c +350 -467
- data/vendor/libgit2/src/repository.h +11 -10
- data/vendor/libgit2/src/reset.c +8 -5
- data/vendor/libgit2/src/revert.c +10 -10
- data/vendor/libgit2/src/revparse.c +48 -35
- data/vendor/libgit2/src/revwalk.c +7 -7
- data/vendor/libgit2/src/signature.c +12 -6
- data/vendor/libgit2/src/signature.h +1 -1
- data/vendor/libgit2/src/sortedcache.c +1 -1
- data/vendor/libgit2/src/sortedcache.h +1 -1
- data/vendor/libgit2/src/stash.c +36 -37
- data/vendor/libgit2/src/status.c +4 -1
- data/vendor/libgit2/src/{buffer.c → str.c} +157 -151
- data/vendor/libgit2/src/str.h +357 -0
- data/vendor/libgit2/src/streams/mbedtls.c +8 -6
- data/vendor/libgit2/src/streams/openssl_dynamic.h +3 -3
- data/vendor/libgit2/src/submodule.c +171 -159
- data/vendor/libgit2/src/submodule.h +1 -1
- data/vendor/libgit2/src/sysdir.c +68 -52
- data/vendor/libgit2/src/sysdir.h +15 -10
- data/vendor/libgit2/src/tag.c +29 -27
- data/vendor/libgit2/src/thread.h +3 -3
- data/vendor/libgit2/src/threadstate.c +3 -3
- data/vendor/libgit2/src/threadstate.h +1 -1
- data/vendor/libgit2/src/trace.c +1 -14
- data/vendor/libgit2/src/trace.h +5 -22
- data/vendor/libgit2/src/trailer.c +1 -1
- data/vendor/libgit2/src/transaction.c +1 -1
- data/vendor/libgit2/src/transport.c +10 -10
- data/vendor/libgit2/src/transports/auth.c +7 -9
- data/vendor/libgit2/src/transports/auth.h +2 -3
- data/vendor/libgit2/src/transports/auth_negotiate.c +12 -13
- data/vendor/libgit2/src/transports/auth_ntlm.c +10 -10
- data/vendor/libgit2/src/transports/auth_ntlm.h +0 -1
- data/vendor/libgit2/src/transports/git.c +9 -11
- data/vendor/libgit2/src/transports/http.c +37 -17
- data/vendor/libgit2/src/transports/http.h +2 -3
- data/vendor/libgit2/src/transports/httpclient.c +65 -65
- data/vendor/libgit2/src/transports/local.c +124 -116
- data/vendor/libgit2/src/transports/smart.c +51 -139
- data/vendor/libgit2/src/transports/smart.h +25 -31
- data/vendor/libgit2/src/transports/smart_pkt.c +33 -33
- data/vendor/libgit2/src/transports/smart_protocol.c +57 -39
- data/vendor/libgit2/src/transports/ssh.c +47 -112
- data/vendor/libgit2/src/transports/winhttp.c +50 -56
- data/vendor/libgit2/src/tree-cache.c +5 -5
- data/vendor/libgit2/src/tree-cache.h +2 -2
- data/vendor/libgit2/src/tree.c +59 -48
- data/vendor/libgit2/src/tree.h +1 -1
- data/vendor/libgit2/src/unix/map.c +0 -2
- data/vendor/libgit2/src/unix/posix.h +1 -4
- data/vendor/libgit2/src/unix/realpath.c +0 -2
- data/vendor/libgit2/src/util.c +14 -14
- data/vendor/libgit2/src/util.h +2 -28
- data/vendor/libgit2/src/vector.h +1 -1
- data/vendor/libgit2/src/win32/findfile.c +172 -116
- data/vendor/libgit2/src/win32/findfile.h +7 -4
- data/vendor/libgit2/src/win32/path_w32.c +140 -9
- data/vendor/libgit2/src/win32/path_w32.h +2 -0
- data/vendor/libgit2/src/win32/posix.h +0 -1
- data/vendor/libgit2/src/win32/posix_w32.c +11 -27
- data/vendor/libgit2/src/win32/w32_buffer.c +2 -3
- data/vendor/libgit2/src/win32/w32_buffer.h +2 -3
- data/vendor/libgit2/src/win32/w32_leakcheck.c +1 -1
- data/vendor/libgit2/src/worktree.c +116 -94
- data/vendor/libgit2/src/worktree.h +1 -1
- data/vendor/libgit2/src/xdiff/git-xdiff.h +53 -0
- data/vendor/libgit2/src/xdiff/xdiff.h +15 -15
- data/vendor/libgit2/src/xdiff/xdiffi.c +134 -108
- data/vendor/libgit2/src/xdiff/xemit.c +23 -7
- data/vendor/libgit2/src/xdiff/xhistogram.c +87 -78
- data/vendor/libgit2/src/xdiff/xinclude.h +1 -12
- data/vendor/libgit2/src/xdiff/xmerge.c +104 -117
- data/vendor/libgit2/src/xdiff/xpatience.c +6 -17
- data/vendor/libgit2/src/xdiff/xprepare.c +15 -20
- data/vendor/libgit2/src/xdiff/xutils.c +18 -7
- data/vendor/libgit2/src/zstream.c +5 -5
- data/vendor/libgit2/src/zstream.h +4 -4
- metadata +25 -10
- data/vendor/libgit2/src/buffer.h +0 -374
data/vendor/libgit2/src/path.c
CHANGED
|
@@ -7,1555 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
#include "path.h"
|
|
9
9
|
|
|
10
|
-
#include "posix.h"
|
|
11
10
|
#include "repository.h"
|
|
12
|
-
#
|
|
13
|
-
#include "win32/posix.h"
|
|
14
|
-
#include "win32/w32_buffer.h"
|
|
15
|
-
#include "win32/w32_util.h"
|
|
16
|
-
#include "win32/version.h"
|
|
17
|
-
#include <aclapi.h>
|
|
18
|
-
#else
|
|
19
|
-
#include <dirent.h>
|
|
20
|
-
#endif
|
|
21
|
-
#include <stdio.h>
|
|
22
|
-
#include <ctype.h>
|
|
23
|
-
|
|
24
|
-
static int dos_drive_prefix_length(const char *path)
|
|
25
|
-
{
|
|
26
|
-
int i;
|
|
27
|
-
|
|
28
|
-
/*
|
|
29
|
-
* Does it start with an ASCII letter (i.e. highest bit not set),
|
|
30
|
-
* followed by a colon?
|
|
31
|
-
*/
|
|
32
|
-
if (!(0x80 & (unsigned char)*path))
|
|
33
|
-
return *path && path[1] == ':' ? 2 : 0;
|
|
34
|
-
|
|
35
|
-
/*
|
|
36
|
-
* While drive letters must be letters of the English alphabet, it is
|
|
37
|
-
* possible to assign virtually _any_ Unicode character via `subst` as
|
|
38
|
-
* a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff
|
|
39
|
-
* like this:
|
|
40
|
-
*
|
|
41
|
-
* subst ֍: %USERPROFILE%\Desktop
|
|
42
|
-
*/
|
|
43
|
-
for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++)
|
|
44
|
-
; /* skip first UTF-8 character */
|
|
45
|
-
return path[i] == ':' ? i + 1 : 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
#ifdef GIT_WIN32
|
|
49
|
-
static bool looks_like_network_computer_name(const char *path, int pos)
|
|
50
|
-
{
|
|
51
|
-
if (pos < 3)
|
|
52
|
-
return false;
|
|
53
|
-
|
|
54
|
-
if (path[0] != '/' || path[1] != '/')
|
|
55
|
-
return false;
|
|
56
|
-
|
|
57
|
-
while (pos-- > 2) {
|
|
58
|
-
if (path[pos] == '/')
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
#endif
|
|
65
|
-
|
|
66
|
-
/*
|
|
67
|
-
* Based on the Android implementation, BSD licensed.
|
|
68
|
-
* http://android.git.kernel.org/
|
|
69
|
-
*
|
|
70
|
-
* Copyright (C) 2008 The Android Open Source Project
|
|
71
|
-
* All rights reserved.
|
|
72
|
-
*
|
|
73
|
-
* Redistribution and use in source and binary forms, with or without
|
|
74
|
-
* modification, are permitted provided that the following conditions
|
|
75
|
-
* are met:
|
|
76
|
-
* * Redistributions of source code must retain the above copyright
|
|
77
|
-
* notice, this list of conditions and the following disclaimer.
|
|
78
|
-
* * Redistributions in binary form must reproduce the above copyright
|
|
79
|
-
* notice, this list of conditions and the following disclaimer in
|
|
80
|
-
* the documentation and/or other materials provided with the
|
|
81
|
-
* distribution.
|
|
82
|
-
*
|
|
83
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
84
|
-
* AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
85
|
-
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
86
|
-
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
87
|
-
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
88
|
-
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
89
|
-
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
90
|
-
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
91
|
-
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
92
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
93
|
-
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
94
|
-
* SUCH DAMAGE.
|
|
95
|
-
*/
|
|
96
|
-
int git_path_basename_r(git_buf *buffer, const char *path)
|
|
97
|
-
{
|
|
98
|
-
const char *endp, *startp;
|
|
99
|
-
int len, result;
|
|
100
|
-
|
|
101
|
-
/* Empty or NULL string gets treated as "." */
|
|
102
|
-
if (path == NULL || *path == '\0') {
|
|
103
|
-
startp = ".";
|
|
104
|
-
len = 1;
|
|
105
|
-
goto Exit;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/* Strip trailing slashes */
|
|
109
|
-
endp = path + strlen(path) - 1;
|
|
110
|
-
while (endp > path && *endp == '/')
|
|
111
|
-
endp--;
|
|
112
|
-
|
|
113
|
-
/* All slashes becomes "/" */
|
|
114
|
-
if (endp == path && *endp == '/') {
|
|
115
|
-
startp = "/";
|
|
116
|
-
len = 1;
|
|
117
|
-
goto Exit;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/* Find the start of the base */
|
|
121
|
-
startp = endp;
|
|
122
|
-
while (startp > path && *(startp - 1) != '/')
|
|
123
|
-
startp--;
|
|
124
|
-
|
|
125
|
-
/* Cast is safe because max path < max int */
|
|
126
|
-
len = (int)(endp - startp + 1);
|
|
127
|
-
|
|
128
|
-
Exit:
|
|
129
|
-
result = len;
|
|
130
|
-
|
|
131
|
-
if (buffer != NULL && git_buf_set(buffer, startp, len) < 0)
|
|
132
|
-
return -1;
|
|
133
|
-
|
|
134
|
-
return result;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/*
|
|
138
|
-
* Determine if the path is a Windows prefix and, if so, returns
|
|
139
|
-
* its actual lentgh. If it is not a prefix, returns -1.
|
|
140
|
-
*/
|
|
141
|
-
static int win32_prefix_length(const char *path, int len)
|
|
142
|
-
{
|
|
143
|
-
#ifndef GIT_WIN32
|
|
144
|
-
GIT_UNUSED(path);
|
|
145
|
-
GIT_UNUSED(len);
|
|
146
|
-
#else
|
|
147
|
-
/*
|
|
148
|
-
* Mimic unix behavior where '/.git' returns '/': 'C:/.git'
|
|
149
|
-
* will return 'C:/' here
|
|
150
|
-
*/
|
|
151
|
-
if (dos_drive_prefix_length(path) == len)
|
|
152
|
-
return len;
|
|
153
|
-
|
|
154
|
-
/*
|
|
155
|
-
* Similarly checks if we're dealing with a network computer name
|
|
156
|
-
* '//computername/.git' will return '//computername/'
|
|
157
|
-
*/
|
|
158
|
-
if (looks_like_network_computer_name(path, len))
|
|
159
|
-
return len;
|
|
160
|
-
#endif
|
|
161
|
-
|
|
162
|
-
return -1;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/*
|
|
166
|
-
* Based on the Android implementation, BSD licensed.
|
|
167
|
-
* Check http://android.git.kernel.org/
|
|
168
|
-
*/
|
|
169
|
-
int git_path_dirname_r(git_buf *buffer, const char *path)
|
|
170
|
-
{
|
|
171
|
-
const char *endp;
|
|
172
|
-
int is_prefix = 0, len;
|
|
173
|
-
|
|
174
|
-
/* Empty or NULL string gets treated as "." */
|
|
175
|
-
if (path == NULL || *path == '\0') {
|
|
176
|
-
path = ".";
|
|
177
|
-
len = 1;
|
|
178
|
-
goto Exit;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/* Strip trailing slashes */
|
|
182
|
-
endp = path + strlen(path) - 1;
|
|
183
|
-
while (endp > path && *endp == '/')
|
|
184
|
-
endp--;
|
|
185
|
-
|
|
186
|
-
if (endp - path + 1 > INT_MAX) {
|
|
187
|
-
git_error_set(GIT_ERROR_INVALID, "path too long");
|
|
188
|
-
len = -1;
|
|
189
|
-
goto Exit;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) {
|
|
193
|
-
is_prefix = 1;
|
|
194
|
-
goto Exit;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/* Find the start of the dir */
|
|
198
|
-
while (endp > path && *endp != '/')
|
|
199
|
-
endp--;
|
|
200
|
-
|
|
201
|
-
/* Either the dir is "/" or there are no slashes */
|
|
202
|
-
if (endp == path) {
|
|
203
|
-
path = (*endp == '/') ? "/" : ".";
|
|
204
|
-
len = 1;
|
|
205
|
-
goto Exit;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
do {
|
|
209
|
-
endp--;
|
|
210
|
-
} while (endp > path && *endp == '/');
|
|
211
|
-
|
|
212
|
-
if (endp - path + 1 > INT_MAX) {
|
|
213
|
-
git_error_set(GIT_ERROR_INVALID, "path too long");
|
|
214
|
-
len = -1;
|
|
215
|
-
goto Exit;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) {
|
|
219
|
-
is_prefix = 1;
|
|
220
|
-
goto Exit;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/* Cast is safe because max path < max int */
|
|
224
|
-
len = (int)(endp - path + 1);
|
|
225
|
-
|
|
226
|
-
Exit:
|
|
227
|
-
if (buffer) {
|
|
228
|
-
if (git_buf_set(buffer, path, len) < 0)
|
|
229
|
-
return -1;
|
|
230
|
-
if (is_prefix && git_buf_putc(buffer, '/') < 0)
|
|
231
|
-
return -1;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return len;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
char *git_path_dirname(const char *path)
|
|
239
|
-
{
|
|
240
|
-
git_buf buf = GIT_BUF_INIT;
|
|
241
|
-
char *dirname;
|
|
242
|
-
|
|
243
|
-
git_path_dirname_r(&buf, path);
|
|
244
|
-
dirname = git_buf_detach(&buf);
|
|
245
|
-
git_buf_dispose(&buf); /* avoid memleak if error occurs */
|
|
246
|
-
|
|
247
|
-
return dirname;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
char *git_path_basename(const char *path)
|
|
251
|
-
{
|
|
252
|
-
git_buf buf = GIT_BUF_INIT;
|
|
253
|
-
char *basename;
|
|
254
|
-
|
|
255
|
-
git_path_basename_r(&buf, path);
|
|
256
|
-
basename = git_buf_detach(&buf);
|
|
257
|
-
git_buf_dispose(&buf); /* avoid memleak if error occurs */
|
|
258
|
-
|
|
259
|
-
return basename;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
size_t git_path_basename_offset(git_buf *buffer)
|
|
263
|
-
{
|
|
264
|
-
ssize_t slash;
|
|
265
|
-
|
|
266
|
-
if (!buffer || buffer->size <= 0)
|
|
267
|
-
return 0;
|
|
268
|
-
|
|
269
|
-
slash = git_buf_rfind_next(buffer, '/');
|
|
270
|
-
|
|
271
|
-
if (slash >= 0 && buffer->ptr[slash] == '/')
|
|
272
|
-
return (size_t)(slash + 1);
|
|
273
|
-
|
|
274
|
-
return 0;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
int git_path_root(const char *path)
|
|
278
|
-
{
|
|
279
|
-
int offset = 0, prefix_len;
|
|
280
|
-
|
|
281
|
-
/* Does the root of the path look like a windows drive ? */
|
|
282
|
-
if ((prefix_len = dos_drive_prefix_length(path)))
|
|
283
|
-
offset += prefix_len;
|
|
284
|
-
|
|
285
|
-
#ifdef GIT_WIN32
|
|
286
|
-
/* Are we dealing with a windows network path? */
|
|
287
|
-
else if ((path[0] == '/' && path[1] == '/' && path[2] != '/') ||
|
|
288
|
-
(path[0] == '\\' && path[1] == '\\' && path[2] != '\\'))
|
|
289
|
-
{
|
|
290
|
-
offset += 2;
|
|
291
|
-
|
|
292
|
-
/* Skip the computer name segment */
|
|
293
|
-
while (path[offset] && path[offset] != '/' && path[offset] != '\\')
|
|
294
|
-
offset++;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (path[offset] == '\\')
|
|
298
|
-
return offset;
|
|
299
|
-
#endif
|
|
300
|
-
|
|
301
|
-
if (path[offset] == '/')
|
|
302
|
-
return offset;
|
|
303
|
-
|
|
304
|
-
return -1; /* Not a real error - signals that path is not rooted */
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
static void path_trim_slashes(git_buf *path)
|
|
308
|
-
{
|
|
309
|
-
int ceiling = git_path_root(path->ptr) + 1;
|
|
310
|
-
|
|
311
|
-
if (ceiling < 0)
|
|
312
|
-
return;
|
|
313
|
-
|
|
314
|
-
while (path->size > (size_t)ceiling) {
|
|
315
|
-
if (path->ptr[path->size-1] != '/')
|
|
316
|
-
break;
|
|
317
|
-
|
|
318
|
-
path->ptr[path->size-1] = '\0';
|
|
319
|
-
path->size--;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
int git_path_join_unrooted(
|
|
324
|
-
git_buf *path_out, const char *path, const char *base, ssize_t *root_at)
|
|
325
|
-
{
|
|
326
|
-
ssize_t root;
|
|
327
|
-
|
|
328
|
-
GIT_ASSERT_ARG(path_out);
|
|
329
|
-
GIT_ASSERT_ARG(path);
|
|
330
|
-
|
|
331
|
-
root = (ssize_t)git_path_root(path);
|
|
332
|
-
|
|
333
|
-
if (base != NULL && root < 0) {
|
|
334
|
-
if (git_buf_joinpath(path_out, base, path) < 0)
|
|
335
|
-
return -1;
|
|
336
|
-
|
|
337
|
-
root = (ssize_t)strlen(base);
|
|
338
|
-
} else {
|
|
339
|
-
if (git_buf_sets(path_out, path) < 0)
|
|
340
|
-
return -1;
|
|
341
|
-
|
|
342
|
-
if (root < 0)
|
|
343
|
-
root = 0;
|
|
344
|
-
else if (base)
|
|
345
|
-
git_path_equal_or_prefixed(base, path, &root);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (root_at)
|
|
349
|
-
*root_at = root;
|
|
350
|
-
|
|
351
|
-
return 0;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
void git_path_squash_slashes(git_buf *path)
|
|
355
|
-
{
|
|
356
|
-
char *p, *q;
|
|
357
|
-
|
|
358
|
-
if (path->size == 0)
|
|
359
|
-
return;
|
|
360
|
-
|
|
361
|
-
for (p = path->ptr, q = path->ptr; *q; p++, q++) {
|
|
362
|
-
*p = *q;
|
|
363
|
-
|
|
364
|
-
while (*q == '/' && *(q+1) == '/') {
|
|
365
|
-
path->size--;
|
|
366
|
-
q++;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
*p = '\0';
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
int git_path_prettify(git_buf *path_out, const char *path, const char *base)
|
|
374
|
-
{
|
|
375
|
-
char buf[GIT_PATH_MAX];
|
|
376
|
-
|
|
377
|
-
GIT_ASSERT_ARG(path_out);
|
|
378
|
-
GIT_ASSERT_ARG(path);
|
|
379
|
-
|
|
380
|
-
/* construct path if needed */
|
|
381
|
-
if (base != NULL && git_path_root(path) < 0) {
|
|
382
|
-
if (git_buf_joinpath(path_out, base, path) < 0)
|
|
383
|
-
return -1;
|
|
384
|
-
path = path_out->ptr;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (p_realpath(path, buf) == NULL) {
|
|
388
|
-
/* git_error_set resets the errno when dealing with a GIT_ERROR_OS kind of error */
|
|
389
|
-
int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1;
|
|
390
|
-
git_error_set(GIT_ERROR_OS, "failed to resolve path '%s'", path);
|
|
391
|
-
|
|
392
|
-
git_buf_clear(path_out);
|
|
393
|
-
|
|
394
|
-
return error;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return git_buf_sets(path_out, buf);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base)
|
|
401
|
-
{
|
|
402
|
-
int error = git_path_prettify(path_out, path, base);
|
|
403
|
-
return (error < 0) ? error : git_path_to_dir(path_out);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
int git_path_to_dir(git_buf *path)
|
|
407
|
-
{
|
|
408
|
-
if (path->asize > 0 &&
|
|
409
|
-
git_buf_len(path) > 0 &&
|
|
410
|
-
path->ptr[git_buf_len(path) - 1] != '/')
|
|
411
|
-
git_buf_putc(path, '/');
|
|
412
|
-
|
|
413
|
-
return git_buf_oom(path) ? -1 : 0;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
void git_path_string_to_dir(char *path, size_t size)
|
|
417
|
-
{
|
|
418
|
-
size_t end = strlen(path);
|
|
419
|
-
|
|
420
|
-
if (end && path[end - 1] != '/' && end < size) {
|
|
421
|
-
path[end] = '/';
|
|
422
|
-
path[end + 1] = '\0';
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
int git__percent_decode(git_buf *decoded_out, const char *input)
|
|
427
|
-
{
|
|
428
|
-
int len, hi, lo, i;
|
|
429
|
-
|
|
430
|
-
GIT_ASSERT_ARG(decoded_out);
|
|
431
|
-
GIT_ASSERT_ARG(input);
|
|
432
|
-
|
|
433
|
-
len = (int)strlen(input);
|
|
434
|
-
git_buf_clear(decoded_out);
|
|
435
|
-
|
|
436
|
-
for(i = 0; i < len; i++)
|
|
437
|
-
{
|
|
438
|
-
char c = input[i];
|
|
439
|
-
|
|
440
|
-
if (c != '%')
|
|
441
|
-
goto append;
|
|
442
|
-
|
|
443
|
-
if (i >= len - 2)
|
|
444
|
-
goto append;
|
|
445
|
-
|
|
446
|
-
hi = git__fromhex(input[i + 1]);
|
|
447
|
-
lo = git__fromhex(input[i + 2]);
|
|
448
|
-
|
|
449
|
-
if (hi < 0 || lo < 0)
|
|
450
|
-
goto append;
|
|
451
|
-
|
|
452
|
-
c = (char)(hi << 4 | lo);
|
|
453
|
-
i += 2;
|
|
454
|
-
|
|
455
|
-
append:
|
|
456
|
-
if (git_buf_putc(decoded_out, c) < 0)
|
|
457
|
-
return -1;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
return 0;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
static int error_invalid_local_file_uri(const char *uri)
|
|
464
|
-
{
|
|
465
|
-
git_error_set(GIT_ERROR_CONFIG, "'%s' is not a valid local file URI", uri);
|
|
466
|
-
return -1;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
static int local_file_url_prefixlen(const char *file_url)
|
|
470
|
-
{
|
|
471
|
-
int len = -1;
|
|
472
|
-
|
|
473
|
-
if (git__prefixcmp(file_url, "file://") == 0) {
|
|
474
|
-
if (file_url[7] == '/')
|
|
475
|
-
len = 8;
|
|
476
|
-
else if (git__prefixcmp(file_url + 7, "localhost/") == 0)
|
|
477
|
-
len = 17;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return len;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
bool git_path_is_local_file_url(const char *file_url)
|
|
484
|
-
{
|
|
485
|
-
return (local_file_url_prefixlen(file_url) > 0);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
int git_path_fromurl(git_buf *local_path_out, const char *file_url)
|
|
489
|
-
{
|
|
490
|
-
int offset;
|
|
491
|
-
|
|
492
|
-
GIT_ASSERT_ARG(local_path_out);
|
|
493
|
-
GIT_ASSERT_ARG(file_url);
|
|
494
|
-
|
|
495
|
-
if ((offset = local_file_url_prefixlen(file_url)) < 0 ||
|
|
496
|
-
file_url[offset] == '\0' || file_url[offset] == '/')
|
|
497
|
-
return error_invalid_local_file_uri(file_url);
|
|
498
|
-
|
|
499
|
-
#ifndef GIT_WIN32
|
|
500
|
-
offset--; /* A *nix absolute path starts with a forward slash */
|
|
501
|
-
#endif
|
|
502
|
-
|
|
503
|
-
git_buf_clear(local_path_out);
|
|
504
|
-
return git__percent_decode(local_path_out, file_url + offset);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
int git_path_walk_up(
|
|
508
|
-
git_buf *path,
|
|
509
|
-
const char *ceiling,
|
|
510
|
-
int (*cb)(void *data, const char *),
|
|
511
|
-
void *data)
|
|
512
|
-
{
|
|
513
|
-
int error = 0;
|
|
514
|
-
git_buf iter;
|
|
515
|
-
ssize_t stop = 0, scan;
|
|
516
|
-
char oldc = '\0';
|
|
517
|
-
|
|
518
|
-
GIT_ASSERT_ARG(path);
|
|
519
|
-
GIT_ASSERT_ARG(cb);
|
|
520
|
-
|
|
521
|
-
if (ceiling != NULL) {
|
|
522
|
-
if (git__prefixcmp(path->ptr, ceiling) == 0)
|
|
523
|
-
stop = (ssize_t)strlen(ceiling);
|
|
524
|
-
else
|
|
525
|
-
stop = git_buf_len(path);
|
|
526
|
-
}
|
|
527
|
-
scan = git_buf_len(path);
|
|
528
|
-
|
|
529
|
-
/* empty path: yield only once */
|
|
530
|
-
if (!scan) {
|
|
531
|
-
error = cb(data, "");
|
|
532
|
-
if (error)
|
|
533
|
-
git_error_set_after_callback(error);
|
|
534
|
-
return error;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
iter.ptr = path->ptr;
|
|
538
|
-
iter.size = git_buf_len(path);
|
|
539
|
-
iter.asize = path->asize;
|
|
540
|
-
|
|
541
|
-
while (scan >= stop) {
|
|
542
|
-
error = cb(data, iter.ptr);
|
|
543
|
-
iter.ptr[scan] = oldc;
|
|
544
|
-
|
|
545
|
-
if (error) {
|
|
546
|
-
git_error_set_after_callback(error);
|
|
547
|
-
break;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
scan = git_buf_rfind_next(&iter, '/');
|
|
551
|
-
if (scan >= 0) {
|
|
552
|
-
scan++;
|
|
553
|
-
oldc = iter.ptr[scan];
|
|
554
|
-
iter.size = scan;
|
|
555
|
-
iter.ptr[scan] = '\0';
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
if (scan >= 0)
|
|
560
|
-
iter.ptr[scan] = oldc;
|
|
561
|
-
|
|
562
|
-
/* relative path: yield for the last component */
|
|
563
|
-
if (!error && stop == 0 && iter.ptr[0] != '/') {
|
|
564
|
-
error = cb(data, "");
|
|
565
|
-
if (error)
|
|
566
|
-
git_error_set_after_callback(error);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return error;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
bool git_path_exists(const char *path)
|
|
573
|
-
{
|
|
574
|
-
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
|
|
575
|
-
return p_access(path, F_OK) == 0;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
bool git_path_isdir(const char *path)
|
|
579
|
-
{
|
|
580
|
-
struct stat st;
|
|
581
|
-
if (p_stat(path, &st) < 0)
|
|
582
|
-
return false;
|
|
583
|
-
|
|
584
|
-
return S_ISDIR(st.st_mode) != 0;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
bool git_path_isfile(const char *path)
|
|
588
|
-
{
|
|
589
|
-
struct stat st;
|
|
590
|
-
|
|
591
|
-
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
|
|
592
|
-
if (p_stat(path, &st) < 0)
|
|
593
|
-
return false;
|
|
594
|
-
|
|
595
|
-
return S_ISREG(st.st_mode) != 0;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
bool git_path_islink(const char *path)
|
|
599
|
-
{
|
|
600
|
-
struct stat st;
|
|
601
|
-
|
|
602
|
-
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
|
|
603
|
-
if (p_lstat(path, &st) < 0)
|
|
604
|
-
return false;
|
|
605
|
-
|
|
606
|
-
return S_ISLNK(st.st_mode) != 0;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
#ifdef GIT_WIN32
|
|
610
|
-
|
|
611
|
-
bool git_path_is_empty_dir(const char *path)
|
|
612
|
-
{
|
|
613
|
-
git_win32_path filter_w;
|
|
614
|
-
bool empty = false;
|
|
615
|
-
|
|
616
|
-
if (git_win32__findfirstfile_filter(filter_w, path)) {
|
|
617
|
-
WIN32_FIND_DATAW findData;
|
|
618
|
-
HANDLE hFind = FindFirstFileW(filter_w, &findData);
|
|
619
|
-
|
|
620
|
-
/* FindFirstFile will fail if there are no children to the given
|
|
621
|
-
* path, which can happen if the given path is a file (and obviously
|
|
622
|
-
* has no children) or if the given path is an empty mount point.
|
|
623
|
-
* (Most directories have at least directory entries '.' and '..',
|
|
624
|
-
* but ridiculously another volume mounted in another drive letter's
|
|
625
|
-
* path space do not, and thus have nothing to enumerate.) If
|
|
626
|
-
* FindFirstFile fails, check if this is a directory-like thing
|
|
627
|
-
* (a mount point).
|
|
628
|
-
*/
|
|
629
|
-
if (hFind == INVALID_HANDLE_VALUE)
|
|
630
|
-
return git_path_isdir(path);
|
|
631
|
-
|
|
632
|
-
/* If the find handle was created successfully, then it's a directory */
|
|
633
|
-
empty = true;
|
|
634
|
-
|
|
635
|
-
do {
|
|
636
|
-
/* Allow the enumeration to return . and .. and still be considered
|
|
637
|
-
* empty. In the special case of drive roots (i.e. C:\) where . and
|
|
638
|
-
* .. do not occur, we can still consider the path to be an empty
|
|
639
|
-
* directory if there's nothing there. */
|
|
640
|
-
if (!git_path_is_dot_or_dotdotW(findData.cFileName)) {
|
|
641
|
-
empty = false;
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
644
|
-
} while (FindNextFileW(hFind, &findData));
|
|
645
|
-
|
|
646
|
-
FindClose(hFind);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
return empty;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
#else
|
|
653
|
-
|
|
654
|
-
static int path_found_entry(void *payload, git_buf *path)
|
|
655
|
-
{
|
|
656
|
-
GIT_UNUSED(payload);
|
|
657
|
-
return !git_path_is_dot_or_dotdot(path->ptr);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
bool git_path_is_empty_dir(const char *path)
|
|
661
|
-
{
|
|
662
|
-
int error;
|
|
663
|
-
git_buf dir = GIT_BUF_INIT;
|
|
664
|
-
|
|
665
|
-
if (!git_path_isdir(path))
|
|
666
|
-
return false;
|
|
667
|
-
|
|
668
|
-
if ((error = git_buf_sets(&dir, path)) != 0)
|
|
669
|
-
git_error_clear();
|
|
670
|
-
else
|
|
671
|
-
error = git_path_direach(&dir, 0, path_found_entry, NULL);
|
|
672
|
-
|
|
673
|
-
git_buf_dispose(&dir);
|
|
674
|
-
|
|
675
|
-
return !error;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
#endif
|
|
679
|
-
|
|
680
|
-
int git_path_set_error(int errno_value, const char *path, const char *action)
|
|
681
|
-
{
|
|
682
|
-
switch (errno_value) {
|
|
683
|
-
case ENOENT:
|
|
684
|
-
case ENOTDIR:
|
|
685
|
-
git_error_set(GIT_ERROR_OS, "could not find '%s' to %s", path, action);
|
|
686
|
-
return GIT_ENOTFOUND;
|
|
687
|
-
|
|
688
|
-
case EINVAL:
|
|
689
|
-
case ENAMETOOLONG:
|
|
690
|
-
git_error_set(GIT_ERROR_OS, "invalid path for filesystem '%s'", path);
|
|
691
|
-
return GIT_EINVALIDSPEC;
|
|
692
|
-
|
|
693
|
-
case EEXIST:
|
|
694
|
-
git_error_set(GIT_ERROR_OS, "failed %s - '%s' already exists", action, path);
|
|
695
|
-
return GIT_EEXISTS;
|
|
696
|
-
|
|
697
|
-
case EACCES:
|
|
698
|
-
git_error_set(GIT_ERROR_OS, "failed %s - '%s' is locked", action, path);
|
|
699
|
-
return GIT_ELOCKED;
|
|
700
|
-
|
|
701
|
-
default:
|
|
702
|
-
git_error_set(GIT_ERROR_OS, "could not %s '%s'", action, path);
|
|
703
|
-
return -1;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
int git_path_lstat(const char *path, struct stat *st)
|
|
708
|
-
{
|
|
709
|
-
if (p_lstat(path, st) == 0)
|
|
710
|
-
return 0;
|
|
711
|
-
|
|
712
|
-
return git_path_set_error(errno, path, "stat");
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
static bool _check_dir_contents(
|
|
716
|
-
git_buf *dir,
|
|
717
|
-
const char *sub,
|
|
718
|
-
bool (*predicate)(const char *))
|
|
719
|
-
{
|
|
720
|
-
bool result;
|
|
721
|
-
size_t dir_size = git_buf_len(dir);
|
|
722
|
-
size_t sub_size = strlen(sub);
|
|
723
|
-
size_t alloc_size;
|
|
724
|
-
|
|
725
|
-
/* leave base valid even if we could not make space for subdir */
|
|
726
|
-
if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, dir_size, sub_size) ||
|
|
727
|
-
GIT_ADD_SIZET_OVERFLOW(&alloc_size, alloc_size, 2) ||
|
|
728
|
-
git_buf_try_grow(dir, alloc_size, false) < 0)
|
|
729
|
-
return false;
|
|
730
|
-
|
|
731
|
-
/* save excursion */
|
|
732
|
-
if (git_buf_joinpath(dir, dir->ptr, sub) < 0)
|
|
733
|
-
return false;
|
|
734
|
-
|
|
735
|
-
result = predicate(dir->ptr);
|
|
736
|
-
|
|
737
|
-
/* restore path */
|
|
738
|
-
git_buf_truncate(dir, dir_size);
|
|
739
|
-
return result;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
bool git_path_contains(git_buf *dir, const char *item)
|
|
743
|
-
{
|
|
744
|
-
return _check_dir_contents(dir, item, &git_path_exists);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
bool git_path_contains_dir(git_buf *base, const char *subdir)
|
|
748
|
-
{
|
|
749
|
-
return _check_dir_contents(base, subdir, &git_path_isdir);
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
bool git_path_contains_file(git_buf *base, const char *file)
|
|
753
|
-
{
|
|
754
|
-
return _check_dir_contents(base, file, &git_path_isfile);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
int git_path_find_dir(git_buf *dir)
|
|
758
|
-
{
|
|
759
|
-
int error = 0;
|
|
760
|
-
char buf[GIT_PATH_MAX];
|
|
761
|
-
|
|
762
|
-
if (p_realpath(dir->ptr, buf) != NULL)
|
|
763
|
-
error = git_buf_sets(dir, buf);
|
|
764
|
-
|
|
765
|
-
/* call dirname if this is not a directory */
|
|
766
|
-
if (!error) /* && git_path_isdir(dir->ptr) == false) */
|
|
767
|
-
error = (git_path_dirname_r(dir, dir->ptr) < 0) ? -1 : 0;
|
|
768
|
-
|
|
769
|
-
if (!error)
|
|
770
|
-
error = git_path_to_dir(dir);
|
|
771
|
-
|
|
772
|
-
return error;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
int git_path_resolve_relative(git_buf *path, size_t ceiling)
|
|
776
|
-
{
|
|
777
|
-
char *base, *to, *from, *next;
|
|
778
|
-
size_t len;
|
|
779
|
-
|
|
780
|
-
GIT_ERROR_CHECK_ALLOC_BUF(path);
|
|
781
|
-
|
|
782
|
-
if (ceiling > path->size)
|
|
783
|
-
ceiling = path->size;
|
|
784
|
-
|
|
785
|
-
/* recognize drive prefixes, etc. that should not be backed over */
|
|
786
|
-
if (ceiling == 0)
|
|
787
|
-
ceiling = git_path_root(path->ptr) + 1;
|
|
788
|
-
|
|
789
|
-
/* recognize URL prefixes that should not be backed over */
|
|
790
|
-
if (ceiling == 0) {
|
|
791
|
-
for (next = path->ptr; *next && git__isalpha(*next); ++next);
|
|
792
|
-
if (next[0] == ':' && next[1] == '/' && next[2] == '/')
|
|
793
|
-
ceiling = (next + 3) - path->ptr;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
base = to = from = path->ptr + ceiling;
|
|
797
|
-
|
|
798
|
-
while (*from) {
|
|
799
|
-
for (next = from; *next && *next != '/'; ++next);
|
|
800
|
-
|
|
801
|
-
len = next - from;
|
|
802
|
-
|
|
803
|
-
if (len == 1 && from[0] == '.')
|
|
804
|
-
/* do nothing with singleton dot */;
|
|
805
|
-
|
|
806
|
-
else if (len == 2 && from[0] == '.' && from[1] == '.') {
|
|
807
|
-
/* error out if trying to up one from a hard base */
|
|
808
|
-
if (to == base && ceiling != 0) {
|
|
809
|
-
git_error_set(GIT_ERROR_INVALID,
|
|
810
|
-
"cannot strip root component off url");
|
|
811
|
-
return -1;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
/* no more path segments to strip,
|
|
815
|
-
* use '../' as a new base path */
|
|
816
|
-
if (to == base) {
|
|
817
|
-
if (*next == '/')
|
|
818
|
-
len++;
|
|
819
|
-
|
|
820
|
-
if (to != from)
|
|
821
|
-
memmove(to, from, len);
|
|
822
|
-
|
|
823
|
-
to += len;
|
|
824
|
-
/* this is now the base, can't back up from a
|
|
825
|
-
* relative prefix */
|
|
826
|
-
base = to;
|
|
827
|
-
} else {
|
|
828
|
-
/* back up a path segment */
|
|
829
|
-
while (to > base && to[-1] == '/') to--;
|
|
830
|
-
while (to > base && to[-1] != '/') to--;
|
|
831
|
-
}
|
|
832
|
-
} else {
|
|
833
|
-
if (*next == '/' && *from != '/')
|
|
834
|
-
len++;
|
|
835
|
-
|
|
836
|
-
if (to != from)
|
|
837
|
-
memmove(to, from, len);
|
|
838
|
-
|
|
839
|
-
to += len;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
from += len;
|
|
843
|
-
|
|
844
|
-
while (*from == '/') from++;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
*to = '\0';
|
|
848
|
-
|
|
849
|
-
path->size = to - path->ptr;
|
|
850
|
-
|
|
851
|
-
return 0;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
int git_path_apply_relative(git_buf *target, const char *relpath)
|
|
855
|
-
{
|
|
856
|
-
return git_buf_joinpath(target, git_buf_cstr(target), relpath) ||
|
|
857
|
-
git_path_resolve_relative(target, 0);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
int git_path_cmp(
|
|
861
|
-
const char *name1, size_t len1, int isdir1,
|
|
862
|
-
const char *name2, size_t len2, int isdir2,
|
|
863
|
-
int (*compare)(const char *, const char *, size_t))
|
|
864
|
-
{
|
|
865
|
-
unsigned char c1, c2;
|
|
866
|
-
size_t len = len1 < len2 ? len1 : len2;
|
|
867
|
-
int cmp;
|
|
868
|
-
|
|
869
|
-
cmp = compare(name1, name2, len);
|
|
870
|
-
if (cmp)
|
|
871
|
-
return cmp;
|
|
872
|
-
|
|
873
|
-
c1 = name1[len];
|
|
874
|
-
c2 = name2[len];
|
|
875
|
-
|
|
876
|
-
if (c1 == '\0' && isdir1)
|
|
877
|
-
c1 = '/';
|
|
878
|
-
|
|
879
|
-
if (c2 == '\0' && isdir2)
|
|
880
|
-
c2 = '/';
|
|
881
|
-
|
|
882
|
-
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
size_t git_path_common_dirlen(const char *one, const char *two)
|
|
886
|
-
{
|
|
887
|
-
const char *p, *q, *dirsep = NULL;
|
|
888
|
-
|
|
889
|
-
for (p = one, q = two; *p && *q; p++, q++) {
|
|
890
|
-
if (*p == '/' && *q == '/')
|
|
891
|
-
dirsep = p;
|
|
892
|
-
else if (*p != *q)
|
|
893
|
-
break;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
return dirsep ? (dirsep - one) + 1 : 0;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
int git_path_make_relative(git_buf *path, const char *parent)
|
|
900
|
-
{
|
|
901
|
-
const char *p, *q, *p_dirsep, *q_dirsep;
|
|
902
|
-
size_t plen = path->size, newlen, alloclen, depth = 1, i, offset;
|
|
903
|
-
|
|
904
|
-
for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) {
|
|
905
|
-
if (*p == '/' && *q == '/') {
|
|
906
|
-
p_dirsep = p;
|
|
907
|
-
q_dirsep = q;
|
|
908
|
-
}
|
|
909
|
-
else if (*p != *q)
|
|
910
|
-
break;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
/* need at least 1 common path segment */
|
|
914
|
-
if ((p_dirsep == path->ptr || q_dirsep == parent) &&
|
|
915
|
-
(*p_dirsep != '/' || *q_dirsep != '/')) {
|
|
916
|
-
git_error_set(GIT_ERROR_INVALID,
|
|
917
|
-
"%s is not a parent of %s", parent, path->ptr);
|
|
918
|
-
return GIT_ENOTFOUND;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
if (*p == '/' && !*q)
|
|
922
|
-
p++;
|
|
923
|
-
else if (!*p && *q == '/')
|
|
924
|
-
q++;
|
|
925
|
-
else if (!*p && !*q)
|
|
926
|
-
return git_buf_clear(path), 0;
|
|
927
|
-
else {
|
|
928
|
-
p = p_dirsep + 1;
|
|
929
|
-
q = q_dirsep + 1;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
plen -= (p - path->ptr);
|
|
933
|
-
|
|
934
|
-
if (!*q)
|
|
935
|
-
return git_buf_set(path, p, plen);
|
|
936
|
-
|
|
937
|
-
for (; (q = strchr(q, '/')) && *(q + 1); q++)
|
|
938
|
-
depth++;
|
|
939
|
-
|
|
940
|
-
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newlen, depth, 3);
|
|
941
|
-
GIT_ERROR_CHECK_ALLOC_ADD(&newlen, newlen, plen);
|
|
942
|
-
|
|
943
|
-
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, newlen, 1);
|
|
944
|
-
|
|
945
|
-
/* save the offset as we might realllocate the pointer */
|
|
946
|
-
offset = p - path->ptr;
|
|
947
|
-
if (git_buf_try_grow(path, alloclen, 1) < 0)
|
|
948
|
-
return -1;
|
|
949
|
-
p = path->ptr + offset;
|
|
950
|
-
|
|
951
|
-
memmove(path->ptr + (depth * 3), p, plen + 1);
|
|
952
|
-
|
|
953
|
-
for (i = 0; i < depth; i++)
|
|
954
|
-
memcpy(path->ptr + (i * 3), "../", 3);
|
|
955
|
-
|
|
956
|
-
path->size = newlen;
|
|
957
|
-
return 0;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
bool git_path_has_non_ascii(const char *path, size_t pathlen)
|
|
961
|
-
{
|
|
962
|
-
const uint8_t *scan = (const uint8_t *)path, *end;
|
|
963
|
-
|
|
964
|
-
for (end = scan + pathlen; scan < end; ++scan)
|
|
965
|
-
if (*scan & 0x80)
|
|
966
|
-
return true;
|
|
967
|
-
|
|
968
|
-
return false;
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
#ifdef GIT_USE_ICONV
|
|
972
|
-
|
|
973
|
-
int git_path_iconv_init_precompose(git_path_iconv_t *ic)
|
|
974
|
-
{
|
|
975
|
-
git_buf_init(&ic->buf, 0);
|
|
976
|
-
ic->map = iconv_open(GIT_PATH_REPO_ENCODING, GIT_PATH_NATIVE_ENCODING);
|
|
977
|
-
return 0;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
void git_path_iconv_clear(git_path_iconv_t *ic)
|
|
981
|
-
{
|
|
982
|
-
if (ic) {
|
|
983
|
-
if (ic->map != (iconv_t)-1)
|
|
984
|
-
iconv_close(ic->map);
|
|
985
|
-
git_buf_dispose(&ic->buf);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen)
|
|
990
|
-
{
|
|
991
|
-
char *nfd = (char*)*in, *nfc;
|
|
992
|
-
size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, alloclen, rv;
|
|
993
|
-
int retry = 1;
|
|
994
|
-
|
|
995
|
-
if (!ic || ic->map == (iconv_t)-1 ||
|
|
996
|
-
!git_path_has_non_ascii(*in, *inlen))
|
|
997
|
-
return 0;
|
|
998
|
-
|
|
999
|
-
git_buf_clear(&ic->buf);
|
|
1000
|
-
|
|
1001
|
-
while (1) {
|
|
1002
|
-
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, wantlen, 1);
|
|
1003
|
-
if (git_buf_grow(&ic->buf, alloclen) < 0)
|
|
1004
|
-
return -1;
|
|
1005
|
-
|
|
1006
|
-
nfc = ic->buf.ptr + ic->buf.size;
|
|
1007
|
-
nfclen = ic->buf.asize - ic->buf.size;
|
|
1008
|
-
|
|
1009
|
-
rv = iconv(ic->map, &nfd, &nfdlen, &nfc, &nfclen);
|
|
1010
|
-
|
|
1011
|
-
ic->buf.size = (nfc - ic->buf.ptr);
|
|
1012
|
-
|
|
1013
|
-
if (rv != (size_t)-1)
|
|
1014
|
-
break;
|
|
1015
|
-
|
|
1016
|
-
/* if we cannot convert the data (probably because iconv thinks
|
|
1017
|
-
* it is not valid UTF-8 source data), then use original data
|
|
1018
|
-
*/
|
|
1019
|
-
if (errno != E2BIG)
|
|
1020
|
-
return 0;
|
|
1021
|
-
|
|
1022
|
-
/* make space for 2x the remaining data to be converted
|
|
1023
|
-
* (with per retry overhead to avoid infinite loops)
|
|
1024
|
-
*/
|
|
1025
|
-
wantlen = ic->buf.size + max(nfclen, nfdlen) * 2 + (size_t)(retry * 4);
|
|
1026
|
-
|
|
1027
|
-
if (retry++ > 4)
|
|
1028
|
-
goto fail;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
ic->buf.ptr[ic->buf.size] = '\0';
|
|
1032
|
-
|
|
1033
|
-
*in = ic->buf.ptr;
|
|
1034
|
-
*inlen = ic->buf.size;
|
|
1035
|
-
|
|
1036
|
-
return 0;
|
|
1037
|
-
|
|
1038
|
-
fail:
|
|
1039
|
-
git_error_set(GIT_ERROR_OS, "unable to convert unicode path data");
|
|
1040
|
-
return -1;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
static const char *nfc_file = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D.XXXXXX";
|
|
1044
|
-
static const char *nfd_file = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D.XXXXXX";
|
|
1045
|
-
|
|
1046
|
-
/* Check if the platform is decomposing unicode data for us. We will
|
|
1047
|
-
* emulate core Git and prefer to use precomposed unicode data internally
|
|
1048
|
-
* on these platforms, composing the decomposed unicode on the fly.
|
|
1049
|
-
*
|
|
1050
|
-
* This mainly happens on the Mac where HDFS stores filenames as
|
|
1051
|
-
* decomposed unicode. Even on VFAT and SAMBA file systems, the Mac will
|
|
1052
|
-
* return decomposed unicode from readdir() even when the actual
|
|
1053
|
-
* filesystem is storing precomposed unicode.
|
|
1054
|
-
*/
|
|
1055
|
-
bool git_path_does_fs_decompose_unicode(const char *root)
|
|
1056
|
-
{
|
|
1057
|
-
git_buf path = GIT_BUF_INIT;
|
|
1058
|
-
int fd;
|
|
1059
|
-
bool found_decomposed = false;
|
|
1060
|
-
char tmp[6];
|
|
1061
|
-
|
|
1062
|
-
/* Create a file using a precomposed path and then try to find it
|
|
1063
|
-
* using the decomposed name. If the lookup fails, then we will mark
|
|
1064
|
-
* that we should precompose unicode for this repository.
|
|
1065
|
-
*/
|
|
1066
|
-
if (git_buf_joinpath(&path, root, nfc_file) < 0 ||
|
|
1067
|
-
(fd = p_mkstemp(path.ptr)) < 0)
|
|
1068
|
-
goto done;
|
|
1069
|
-
p_close(fd);
|
|
1070
|
-
|
|
1071
|
-
/* record trailing digits generated by mkstemp */
|
|
1072
|
-
memcpy(tmp, path.ptr + path.size - sizeof(tmp), sizeof(tmp));
|
|
1073
|
-
|
|
1074
|
-
/* try to look up as NFD path */
|
|
1075
|
-
if (git_buf_joinpath(&path, root, nfd_file) < 0)
|
|
1076
|
-
goto done;
|
|
1077
|
-
memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
|
|
1078
|
-
|
|
1079
|
-
found_decomposed = git_path_exists(path.ptr);
|
|
1080
|
-
|
|
1081
|
-
/* remove temporary file (using original precomposed path) */
|
|
1082
|
-
if (git_buf_joinpath(&path, root, nfc_file) < 0)
|
|
1083
|
-
goto done;
|
|
1084
|
-
memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
|
|
1085
|
-
|
|
1086
|
-
(void)p_unlink(path.ptr);
|
|
1087
|
-
|
|
1088
|
-
done:
|
|
1089
|
-
git_buf_dispose(&path);
|
|
1090
|
-
return found_decomposed;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
#else
|
|
1094
|
-
|
|
1095
|
-
bool git_path_does_fs_decompose_unicode(const char *root)
|
|
1096
|
-
{
|
|
1097
|
-
GIT_UNUSED(root);
|
|
1098
|
-
return false;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
#endif
|
|
1102
|
-
|
|
1103
|
-
#if defined(__sun) || defined(__GNU__)
|
|
1104
|
-
typedef char path_dirent_data[sizeof(struct dirent) + FILENAME_MAX + 1];
|
|
1105
|
-
#else
|
|
1106
|
-
typedef struct dirent path_dirent_data;
|
|
1107
|
-
#endif
|
|
1108
|
-
|
|
1109
|
-
int git_path_direach(
|
|
1110
|
-
git_buf *path,
|
|
1111
|
-
uint32_t flags,
|
|
1112
|
-
int (*fn)(void *, git_buf *),
|
|
1113
|
-
void *arg)
|
|
1114
|
-
{
|
|
1115
|
-
int error = 0;
|
|
1116
|
-
ssize_t wd_len;
|
|
1117
|
-
DIR *dir;
|
|
1118
|
-
struct dirent *de;
|
|
1119
|
-
|
|
1120
|
-
#ifdef GIT_USE_ICONV
|
|
1121
|
-
git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
|
|
1122
|
-
#endif
|
|
1123
|
-
|
|
1124
|
-
GIT_UNUSED(flags);
|
|
1125
|
-
|
|
1126
|
-
if (git_path_to_dir(path) < 0)
|
|
1127
|
-
return -1;
|
|
1128
|
-
|
|
1129
|
-
wd_len = git_buf_len(path);
|
|
1130
|
-
|
|
1131
|
-
if ((dir = opendir(path->ptr)) == NULL) {
|
|
1132
|
-
git_error_set(GIT_ERROR_OS, "failed to open directory '%s'", path->ptr);
|
|
1133
|
-
if (errno == ENOENT)
|
|
1134
|
-
return GIT_ENOTFOUND;
|
|
1135
|
-
|
|
1136
|
-
return -1;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
#ifdef GIT_USE_ICONV
|
|
1140
|
-
if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0)
|
|
1141
|
-
(void)git_path_iconv_init_precompose(&ic);
|
|
1142
|
-
#endif
|
|
1143
|
-
|
|
1144
|
-
while ((de = readdir(dir)) != NULL) {
|
|
1145
|
-
const char *de_path = de->d_name;
|
|
1146
|
-
size_t de_len = strlen(de_path);
|
|
1147
|
-
|
|
1148
|
-
if (git_path_is_dot_or_dotdot(de_path))
|
|
1149
|
-
continue;
|
|
1150
|
-
|
|
1151
|
-
#ifdef GIT_USE_ICONV
|
|
1152
|
-
if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0)
|
|
1153
|
-
break;
|
|
1154
|
-
#endif
|
|
1155
|
-
|
|
1156
|
-
if ((error = git_buf_put(path, de_path, de_len)) < 0)
|
|
1157
|
-
break;
|
|
1158
|
-
|
|
1159
|
-
git_error_clear();
|
|
1160
|
-
error = fn(arg, path);
|
|
1161
|
-
|
|
1162
|
-
git_buf_truncate(path, wd_len); /* restore path */
|
|
1163
|
-
|
|
1164
|
-
/* Only set our own error if the callback did not set one already */
|
|
1165
|
-
if (error != 0) {
|
|
1166
|
-
if (!git_error_last())
|
|
1167
|
-
git_error_set_after_callback(error);
|
|
1168
|
-
|
|
1169
|
-
break;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
closedir(dir);
|
|
1174
|
-
|
|
1175
|
-
#ifdef GIT_USE_ICONV
|
|
1176
|
-
git_path_iconv_clear(&ic);
|
|
1177
|
-
#endif
|
|
1178
|
-
|
|
1179
|
-
return error;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
#if defined(GIT_WIN32) && !defined(__MINGW32__)
|
|
1183
|
-
|
|
1184
|
-
/* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7
|
|
1185
|
-
* and better.
|
|
1186
|
-
*/
|
|
1187
|
-
#ifndef FIND_FIRST_EX_LARGE_FETCH
|
|
1188
|
-
# define FIND_FIRST_EX_LARGE_FETCH 2
|
|
1189
|
-
#endif
|
|
1190
|
-
|
|
1191
|
-
int git_path_diriter_init(
|
|
1192
|
-
git_path_diriter *diriter,
|
|
1193
|
-
const char *path,
|
|
1194
|
-
unsigned int flags)
|
|
1195
|
-
{
|
|
1196
|
-
git_win32_path path_filter;
|
|
1197
|
-
|
|
1198
|
-
static int is_win7_or_later = -1;
|
|
1199
|
-
if (is_win7_or_later < 0)
|
|
1200
|
-
is_win7_or_later = git_has_win32_version(6, 1, 0);
|
|
1201
|
-
|
|
1202
|
-
GIT_ASSERT_ARG(diriter);
|
|
1203
|
-
GIT_ASSERT_ARG(path);
|
|
1204
|
-
|
|
1205
|
-
memset(diriter, 0, sizeof(git_path_diriter));
|
|
1206
|
-
diriter->handle = INVALID_HANDLE_VALUE;
|
|
1207
|
-
|
|
1208
|
-
if (git_buf_puts(&diriter->path_utf8, path) < 0)
|
|
1209
|
-
return -1;
|
|
1210
|
-
|
|
1211
|
-
path_trim_slashes(&diriter->path_utf8);
|
|
1212
|
-
|
|
1213
|
-
if (diriter->path_utf8.size == 0) {
|
|
1214
|
-
git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
|
|
1215
|
-
return -1;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
if ((diriter->parent_len = git_win32_path_from_utf8(diriter->path, diriter->path_utf8.ptr)) < 0 ||
|
|
1219
|
-
!git_win32__findfirstfile_filter(path_filter, diriter->path_utf8.ptr)) {
|
|
1220
|
-
git_error_set(GIT_ERROR_OS, "could not parse the directory path '%s'", path);
|
|
1221
|
-
return -1;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
diriter->handle = FindFirstFileExW(
|
|
1225
|
-
path_filter,
|
|
1226
|
-
is_win7_or_later ? FindExInfoBasic : FindExInfoStandard,
|
|
1227
|
-
&diriter->current,
|
|
1228
|
-
FindExSearchNameMatch,
|
|
1229
|
-
NULL,
|
|
1230
|
-
is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0);
|
|
1231
|
-
|
|
1232
|
-
if (diriter->handle == INVALID_HANDLE_VALUE) {
|
|
1233
|
-
git_error_set(GIT_ERROR_OS, "could not open directory '%s'", path);
|
|
1234
|
-
return -1;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
diriter->parent_utf8_len = diriter->path_utf8.size;
|
|
1238
|
-
diriter->flags = flags;
|
|
1239
|
-
return 0;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
static int diriter_update_paths(git_path_diriter *diriter)
|
|
1243
|
-
{
|
|
1244
|
-
size_t filename_len, path_len;
|
|
1245
|
-
|
|
1246
|
-
filename_len = wcslen(diriter->current.cFileName);
|
|
1247
|
-
|
|
1248
|
-
if (GIT_ADD_SIZET_OVERFLOW(&path_len, diriter->parent_len, filename_len) ||
|
|
1249
|
-
GIT_ADD_SIZET_OVERFLOW(&path_len, path_len, 2))
|
|
1250
|
-
return -1;
|
|
1251
|
-
|
|
1252
|
-
if (path_len > GIT_WIN_PATH_UTF16) {
|
|
1253
|
-
git_error_set(GIT_ERROR_FILESYSTEM,
|
|
1254
|
-
"invalid path '%.*ls\\%ls' (path too long)",
|
|
1255
|
-
diriter->parent_len, diriter->path, diriter->current.cFileName);
|
|
1256
|
-
return -1;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
diriter->path[diriter->parent_len] = L'\\';
|
|
1260
|
-
memcpy(&diriter->path[diriter->parent_len+1],
|
|
1261
|
-
diriter->current.cFileName, filename_len * sizeof(wchar_t));
|
|
1262
|
-
diriter->path[path_len-1] = L'\0';
|
|
1263
|
-
|
|
1264
|
-
git_buf_truncate(&diriter->path_utf8, diriter->parent_utf8_len);
|
|
1265
|
-
|
|
1266
|
-
if (diriter->parent_utf8_len > 0 &&
|
|
1267
|
-
diriter->path_utf8.ptr[diriter->parent_utf8_len-1] != '/')
|
|
1268
|
-
git_buf_putc(&diriter->path_utf8, '/');
|
|
1269
|
-
|
|
1270
|
-
git_buf_put_w(&diriter->path_utf8, diriter->current.cFileName, filename_len);
|
|
1271
|
-
|
|
1272
|
-
if (git_buf_oom(&diriter->path_utf8))
|
|
1273
|
-
return -1;
|
|
1274
|
-
|
|
1275
|
-
return 0;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
int git_path_diriter_next(git_path_diriter *diriter)
|
|
1279
|
-
{
|
|
1280
|
-
bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT);
|
|
1281
|
-
|
|
1282
|
-
do {
|
|
1283
|
-
/* Our first time through, we already have the data from
|
|
1284
|
-
* FindFirstFileW. Use it, otherwise get the next file.
|
|
1285
|
-
*/
|
|
1286
|
-
if (!diriter->needs_next)
|
|
1287
|
-
diriter->needs_next = 1;
|
|
1288
|
-
else if (!FindNextFileW(diriter->handle, &diriter->current))
|
|
1289
|
-
return GIT_ITEROVER;
|
|
1290
|
-
} while (skip_dot && git_path_is_dot_or_dotdotW(diriter->current.cFileName));
|
|
1291
|
-
|
|
1292
|
-
if (diriter_update_paths(diriter) < 0)
|
|
1293
|
-
return -1;
|
|
1294
|
-
|
|
1295
|
-
return 0;
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
int git_path_diriter_filename(
|
|
1299
|
-
const char **out,
|
|
1300
|
-
size_t *out_len,
|
|
1301
|
-
git_path_diriter *diriter)
|
|
1302
|
-
{
|
|
1303
|
-
GIT_ASSERT_ARG(out);
|
|
1304
|
-
GIT_ASSERT_ARG(out_len);
|
|
1305
|
-
GIT_ASSERT_ARG(diriter);
|
|
1306
|
-
GIT_ASSERT(diriter->path_utf8.size > diriter->parent_utf8_len);
|
|
1307
|
-
|
|
1308
|
-
*out = &diriter->path_utf8.ptr[diriter->parent_utf8_len+1];
|
|
1309
|
-
*out_len = diriter->path_utf8.size - diriter->parent_utf8_len - 1;
|
|
1310
|
-
return 0;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
int git_path_diriter_fullpath(
|
|
1314
|
-
const char **out,
|
|
1315
|
-
size_t *out_len,
|
|
1316
|
-
git_path_diriter *diriter)
|
|
1317
|
-
{
|
|
1318
|
-
GIT_ASSERT_ARG(out);
|
|
1319
|
-
GIT_ASSERT_ARG(out_len);
|
|
1320
|
-
GIT_ASSERT_ARG(diriter);
|
|
1321
|
-
|
|
1322
|
-
*out = diriter->path_utf8.ptr;
|
|
1323
|
-
*out_len = diriter->path_utf8.size;
|
|
1324
|
-
return 0;
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
|
|
1328
|
-
{
|
|
1329
|
-
GIT_ASSERT_ARG(out);
|
|
1330
|
-
GIT_ASSERT_ARG(diriter);
|
|
1331
|
-
|
|
1332
|
-
return git_win32__file_attribute_to_stat(out,
|
|
1333
|
-
(WIN32_FILE_ATTRIBUTE_DATA *)&diriter->current,
|
|
1334
|
-
diriter->path);
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
void git_path_diriter_free(git_path_diriter *diriter)
|
|
1338
|
-
{
|
|
1339
|
-
if (diriter == NULL)
|
|
1340
|
-
return;
|
|
1341
|
-
|
|
1342
|
-
git_buf_dispose(&diriter->path_utf8);
|
|
1343
|
-
|
|
1344
|
-
if (diriter->handle != INVALID_HANDLE_VALUE) {
|
|
1345
|
-
FindClose(diriter->handle);
|
|
1346
|
-
diriter->handle = INVALID_HANDLE_VALUE;
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
#else
|
|
1351
|
-
|
|
1352
|
-
int git_path_diriter_init(
|
|
1353
|
-
git_path_diriter *diriter,
|
|
1354
|
-
const char *path,
|
|
1355
|
-
unsigned int flags)
|
|
1356
|
-
{
|
|
1357
|
-
GIT_ASSERT_ARG(diriter);
|
|
1358
|
-
GIT_ASSERT_ARG(path);
|
|
1359
|
-
|
|
1360
|
-
memset(diriter, 0, sizeof(git_path_diriter));
|
|
1361
|
-
|
|
1362
|
-
if (git_buf_puts(&diriter->path, path) < 0)
|
|
1363
|
-
return -1;
|
|
1364
|
-
|
|
1365
|
-
path_trim_slashes(&diriter->path);
|
|
1366
|
-
|
|
1367
|
-
if (diriter->path.size == 0) {
|
|
1368
|
-
git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
|
|
1369
|
-
return -1;
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
if ((diriter->dir = opendir(diriter->path.ptr)) == NULL) {
|
|
1373
|
-
git_buf_dispose(&diriter->path);
|
|
1374
|
-
|
|
1375
|
-
git_error_set(GIT_ERROR_OS, "failed to open directory '%s'", path);
|
|
1376
|
-
return -1;
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
#ifdef GIT_USE_ICONV
|
|
1380
|
-
if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0)
|
|
1381
|
-
(void)git_path_iconv_init_precompose(&diriter->ic);
|
|
1382
|
-
#endif
|
|
1383
|
-
|
|
1384
|
-
diriter->parent_len = diriter->path.size;
|
|
1385
|
-
diriter->flags = flags;
|
|
1386
|
-
|
|
1387
|
-
return 0;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
int git_path_diriter_next(git_path_diriter *diriter)
|
|
1391
|
-
{
|
|
1392
|
-
struct dirent *de;
|
|
1393
|
-
const char *filename;
|
|
1394
|
-
size_t filename_len;
|
|
1395
|
-
bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT);
|
|
1396
|
-
int error = 0;
|
|
1397
|
-
|
|
1398
|
-
GIT_ASSERT_ARG(diriter);
|
|
1399
|
-
|
|
1400
|
-
errno = 0;
|
|
1401
|
-
|
|
1402
|
-
do {
|
|
1403
|
-
if ((de = readdir(diriter->dir)) == NULL) {
|
|
1404
|
-
if (!errno)
|
|
1405
|
-
return GIT_ITEROVER;
|
|
1406
|
-
|
|
1407
|
-
git_error_set(GIT_ERROR_OS,
|
|
1408
|
-
"could not read directory '%s'", diriter->path.ptr);
|
|
1409
|
-
return -1;
|
|
1410
|
-
}
|
|
1411
|
-
} while (skip_dot && git_path_is_dot_or_dotdot(de->d_name));
|
|
1412
|
-
|
|
1413
|
-
filename = de->d_name;
|
|
1414
|
-
filename_len = strlen(filename);
|
|
1415
|
-
|
|
1416
|
-
#ifdef GIT_USE_ICONV
|
|
1417
|
-
if ((diriter->flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0 &&
|
|
1418
|
-
(error = git_path_iconv(&diriter->ic, &filename, &filename_len)) < 0)
|
|
1419
|
-
return error;
|
|
1420
|
-
#endif
|
|
1421
|
-
|
|
1422
|
-
git_buf_truncate(&diriter->path, diriter->parent_len);
|
|
1423
|
-
|
|
1424
|
-
if (diriter->parent_len > 0 &&
|
|
1425
|
-
diriter->path.ptr[diriter->parent_len-1] != '/')
|
|
1426
|
-
git_buf_putc(&diriter->path, '/');
|
|
1427
|
-
|
|
1428
|
-
git_buf_put(&diriter->path, filename, filename_len);
|
|
1429
|
-
|
|
1430
|
-
if (git_buf_oom(&diriter->path))
|
|
1431
|
-
return -1;
|
|
1432
|
-
|
|
1433
|
-
return error;
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
int git_path_diriter_filename(
|
|
1437
|
-
const char **out,
|
|
1438
|
-
size_t *out_len,
|
|
1439
|
-
git_path_diriter *diriter)
|
|
1440
|
-
{
|
|
1441
|
-
GIT_ASSERT_ARG(out);
|
|
1442
|
-
GIT_ASSERT_ARG(out_len);
|
|
1443
|
-
GIT_ASSERT_ARG(diriter);
|
|
1444
|
-
GIT_ASSERT(diriter->path.size > diriter->parent_len);
|
|
1445
|
-
|
|
1446
|
-
*out = &diriter->path.ptr[diriter->parent_len+1];
|
|
1447
|
-
*out_len = diriter->path.size - diriter->parent_len - 1;
|
|
1448
|
-
return 0;
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
|
-
int git_path_diriter_fullpath(
|
|
1452
|
-
const char **out,
|
|
1453
|
-
size_t *out_len,
|
|
1454
|
-
git_path_diriter *diriter)
|
|
1455
|
-
{
|
|
1456
|
-
GIT_ASSERT_ARG(out);
|
|
1457
|
-
GIT_ASSERT_ARG(out_len);
|
|
1458
|
-
GIT_ASSERT_ARG(diriter);
|
|
1459
|
-
|
|
1460
|
-
*out = diriter->path.ptr;
|
|
1461
|
-
*out_len = diriter->path.size;
|
|
1462
|
-
return 0;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
|
|
1466
|
-
{
|
|
1467
|
-
GIT_ASSERT_ARG(out);
|
|
1468
|
-
GIT_ASSERT_ARG(diriter);
|
|
1469
|
-
|
|
1470
|
-
return git_path_lstat(diriter->path.ptr, out);
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
void git_path_diriter_free(git_path_diriter *diriter)
|
|
1474
|
-
{
|
|
1475
|
-
if (diriter == NULL)
|
|
1476
|
-
return;
|
|
1477
|
-
|
|
1478
|
-
if (diriter->dir) {
|
|
1479
|
-
closedir(diriter->dir);
|
|
1480
|
-
diriter->dir = NULL;
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
#ifdef GIT_USE_ICONV
|
|
1484
|
-
git_path_iconv_clear(&diriter->ic);
|
|
1485
|
-
#endif
|
|
1486
|
-
|
|
1487
|
-
git_buf_dispose(&diriter->path);
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
#endif
|
|
1491
|
-
|
|
1492
|
-
int git_path_dirload(
|
|
1493
|
-
git_vector *contents,
|
|
1494
|
-
const char *path,
|
|
1495
|
-
size_t prefix_len,
|
|
1496
|
-
uint32_t flags)
|
|
1497
|
-
{
|
|
1498
|
-
git_path_diriter iter = GIT_PATH_DIRITER_INIT;
|
|
1499
|
-
const char *name;
|
|
1500
|
-
size_t name_len;
|
|
1501
|
-
char *dup;
|
|
1502
|
-
int error;
|
|
1503
|
-
|
|
1504
|
-
GIT_ASSERT_ARG(contents);
|
|
1505
|
-
GIT_ASSERT_ARG(path);
|
|
11
|
+
#include "fs_path.h"
|
|
1506
12
|
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
break;
|
|
1513
|
-
|
|
1514
|
-
GIT_ASSERT(name_len > prefix_len);
|
|
1515
|
-
|
|
1516
|
-
dup = git__strndup(name + prefix_len, name_len - prefix_len);
|
|
1517
|
-
GIT_ERROR_CHECK_ALLOC(dup);
|
|
1518
|
-
|
|
1519
|
-
if ((error = git_vector_insert(contents, dup)) < 0)
|
|
1520
|
-
break;
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
if (error == GIT_ITEROVER)
|
|
1524
|
-
error = 0;
|
|
1525
|
-
|
|
1526
|
-
git_path_diriter_free(&iter);
|
|
1527
|
-
return error;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
|
1531
|
-
{
|
|
1532
|
-
if (git_path_is_local_file_url(url_or_path))
|
|
1533
|
-
return git_path_fromurl(local_path_out, url_or_path);
|
|
1534
|
-
else
|
|
1535
|
-
return git_buf_sets(local_path_out, url_or_path);
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
/* Reject paths like AUX or COM1, or those versions that end in a dot or
|
|
1539
|
-
* colon. ("AUX." or "AUX:")
|
|
1540
|
-
*/
|
|
1541
|
-
GIT_INLINE(bool) verify_dospath(
|
|
1542
|
-
const char *component,
|
|
1543
|
-
size_t len,
|
|
1544
|
-
const char dospath[3],
|
|
1545
|
-
bool trailing_num)
|
|
1546
|
-
{
|
|
1547
|
-
size_t last = trailing_num ? 4 : 3;
|
|
1548
|
-
|
|
1549
|
-
if (len < last || git__strncasecmp(component, dospath, 3) != 0)
|
|
1550
|
-
return true;
|
|
1551
|
-
|
|
1552
|
-
if (trailing_num && (component[3] < '1' || component[3] > '9'))
|
|
1553
|
-
return true;
|
|
1554
|
-
|
|
1555
|
-
return (len > last &&
|
|
1556
|
-
component[last] != '.' &&
|
|
1557
|
-
component[last] != ':');
|
|
1558
|
-
}
|
|
13
|
+
typedef struct {
|
|
14
|
+
git_repository *repo;
|
|
15
|
+
uint16_t file_mode;
|
|
16
|
+
unsigned int flags;
|
|
17
|
+
} repository_path_validate_data;
|
|
1559
18
|
|
|
1560
19
|
static int32_t next_hfs_char(const char **in, size_t *len)
|
|
1561
20
|
{
|
|
@@ -1598,7 +57,11 @@ static int32_t next_hfs_char(const char **in, size_t *len)
|
|
|
1598
57
|
return 0; /* NULL byte -- end of string */
|
|
1599
58
|
}
|
|
1600
59
|
|
|
1601
|
-
static bool
|
|
60
|
+
static bool validate_dotgit_hfs_generic(
|
|
61
|
+
const char *path,
|
|
62
|
+
size_t len,
|
|
63
|
+
const char *needle,
|
|
64
|
+
size_t needle_len)
|
|
1602
65
|
{
|
|
1603
66
|
size_t i;
|
|
1604
67
|
char c;
|
|
@@ -1618,14 +81,17 @@ static bool verify_dotgit_hfs_generic(const char *path, size_t len, const char *
|
|
|
1618
81
|
return false;
|
|
1619
82
|
}
|
|
1620
83
|
|
|
1621
|
-
static bool
|
|
84
|
+
static bool validate_dotgit_hfs(const char *path, size_t len)
|
|
1622
85
|
{
|
|
1623
|
-
return
|
|
86
|
+
return validate_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git"));
|
|
1624
87
|
}
|
|
1625
88
|
|
|
1626
|
-
GIT_INLINE(bool)
|
|
89
|
+
GIT_INLINE(bool) validate_dotgit_ntfs(
|
|
90
|
+
git_repository *repo,
|
|
91
|
+
const char *path,
|
|
92
|
+
size_t len)
|
|
1627
93
|
{
|
|
1628
|
-
|
|
94
|
+
git_str *reserved = git_repository__reserved_names_win32;
|
|
1629
95
|
size_t reserved_len = git_repository__reserved_names_win32_len;
|
|
1630
96
|
size_t start = 0, i;
|
|
1631
97
|
|
|
@@ -1633,7 +99,7 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size
|
|
|
1633
99
|
git_repository__reserved_names(&reserved, &reserved_len, repo, true);
|
|
1634
100
|
|
|
1635
101
|
for (i = 0; i < reserved_len; i++) {
|
|
1636
|
-
|
|
102
|
+
git_str *r = &reserved[i];
|
|
1637
103
|
|
|
1638
104
|
if (len >= r->size &&
|
|
1639
105
|
strncasecmp(path, r->ptr, r->size) == 0) {
|
|
@@ -1685,7 +151,12 @@ GIT_INLINE(bool) ntfs_end_of_filename(const char *path)
|
|
|
1685
151
|
return true;
|
|
1686
152
|
}
|
|
1687
153
|
|
|
1688
|
-
GIT_INLINE(bool)
|
|
154
|
+
GIT_INLINE(bool) validate_dotgit_ntfs_generic(
|
|
155
|
+
const char *name,
|
|
156
|
+
size_t len,
|
|
157
|
+
const char *dotgit_name,
|
|
158
|
+
size_t dotgit_len,
|
|
159
|
+
const char *shortname_pfix)
|
|
1689
160
|
{
|
|
1690
161
|
int i, saw_tilde;
|
|
1691
162
|
|
|
@@ -1722,33 +193,6 @@ GIT_INLINE(bool) verify_dotgit_ntfs_generic(const char *name, size_t len, const
|
|
|
1722
193
|
return !ntfs_end_of_filename(name + i);
|
|
1723
194
|
}
|
|
1724
195
|
|
|
1725
|
-
GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
|
|
1726
|
-
{
|
|
1727
|
-
if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
|
|
1728
|
-
return false;
|
|
1729
|
-
|
|
1730
|
-
if ((flags & GIT_PATH_REJECT_SLASH) && c == '/')
|
|
1731
|
-
return false;
|
|
1732
|
-
|
|
1733
|
-
if (flags & GIT_PATH_REJECT_NT_CHARS) {
|
|
1734
|
-
if (c < 32)
|
|
1735
|
-
return false;
|
|
1736
|
-
|
|
1737
|
-
switch (c) {
|
|
1738
|
-
case '<':
|
|
1739
|
-
case '>':
|
|
1740
|
-
case ':':
|
|
1741
|
-
case '"':
|
|
1742
|
-
case '|':
|
|
1743
|
-
case '?':
|
|
1744
|
-
case '*':
|
|
1745
|
-
return false;
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
return true;
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
196
|
/*
|
|
1753
197
|
* Return the length of the common prefix between str and prefix, comparing them
|
|
1754
198
|
* case-insensitively (must be ASCII to match).
|
|
@@ -1757,7 +201,7 @@ GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *
|
|
|
1757
201
|
{
|
|
1758
202
|
size_t count = 0;
|
|
1759
203
|
|
|
1760
|
-
while (len >0 && tolower(*str) == tolower(*prefix)) {
|
|
204
|
+
while (len > 0 && tolower(*str) == tolower(*prefix)) {
|
|
1761
205
|
count++;
|
|
1762
206
|
str++;
|
|
1763
207
|
prefix++;
|
|
@@ -1767,72 +211,37 @@ GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *
|
|
|
1767
211
|
return count;
|
|
1768
212
|
}
|
|
1769
213
|
|
|
1770
|
-
|
|
1771
|
-
* We fundamentally don't like some paths when dealing with user-inputted
|
|
1772
|
-
* strings (in checkout or ref names): we don't want dot or dot-dot
|
|
1773
|
-
* anywhere, we want to avoid writing weird paths on Windows that can't
|
|
1774
|
-
* be handled by tools that use the non-\\?\ APIs, we don't want slashes
|
|
1775
|
-
* or double slashes at the end of paths that can make them ambiguous.
|
|
1776
|
-
*
|
|
1777
|
-
* For checkout, we don't want to recurse into ".git" either.
|
|
1778
|
-
*/
|
|
1779
|
-
static bool verify_component(
|
|
1780
|
-
git_repository *repo,
|
|
214
|
+
static bool validate_repo_component(
|
|
1781
215
|
const char *component,
|
|
1782
216
|
size_t len,
|
|
1783
|
-
|
|
1784
|
-
unsigned int flags)
|
|
217
|
+
void *payload)
|
|
1785
218
|
{
|
|
1786
|
-
|
|
1787
|
-
return false;
|
|
1788
|
-
|
|
1789
|
-
if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
|
|
1790
|
-
len == 1 && component[0] == '.')
|
|
1791
|
-
return false;
|
|
1792
|
-
|
|
1793
|
-
if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
|
|
1794
|
-
len == 2 && component[0] == '.' && component[1] == '.')
|
|
1795
|
-
return false;
|
|
1796
|
-
|
|
1797
|
-
if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.')
|
|
1798
|
-
return false;
|
|
1799
|
-
|
|
1800
|
-
if ((flags & GIT_PATH_REJECT_TRAILING_SPACE) && component[len-1] == ' ')
|
|
1801
|
-
return false;
|
|
1802
|
-
|
|
1803
|
-
if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':')
|
|
1804
|
-
return false;
|
|
219
|
+
repository_path_validate_data *data = (repository_path_validate_data *)payload;
|
|
1805
220
|
|
|
1806
|
-
if (flags &
|
|
1807
|
-
if (!
|
|
1808
|
-
!verify_dospath(component, len, "PRN", false) ||
|
|
1809
|
-
!verify_dospath(component, len, "AUX", false) ||
|
|
1810
|
-
!verify_dospath(component, len, "NUL", false) ||
|
|
1811
|
-
!verify_dospath(component, len, "COM", true) ||
|
|
1812
|
-
!verify_dospath(component, len, "LPT", true))
|
|
221
|
+
if (data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) {
|
|
222
|
+
if (!validate_dotgit_hfs(component, len))
|
|
1813
223
|
return false;
|
|
1814
|
-
}
|
|
1815
224
|
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
return false;
|
|
1819
|
-
if (S_ISLNK(mode) && git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_HFS))
|
|
225
|
+
if (S_ISLNK(data->file_mode) &&
|
|
226
|
+
git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_HFS))
|
|
1820
227
|
return false;
|
|
1821
228
|
}
|
|
1822
229
|
|
|
1823
|
-
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
|
|
1824
|
-
if (!
|
|
230
|
+
if (data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
|
|
231
|
+
if (!validate_dotgit_ntfs(data->repo, component, len))
|
|
1825
232
|
return false;
|
|
1826
|
-
|
|
233
|
+
|
|
234
|
+
if (S_ISLNK(data->file_mode) &&
|
|
235
|
+
git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_NTFS))
|
|
1827
236
|
return false;
|
|
1828
237
|
}
|
|
1829
238
|
|
|
1830
239
|
/* don't bother rerunning the `.git` test if we ran the HFS or NTFS
|
|
1831
240
|
* specific tests, they would have already rejected `.git`.
|
|
1832
241
|
*/
|
|
1833
|
-
if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
|
|
1834
|
-
(flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
|
|
1835
|
-
(flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) {
|
|
242
|
+
if ((data->flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
|
|
243
|
+
(data->flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
|
|
244
|
+
(data->flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) {
|
|
1836
245
|
if (len >= 4 &&
|
|
1837
246
|
component[0] == '.' &&
|
|
1838
247
|
(component[1] == 'g' || component[1] == 'G') &&
|
|
@@ -1841,10 +250,11 @@ static bool verify_component(
|
|
|
1841
250
|
if (len == 4)
|
|
1842
251
|
return false;
|
|
1843
252
|
|
|
1844
|
-
if (S_ISLNK(
|
|
253
|
+
if (S_ISLNK(data->file_mode) &&
|
|
254
|
+
common_prefix_icase(component, len, ".gitmodules") == len)
|
|
1845
255
|
return false;
|
|
1846
256
|
}
|
|
1847
|
-
|
|
257
|
+
}
|
|
1848
258
|
|
|
1849
259
|
return true;
|
|
1850
260
|
}
|
|
@@ -1875,93 +285,49 @@ GIT_INLINE(unsigned int) dotgit_flags(
|
|
|
1875
285
|
return flags;
|
|
1876
286
|
}
|
|
1877
287
|
|
|
1878
|
-
|
|
288
|
+
GIT_INLINE(unsigned int) length_flags(
|
|
1879
289
|
git_repository *repo,
|
|
1880
|
-
const char *path,
|
|
1881
|
-
uint16_t mode,
|
|
1882
290
|
unsigned int flags)
|
|
1883
291
|
{
|
|
1884
|
-
const char *start, *c;
|
|
1885
|
-
|
|
1886
|
-
/* Upgrade the ".git" checks based on platform */
|
|
1887
|
-
if ((flags & GIT_PATH_REJECT_DOT_GIT))
|
|
1888
|
-
flags = dotgit_flags(repo, flags);
|
|
1889
|
-
|
|
1890
|
-
for (start = c = path; *c; c++) {
|
|
1891
|
-
if (!verify_char(*c, flags))
|
|
1892
|
-
return false;
|
|
1893
|
-
|
|
1894
|
-
if (*c == '/') {
|
|
1895
|
-
if (!verify_component(repo, start, (c - start), mode, flags))
|
|
1896
|
-
return false;
|
|
1897
|
-
|
|
1898
|
-
start = c+1;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
return verify_component(repo, start, (c - start), mode, flags);
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
292
|
#ifdef GIT_WIN32
|
|
1906
|
-
|
|
1907
|
-
{
|
|
1908
|
-
int longpaths = 0;
|
|
293
|
+
int allow = 0;
|
|
1909
294
|
|
|
1910
295
|
if (repo &&
|
|
1911
|
-
git_repository__configmap_lookup(&
|
|
1912
|
-
|
|
296
|
+
git_repository__configmap_lookup(&allow, repo, GIT_CONFIGMAP_LONGPATHS) < 0)
|
|
297
|
+
allow = 0;
|
|
1913
298
|
|
|
1914
|
-
|
|
1915
|
-
|
|
299
|
+
if (allow)
|
|
300
|
+
flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS;
|
|
1916
301
|
|
|
1917
302
|
#else
|
|
1918
|
-
|
|
1919
|
-
GIT_INLINE(bool) should_validate_longpaths(git_repository *repo)
|
|
1920
|
-
{
|
|
1921
303
|
GIT_UNUSED(repo);
|
|
1922
|
-
|
|
1923
|
-
return false;
|
|
1924
|
-
}
|
|
304
|
+
flags &= ~GIT_FS_PATH_REJECT_LONG_PATHS;
|
|
1925
305
|
#endif
|
|
1926
306
|
|
|
1927
|
-
|
|
1928
|
-
{
|
|
1929
|
-
if (should_validate_longpaths(repo))
|
|
1930
|
-
return git_path_validate_filesystem(path, strlen(path));
|
|
1931
|
-
|
|
1932
|
-
return 0;
|
|
307
|
+
return flags;
|
|
1933
308
|
}
|
|
1934
309
|
|
|
1935
|
-
|
|
310
|
+
bool git_path_str_is_valid(
|
|
1936
311
|
git_repository *repo,
|
|
1937
|
-
const
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
if (should_validate_longpaths(repo))
|
|
1941
|
-
return git_path_validate_filesystem(path, path_len);
|
|
1942
|
-
|
|
1943
|
-
return 0;
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
int git_path_validate_workdir_buf(git_repository *repo, git_buf *path)
|
|
312
|
+
const git_str *path,
|
|
313
|
+
uint16_t file_mode,
|
|
314
|
+
unsigned int flags)
|
|
1947
315
|
{
|
|
1948
|
-
|
|
1949
|
-
}
|
|
316
|
+
repository_path_validate_data data = {0};
|
|
1950
317
|
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
char *p;
|
|
318
|
+
/* Upgrade the ".git" checks based on platform */
|
|
319
|
+
if ((flags & GIT_PATH_REJECT_DOT_GIT))
|
|
320
|
+
flags = dotgit_flags(repo, flags);
|
|
1955
321
|
|
|
1956
|
-
|
|
1957
|
-
|
|
322
|
+
/* Update the length checks based on platform */
|
|
323
|
+
if ((flags & GIT_FS_PATH_REJECT_LONG_PATHS))
|
|
324
|
+
flags = length_flags(repo, flags);
|
|
1958
325
|
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
}
|
|
326
|
+
data.repo = repo;
|
|
327
|
+
data.file_mode = file_mode;
|
|
328
|
+
data.flags = flags;
|
|
1963
329
|
|
|
1964
|
-
return
|
|
330
|
+
return git_fs_path_str_is_valid_ext(path, flags, NULL, validate_repo_component, NULL, &data);
|
|
1965
331
|
}
|
|
1966
332
|
|
|
1967
333
|
static const struct {
|
|
@@ -1974,7 +340,11 @@ static const struct {
|
|
|
1974
340
|
{ "gitattributes", "gi7d29", CONST_STRLEN("gitattributes") }
|
|
1975
341
|
};
|
|
1976
342
|
|
|
1977
|
-
extern int git_path_is_gitfile(
|
|
343
|
+
extern int git_path_is_gitfile(
|
|
344
|
+
const char *path,
|
|
345
|
+
size_t pathlen,
|
|
346
|
+
git_path_gitfile gitfile,
|
|
347
|
+
git_path_fs fs)
|
|
1978
348
|
{
|
|
1979
349
|
const char *file, *hash;
|
|
1980
350
|
size_t filelen;
|
|
@@ -1990,260 +360,15 @@ extern int git_path_is_gitfile(const char *path, size_t pathlen, git_path_gitfil
|
|
|
1990
360
|
|
|
1991
361
|
switch (fs) {
|
|
1992
362
|
case GIT_PATH_FS_GENERIC:
|
|
1993
|
-
return !
|
|
1994
|
-
!
|
|
363
|
+
return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash) ||
|
|
364
|
+
!validate_dotgit_hfs_generic(path, pathlen, file, filelen);
|
|
1995
365
|
case GIT_PATH_FS_NTFS:
|
|
1996
|
-
return !
|
|
366
|
+
return !validate_dotgit_ntfs_generic(path, pathlen, file, filelen, hash);
|
|
1997
367
|
case GIT_PATH_FS_HFS:
|
|
1998
|
-
return !
|
|
368
|
+
return !validate_dotgit_hfs_generic(path, pathlen, file, filelen);
|
|
1999
369
|
default:
|
|
2000
370
|
git_error_set(GIT_ERROR_OS, "invalid filesystem for path validation");
|
|
2001
371
|
return -1;
|
|
2002
372
|
}
|
|
2003
373
|
}
|
|
2004
374
|
|
|
2005
|
-
bool git_path_supports_symlinks(const char *dir)
|
|
2006
|
-
{
|
|
2007
|
-
git_buf path = GIT_BUF_INIT;
|
|
2008
|
-
bool supported = false;
|
|
2009
|
-
struct stat st;
|
|
2010
|
-
int fd;
|
|
2011
|
-
|
|
2012
|
-
if ((fd = git_futils_mktmp(&path, dir, 0666)) < 0 ||
|
|
2013
|
-
p_close(fd) < 0 ||
|
|
2014
|
-
p_unlink(path.ptr) < 0 ||
|
|
2015
|
-
p_symlink("testing", path.ptr) < 0 ||
|
|
2016
|
-
p_lstat(path.ptr, &st) < 0)
|
|
2017
|
-
goto done;
|
|
2018
|
-
|
|
2019
|
-
supported = (S_ISLNK(st.st_mode) != 0);
|
|
2020
|
-
done:
|
|
2021
|
-
if (path.size)
|
|
2022
|
-
(void)p_unlink(path.ptr);
|
|
2023
|
-
git_buf_dispose(&path);
|
|
2024
|
-
return supported;
|
|
2025
|
-
}
|
|
2026
|
-
|
|
2027
|
-
static git_path_owner_t mock_owner = GIT_PATH_OWNER_NONE;
|
|
2028
|
-
|
|
2029
|
-
void git_path__set_owner(git_path_owner_t owner)
|
|
2030
|
-
{
|
|
2031
|
-
mock_owner = owner;
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
#ifdef GIT_WIN32
|
|
2035
|
-
static PSID *sid_dup(PSID sid)
|
|
2036
|
-
{
|
|
2037
|
-
DWORD len;
|
|
2038
|
-
PSID dup;
|
|
2039
|
-
|
|
2040
|
-
len = GetLengthSid(sid);
|
|
2041
|
-
|
|
2042
|
-
if ((dup = git__malloc(len)) == NULL)
|
|
2043
|
-
return NULL;
|
|
2044
|
-
|
|
2045
|
-
if (!CopySid(len, dup, sid)) {
|
|
2046
|
-
git_error_set(GIT_ERROR_OS, "could not duplicate sid");
|
|
2047
|
-
git__free(dup);
|
|
2048
|
-
return NULL;
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
|
-
return dup;
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
static int current_user_sid(PSID *out)
|
|
2055
|
-
{
|
|
2056
|
-
TOKEN_USER *info = NULL;
|
|
2057
|
-
HANDLE token = NULL;
|
|
2058
|
-
DWORD len = 0;
|
|
2059
|
-
int error = -1;
|
|
2060
|
-
|
|
2061
|
-
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
|
2062
|
-
git_error_set(GIT_ERROR_OS, "could not lookup process information");
|
|
2063
|
-
goto done;
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
|
-
if (GetTokenInformation(token, TokenUser, NULL, 0, &len) ||
|
|
2067
|
-
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
2068
|
-
git_error_set(GIT_ERROR_OS, "could not lookup token metadata");
|
|
2069
|
-
goto done;
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
info = git__malloc(len);
|
|
2073
|
-
GIT_ERROR_CHECK_ALLOC(info);
|
|
2074
|
-
|
|
2075
|
-
if (!GetTokenInformation(token, TokenUser, info, len, &len)) {
|
|
2076
|
-
git_error_set(GIT_ERROR_OS, "could not lookup current user");
|
|
2077
|
-
goto done;
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
if ((*out = sid_dup(info->User.Sid)))
|
|
2081
|
-
error = 0;
|
|
2082
|
-
|
|
2083
|
-
done:
|
|
2084
|
-
if (token)
|
|
2085
|
-
CloseHandle(token);
|
|
2086
|
-
|
|
2087
|
-
git__free(info);
|
|
2088
|
-
return error;
|
|
2089
|
-
}
|
|
2090
|
-
|
|
2091
|
-
static int file_owner_sid(PSID *out, const char *path)
|
|
2092
|
-
{
|
|
2093
|
-
git_win32_path path_w32;
|
|
2094
|
-
PSECURITY_DESCRIPTOR descriptor = NULL;
|
|
2095
|
-
PSID owner_sid;
|
|
2096
|
-
DWORD ret;
|
|
2097
|
-
int error = -1;
|
|
2098
|
-
|
|
2099
|
-
if (git_win32_path_from_utf8(path_w32, path) < 0)
|
|
2100
|
-
return -1;
|
|
2101
|
-
|
|
2102
|
-
ret = GetNamedSecurityInfoW(path_w32, SE_FILE_OBJECT,
|
|
2103
|
-
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
|
2104
|
-
&owner_sid, NULL, NULL, NULL, &descriptor);
|
|
2105
|
-
|
|
2106
|
-
if (ret == ERROR_FILE_NOT_FOUND || ret == ERROR_PATH_NOT_FOUND)
|
|
2107
|
-
error = GIT_ENOTFOUND;
|
|
2108
|
-
else if (ret != ERROR_SUCCESS)
|
|
2109
|
-
git_error_set(GIT_ERROR_OS, "failed to get security information");
|
|
2110
|
-
else if (!IsValidSid(owner_sid))
|
|
2111
|
-
git_error_set(GIT_ERROR_OS, "file owner is not valid");
|
|
2112
|
-
else if ((*out = sid_dup(owner_sid)))
|
|
2113
|
-
error = 0;
|
|
2114
|
-
|
|
2115
|
-
if (descriptor)
|
|
2116
|
-
LocalFree(descriptor);
|
|
2117
|
-
|
|
2118
|
-
return error;
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
int git_path_owner_is(
|
|
2122
|
-
bool *out,
|
|
2123
|
-
const char *path,
|
|
2124
|
-
git_path_owner_t owner_type)
|
|
2125
|
-
{
|
|
2126
|
-
PSID owner_sid = NULL, user_sid = NULL;
|
|
2127
|
-
BOOL is_admin, admin_owned;
|
|
2128
|
-
int error;
|
|
2129
|
-
|
|
2130
|
-
if (mock_owner) {
|
|
2131
|
-
*out = ((mock_owner & owner_type) != 0);
|
|
2132
|
-
return 0;
|
|
2133
|
-
}
|
|
2134
|
-
|
|
2135
|
-
if ((error = file_owner_sid(&owner_sid, path)) < 0)
|
|
2136
|
-
goto done;
|
|
2137
|
-
|
|
2138
|
-
if ((owner_type & GIT_PATH_OWNER_CURRENT_USER) != 0) {
|
|
2139
|
-
if ((error = current_user_sid(&user_sid)) < 0)
|
|
2140
|
-
goto done;
|
|
2141
|
-
|
|
2142
|
-
if (EqualSid(owner_sid, user_sid)) {
|
|
2143
|
-
*out = true;
|
|
2144
|
-
goto done;
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
admin_owned =
|
|
2149
|
-
IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
|
|
2150
|
-
IsWellKnownSid(owner_sid, WinLocalSystemSid);
|
|
2151
|
-
|
|
2152
|
-
if (admin_owned &&
|
|
2153
|
-
(owner_type & GIT_PATH_OWNER_ADMINISTRATOR) != 0) {
|
|
2154
|
-
*out = true;
|
|
2155
|
-
goto done;
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
if (admin_owned &&
|
|
2159
|
-
(owner_type & GIT_PATH_USER_IS_ADMINISTRATOR) != 0 &&
|
|
2160
|
-
CheckTokenMembership(NULL, owner_sid, &is_admin) &&
|
|
2161
|
-
is_admin) {
|
|
2162
|
-
*out = true;
|
|
2163
|
-
goto done;
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
*out = false;
|
|
2167
|
-
|
|
2168
|
-
done:
|
|
2169
|
-
git__free(owner_sid);
|
|
2170
|
-
git__free(user_sid);
|
|
2171
|
-
return error;
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
#else
|
|
2175
|
-
|
|
2176
|
-
static int sudo_uid_lookup(uid_t *out)
|
|
2177
|
-
{
|
|
2178
|
-
git_buf uid_str = GIT_BUF_INIT;
|
|
2179
|
-
int64_t uid;
|
|
2180
|
-
int error;
|
|
2181
|
-
|
|
2182
|
-
if ((error = git__getenv(&uid_str, "SUDO_UID")) == 0 &&
|
|
2183
|
-
(error = git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10)) == 0 &&
|
|
2184
|
-
uid == (int64_t)((uid_t)uid)) {
|
|
2185
|
-
*out = (uid_t)uid;
|
|
2186
|
-
}
|
|
2187
|
-
|
|
2188
|
-
git_buf_dispose(&uid_str);
|
|
2189
|
-
return error;
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
int git_path_owner_is(
|
|
2193
|
-
bool *out,
|
|
2194
|
-
const char *path,
|
|
2195
|
-
git_path_owner_t owner_type)
|
|
2196
|
-
{
|
|
2197
|
-
struct stat st;
|
|
2198
|
-
uid_t euid, sudo_uid;
|
|
2199
|
-
|
|
2200
|
-
if (mock_owner) {
|
|
2201
|
-
*out = ((mock_owner & owner_type) != 0);
|
|
2202
|
-
return 0;
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
euid = geteuid();
|
|
2206
|
-
|
|
2207
|
-
if (p_lstat(path, &st) != 0) {
|
|
2208
|
-
if (errno == ENOENT)
|
|
2209
|
-
return GIT_ENOTFOUND;
|
|
2210
|
-
|
|
2211
|
-
git_error_set(GIT_ERROR_OS, "could not stat '%s'", path);
|
|
2212
|
-
return -1;
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
if ((owner_type & GIT_PATH_OWNER_CURRENT_USER) != 0 &&
|
|
2216
|
-
st.st_uid == euid) {
|
|
2217
|
-
*out = true;
|
|
2218
|
-
return 0;
|
|
2219
|
-
}
|
|
2220
|
-
|
|
2221
|
-
if ((owner_type & GIT_PATH_OWNER_ADMINISTRATOR) != 0 &&
|
|
2222
|
-
st.st_uid == 0) {
|
|
2223
|
-
*out = true;
|
|
2224
|
-
return 0;
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
if ((owner_type & GIT_PATH_OWNER_RUNNING_SUDO) != 0 &&
|
|
2228
|
-
euid == 0 &&
|
|
2229
|
-
sudo_uid_lookup(&sudo_uid) == 0 &&
|
|
2230
|
-
st.st_uid == sudo_uid) {
|
|
2231
|
-
*out = true;
|
|
2232
|
-
return 0;
|
|
2233
|
-
}
|
|
2234
|
-
|
|
2235
|
-
*out = false;
|
|
2236
|
-
return 0;
|
|
2237
|
-
}
|
|
2238
|
-
|
|
2239
|
-
#endif
|
|
2240
|
-
|
|
2241
|
-
int git_path_owner_is_current_user(bool *out, const char *path)
|
|
2242
|
-
{
|
|
2243
|
-
return git_path_owner_is(out, path, GIT_PATH_OWNER_CURRENT_USER);
|
|
2244
|
-
}
|
|
2245
|
-
|
|
2246
|
-
int git_path_owner_is_system(bool *out, const char *path)
|
|
2247
|
-
{
|
|
2248
|
-
return git_path_owner_is(out, path, GIT_PATH_OWNER_ADMINISTRATOR);
|
|
2249
|
-
}
|