rugged 0.21.2 → 0.21.3
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/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/include/git2/version.h +2 -2
- data/vendor/libgit2/src/checkout.c +27 -1
- data/vendor/libgit2/src/config_cache.c +2 -0
- data/vendor/libgit2/src/index.c +48 -25
- data/vendor/libgit2/src/path.c +256 -0
- data/vendor/libgit2/src/path.h +43 -0
- data/vendor/libgit2/src/refdb_fs.c +11 -1
- data/vendor/libgit2/src/repository.c +25 -0
- data/vendor/libgit2/src/repository.h +25 -1
- data/vendor/libgit2/src/tree.c +1 -1
- data/vendor/libgit2/src/util.c +91 -0
- data/vendor/libgit2/src/util.h +12 -0
- data/vendor/libgit2/src/win32/findfile.c +1 -0
- data/vendor/libgit2/src/win32/path_w32.c +305 -0
- data/vendor/libgit2/src/win32/path_w32.h +80 -0
- data/vendor/libgit2/src/win32/posix.h +1 -0
- data/vendor/libgit2/src/win32/posix_w32.c +25 -42
- data/vendor/libgit2/src/win32/utf-conv.c +36 -6
- data/vendor/libgit2/src/win32/utf-conv.h +0 -39
- data/vendor/libgit2/src/win32/w32_util.h +1 -0
- metadata +4 -2
data/vendor/libgit2/src/path.h
CHANGED
@@ -441,4 +441,47 @@ extern bool git_path_does_fs_decompose_unicode(const char *root);
|
|
441
441
|
/* Used for paths to repositories on the filesystem */
|
442
442
|
extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path);
|
443
443
|
|
444
|
+
/* Flags to determine path validity in `git_path_isvalid` */
|
445
|
+
#define GIT_PATH_REJECT_TRAVERSAL (1 << 0)
|
446
|
+
#define GIT_PATH_REJECT_DOT_GIT (1 << 1)
|
447
|
+
#define GIT_PATH_REJECT_SLASH (1 << 2)
|
448
|
+
#define GIT_PATH_REJECT_BACKSLASH (1 << 3)
|
449
|
+
#define GIT_PATH_REJECT_TRAILING_DOT (1 << 4)
|
450
|
+
#define GIT_PATH_REJECT_TRAILING_SPACE (1 << 5)
|
451
|
+
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 6)
|
452
|
+
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
|
453
|
+
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
|
454
|
+
#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 9)
|
455
|
+
#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 10)
|
456
|
+
|
457
|
+
/* Default path safety for writing files to disk: since we use the
|
458
|
+
* Win32 "File Namespace" APIs ("\\?\") we need to protect from
|
459
|
+
* paths that the normal Win32 APIs would not write.
|
460
|
+
*/
|
461
|
+
#ifdef GIT_WIN32
|
462
|
+
# define GIT_PATH_REJECT_DEFAULTS \
|
463
|
+
GIT_PATH_REJECT_TRAVERSAL | \
|
464
|
+
GIT_PATH_REJECT_BACKSLASH | \
|
465
|
+
GIT_PATH_REJECT_TRAILING_DOT | \
|
466
|
+
GIT_PATH_REJECT_TRAILING_SPACE | \
|
467
|
+
GIT_PATH_REJECT_TRAILING_COLON | \
|
468
|
+
GIT_PATH_REJECT_DOS_PATHS | \
|
469
|
+
GIT_PATH_REJECT_NT_CHARS
|
470
|
+
#else
|
471
|
+
# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
|
472
|
+
#endif
|
473
|
+
|
474
|
+
/*
|
475
|
+
* Determine whether a path is a valid git path or not - this must not contain
|
476
|
+
* a '.' or '..' component, or a component that is ".git" (in any case).
|
477
|
+
*
|
478
|
+
* `repo` is optional. If specified, it will be used to determine the short
|
479
|
+
* path name to reject (if `GIT_PATH_REJECT_DOS_SHORTNAME` is specified),
|
480
|
+
* in addition to the default of "git~1".
|
481
|
+
*/
|
482
|
+
extern bool git_path_isvalid(
|
483
|
+
git_repository *repo,
|
484
|
+
const char *path,
|
485
|
+
unsigned int flags);
|
486
|
+
|
444
487
|
#endif
|
@@ -707,11 +707,16 @@ static int reference_path_available(
|
|
707
707
|
|
708
708
|
static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name)
|
709
709
|
{
|
710
|
-
|
710
|
+
int error;
|
711
711
|
git_buf ref_path = GIT_BUF_INIT;
|
712
712
|
|
713
713
|
assert(file && backend && name);
|
714
714
|
|
715
|
+
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_DEFAULTS)) {
|
716
|
+
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name);
|
717
|
+
return GIT_EINVALIDSPEC;
|
718
|
+
}
|
719
|
+
|
715
720
|
/* Remove a possibly existing empty directory hierarchy
|
716
721
|
* which name would collide with the reference name
|
717
722
|
*/
|
@@ -1573,6 +1578,11 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
|
|
1573
1578
|
|
1574
1579
|
repo = backend->repo;
|
1575
1580
|
|
1581
|
+
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_DEFAULTS)) {
|
1582
|
+
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname);
|
1583
|
+
return GIT_EINVALIDSPEC;
|
1584
|
+
}
|
1585
|
+
|
1576
1586
|
if (retrieve_reflog_path(&log_path, repo, refname) < 0)
|
1577
1587
|
return -1;
|
1578
1588
|
|
@@ -37,6 +37,9 @@
|
|
37
37
|
|
38
38
|
#define GIT_REPO_VERSION 0
|
39
39
|
|
40
|
+
const char *git_repository__8dot3_default = "GIT~1";
|
41
|
+
size_t git_repository__8dot3_default_len = 5;
|
42
|
+
|
40
43
|
static void set_odb(git_repository *repo, git_odb *odb)
|
41
44
|
{
|
42
45
|
if (odb) {
|
@@ -120,6 +123,7 @@ void git_repository_free(git_repository *repo)
|
|
120
123
|
git__free(repo->path_repository);
|
121
124
|
git__free(repo->workdir);
|
122
125
|
git__free(repo->namespace);
|
126
|
+
git__free(repo->name_8dot3);
|
123
127
|
|
124
128
|
git__memzero(repo, sizeof(*repo));
|
125
129
|
git__free(repo);
|
@@ -791,6 +795,27 @@ const char *git_repository_get_namespace(git_repository *repo)
|
|
791
795
|
return repo->namespace;
|
792
796
|
}
|
793
797
|
|
798
|
+
const char *git_repository__8dot3_name(git_repository *repo)
|
799
|
+
{
|
800
|
+
if (!repo->has_8dot3) {
|
801
|
+
repo->has_8dot3 = 1;
|
802
|
+
|
803
|
+
#ifdef GIT_WIN32
|
804
|
+
if (!repo->is_bare) {
|
805
|
+
repo->name_8dot3 = git_win32_path_8dot3_name(repo->path_repository);
|
806
|
+
|
807
|
+
/* We anticipate the 8.3 name is "GIT~1", so use a static for
|
808
|
+
* easy testing in the common case */
|
809
|
+
if (strcasecmp(repo->name_8dot3, git_repository__8dot3_default) == 0)
|
810
|
+
repo->has_8dot3_default = 1;
|
811
|
+
}
|
812
|
+
#endif
|
813
|
+
}
|
814
|
+
|
815
|
+
return repo->has_8dot3_default ?
|
816
|
+
git_repository__8dot3_default : repo->name_8dot3;
|
817
|
+
}
|
818
|
+
|
794
819
|
static int check_repositoryformatversion(git_config *config)
|
795
820
|
{
|
796
821
|
int version;
|
@@ -40,6 +40,8 @@ typedef enum {
|
|
40
40
|
GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */
|
41
41
|
GIT_CVAR_SAFE_CRLF, /* core.safecrlf */
|
42
42
|
GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */
|
43
|
+
GIT_CVAR_PROTECTHFS, /* core.protectHFS */
|
44
|
+
GIT_CVAR_PROTECTNTFS, /* core.protectNTFS */
|
43
45
|
GIT_CVAR_CACHE_MAX
|
44
46
|
} git_cvar_cached;
|
45
47
|
|
@@ -96,6 +98,10 @@ typedef enum {
|
|
96
98
|
/* core.logallrefupdates */
|
97
99
|
GIT_LOGALLREFUPDATES_UNSET = 2,
|
98
100
|
GIT_LOGALLREFUPDATES_DEFAULT = GIT_LOGALLREFUPDATES_UNSET,
|
101
|
+
/* core.protectHFS */
|
102
|
+
GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE,
|
103
|
+
/* core.protectNTFS */
|
104
|
+
GIT_PROTECTNTFS_DEFAULT = GIT_CVAR_FALSE,
|
99
105
|
} git_cvar_value;
|
100
106
|
|
101
107
|
/* internal repository init flags */
|
@@ -120,8 +126,11 @@ struct git_repository {
|
|
120
126
|
char *path_repository;
|
121
127
|
char *workdir;
|
122
128
|
char *namespace;
|
129
|
+
char *name_8dot3;
|
123
130
|
|
124
|
-
unsigned is_bare:1
|
131
|
+
unsigned is_bare:1,
|
132
|
+
has_8dot3:1,
|
133
|
+
has_8dot3_default:1;
|
125
134
|
unsigned int lru_counter;
|
126
135
|
|
127
136
|
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
@@ -172,4 +181,19 @@ GIT_INLINE(int) git_repository__ensure_not_bare(
|
|
172
181
|
|
173
182
|
int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len);
|
174
183
|
|
184
|
+
/*
|
185
|
+
* Gets the DOS-compatible 8.3 "short name". This will return only the
|
186
|
+
* short name for the repository directory (ie, "git~1" for ".git"). This
|
187
|
+
* will always return a pointer to `git_repository__8dot3_default` when
|
188
|
+
* "GIT~1" is the short name. This will return NULL for bare repositories,
|
189
|
+
* and systems that do not have a short name.
|
190
|
+
*/
|
191
|
+
const char *git_repository__8dot3_name(git_repository *repo);
|
192
|
+
|
193
|
+
/* The default DOS-compatible 8.3 "short name" for a git repository,
|
194
|
+
* "GIT~1".
|
195
|
+
*/
|
196
|
+
extern const char *git_repository__8dot3_default;
|
197
|
+
extern size_t git_repository__8dot3_default_len;
|
198
|
+
|
175
199
|
#endif
|
data/vendor/libgit2/src/tree.c
CHANGED
@@ -55,7 +55,7 @@ static int valid_entry_name(const char *filename)
|
|
55
55
|
(*filename != '.' ||
|
56
56
|
(strcmp(filename, ".") != 0 &&
|
57
57
|
strcmp(filename, "..") != 0 &&
|
58
|
-
|
58
|
+
strcasecmp(filename, DOT_GIT) != 0));
|
59
59
|
}
|
60
60
|
|
61
61
|
static int entry_sort_cmp(const void *a, const void *b)
|
data/vendor/libgit2/src/util.c
CHANGED
@@ -250,6 +250,21 @@ int git__prefixcmp_icase(const char *str, const char *prefix)
|
|
250
250
|
return strncasecmp(str, prefix, strlen(prefix));
|
251
251
|
}
|
252
252
|
|
253
|
+
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
|
254
|
+
{
|
255
|
+
int s, p;
|
256
|
+
|
257
|
+
while(str_n--) {
|
258
|
+
s = (unsigned char)tolower(*str++);
|
259
|
+
p = (unsigned char)tolower(*prefix++);
|
260
|
+
|
261
|
+
if (s != p)
|
262
|
+
return s - p;
|
263
|
+
}
|
264
|
+
|
265
|
+
return (0 - *prefix);
|
266
|
+
}
|
267
|
+
|
253
268
|
int git__suffixcmp(const char *str, const char *suffix)
|
254
269
|
{
|
255
270
|
size_t a = strlen(str);
|
@@ -648,3 +663,79 @@ void git__insertsort_r(
|
|
648
663
|
if (freeswap)
|
649
664
|
git__free(swapel);
|
650
665
|
}
|
666
|
+
|
667
|
+
static const int8_t utf8proc_utf8class[256] = {
|
668
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
669
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
670
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
671
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
672
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
673
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
674
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
675
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
676
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
677
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
678
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
679
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
680
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
681
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
682
|
+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
683
|
+
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
|
684
|
+
};
|
685
|
+
|
686
|
+
int git__utf8_charlen(const uint8_t *str, int str_len)
|
687
|
+
{
|
688
|
+
int length, i;
|
689
|
+
|
690
|
+
length = utf8proc_utf8class[str[0]];
|
691
|
+
if (!length)
|
692
|
+
return -1;
|
693
|
+
|
694
|
+
if (str_len >= 0 && length > str_len)
|
695
|
+
return -str_len;
|
696
|
+
|
697
|
+
for (i = 1; i < length; i++) {
|
698
|
+
if ((str[i] & 0xC0) != 0x80)
|
699
|
+
return -i;
|
700
|
+
}
|
701
|
+
|
702
|
+
return length;
|
703
|
+
}
|
704
|
+
|
705
|
+
int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst)
|
706
|
+
{
|
707
|
+
int length;
|
708
|
+
int32_t uc = -1;
|
709
|
+
|
710
|
+
*dst = -1;
|
711
|
+
length = git__utf8_charlen(str, str_len);
|
712
|
+
if (length < 0)
|
713
|
+
return -1;
|
714
|
+
|
715
|
+
switch (length) {
|
716
|
+
case 1:
|
717
|
+
uc = str[0];
|
718
|
+
break;
|
719
|
+
case 2:
|
720
|
+
uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
|
721
|
+
if (uc < 0x80) uc = -1;
|
722
|
+
break;
|
723
|
+
case 3:
|
724
|
+
uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
|
725
|
+
+ (str[2] & 0x3F);
|
726
|
+
if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
|
727
|
+
(uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
|
728
|
+
break;
|
729
|
+
case 4:
|
730
|
+
uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
|
731
|
+
+ ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
|
732
|
+
if (uc < 0x10000 || uc >= 0x110000) uc = -1;
|
733
|
+
break;
|
734
|
+
}
|
735
|
+
|
736
|
+
if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE))
|
737
|
+
return -1;
|
738
|
+
|
739
|
+
*dst = uc;
|
740
|
+
return length;
|
741
|
+
}
|
data/vendor/libgit2/src/util.h
CHANGED
@@ -106,6 +106,7 @@ GIT_INLINE(void) git__free(void *ptr)
|
|
106
106
|
|
107
107
|
extern int git__prefixcmp(const char *str, const char *prefix);
|
108
108
|
extern int git__prefixcmp_icase(const char *str, const char *prefix);
|
109
|
+
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
|
109
110
|
extern int git__suffixcmp(const char *str, const char *suffix);
|
110
111
|
|
111
112
|
GIT_INLINE(int) git__signum(int val)
|
@@ -366,6 +367,17 @@ extern int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date);
|
|
366
367
|
*/
|
367
368
|
extern size_t git__unescape(char *str);
|
368
369
|
|
370
|
+
/*
|
371
|
+
* Iterate through an UTF-8 string, yielding one
|
372
|
+
* codepoint at a time.
|
373
|
+
*
|
374
|
+
* @param str current position in the string
|
375
|
+
* @param str_len size left in the string; -1 if the string is NULL-terminated
|
376
|
+
* @param dst pointer where to store the current codepoint
|
377
|
+
* @return length in bytes of the read codepoint; -1 if the codepoint was invalid
|
378
|
+
*/
|
379
|
+
extern int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst);
|
380
|
+
|
369
381
|
/*
|
370
382
|
* Safely zero-out memory, making sure that the compiler
|
371
383
|
* doesn't optimize away the operation.
|
@@ -0,0 +1,305 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
3
|
+
*
|
4
|
+
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
5
|
+
* a Linking Exception. For full terms see the included COPYING file.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "common.h"
|
9
|
+
#include "path.h"
|
10
|
+
#include "path_w32.h"
|
11
|
+
#include "utf-conv.h"
|
12
|
+
|
13
|
+
#define PATH__NT_NAMESPACE L"\\\\?\\"
|
14
|
+
#define PATH__NT_NAMESPACE_LEN 4
|
15
|
+
|
16
|
+
#define PATH__ABSOLUTE_LEN 3
|
17
|
+
|
18
|
+
#define path__is_dirsep(p) ((p) == '/' || (p) == '\\')
|
19
|
+
|
20
|
+
#define path__is_absolute(p) \
|
21
|
+
(git__isalpha((p)[0]) && (p)[1] == ':' && ((p)[2] == '\\' || (p)[2] == '/'))
|
22
|
+
|
23
|
+
#define path__is_nt_namespace(p) \
|
24
|
+
(((p)[0] == '\\' && (p)[1] == '\\' && (p)[2] == '?' && (p)[3] == '\\') || \
|
25
|
+
((p)[0] == '/' && (p)[1] == '/' && (p)[2] == '?' && (p)[3] == '/'))
|
26
|
+
|
27
|
+
#define path__is_unc(p) \
|
28
|
+
(((p)[0] == '\\' && (p)[1] == '\\') || ((p)[0] == '/' && (p)[1] == '/'))
|
29
|
+
|
30
|
+
GIT_INLINE(int) path__cwd(wchar_t *path, int size)
|
31
|
+
{
|
32
|
+
int len;
|
33
|
+
|
34
|
+
if ((len = GetCurrentDirectoryW(size, path)) == 0) {
|
35
|
+
errno = GetLastError() == ERROR_ACCESS_DENIED ? EACCES : ENOENT;
|
36
|
+
return -1;
|
37
|
+
} else if (len > size) {
|
38
|
+
errno = ENAMETOOLONG;
|
39
|
+
return -1;
|
40
|
+
}
|
41
|
+
|
42
|
+
/* The Win32 APIs may return "\\?\" once you've used it first.
|
43
|
+
* But it may not. What a gloriously predictible API!
|
44
|
+
*/
|
45
|
+
if (wcsncmp(path, PATH__NT_NAMESPACE, PATH__NT_NAMESPACE_LEN))
|
46
|
+
return len;
|
47
|
+
|
48
|
+
len -= PATH__NT_NAMESPACE_LEN;
|
49
|
+
|
50
|
+
memmove(path, path + PATH__NT_NAMESPACE_LEN, sizeof(wchar_t) * len);
|
51
|
+
return len;
|
52
|
+
}
|
53
|
+
|
54
|
+
static wchar_t *path__skip_server(wchar_t *path)
|
55
|
+
{
|
56
|
+
wchar_t *c;
|
57
|
+
|
58
|
+
for (c = path; *c; c++) {
|
59
|
+
if (path__is_dirsep(*c))
|
60
|
+
return c + 1;
|
61
|
+
}
|
62
|
+
|
63
|
+
return c;
|
64
|
+
}
|
65
|
+
|
66
|
+
static wchar_t *path__skip_prefix(wchar_t *path)
|
67
|
+
{
|
68
|
+
if (path__is_nt_namespace(path)) {
|
69
|
+
path += PATH__NT_NAMESPACE_LEN;
|
70
|
+
|
71
|
+
if (wcsncmp(path, L"UNC\\", 4) == 0)
|
72
|
+
path = path__skip_server(path + 4);
|
73
|
+
else if (path__is_absolute(path))
|
74
|
+
path += PATH__ABSOLUTE_LEN;
|
75
|
+
} else if (path__is_absolute(path)) {
|
76
|
+
path += PATH__ABSOLUTE_LEN;
|
77
|
+
} else if (path__is_unc(path)) {
|
78
|
+
path = path__skip_server(path + 2);
|
79
|
+
}
|
80
|
+
|
81
|
+
return path;
|
82
|
+
}
|
83
|
+
|
84
|
+
int git_win32_path_canonicalize(git_win32_path path)
|
85
|
+
{
|
86
|
+
wchar_t *base, *from, *to, *next;
|
87
|
+
size_t len;
|
88
|
+
|
89
|
+
base = to = path__skip_prefix(path);
|
90
|
+
|
91
|
+
/* Unposixify if the prefix */
|
92
|
+
for (from = path; from < to; from++) {
|
93
|
+
if (*from == L'/')
|
94
|
+
*from = L'\\';
|
95
|
+
}
|
96
|
+
|
97
|
+
while (*from) {
|
98
|
+
for (next = from; *next; ++next) {
|
99
|
+
if (*next == L'/') {
|
100
|
+
*next = L'\\';
|
101
|
+
break;
|
102
|
+
}
|
103
|
+
|
104
|
+
if (*next == L'\\')
|
105
|
+
break;
|
106
|
+
}
|
107
|
+
|
108
|
+
len = next - from;
|
109
|
+
|
110
|
+
if (len == 1 && from[0] == L'.')
|
111
|
+
/* do nothing with singleton dot */;
|
112
|
+
|
113
|
+
else if (len == 2 && from[0] == L'.' && from[1] == L'.') {
|
114
|
+
if (to == base) {
|
115
|
+
/* no more path segments to strip, eat the "../" */
|
116
|
+
if (*next == L'\\')
|
117
|
+
len++;
|
118
|
+
|
119
|
+
base = to;
|
120
|
+
} else {
|
121
|
+
/* back up a path segment */
|
122
|
+
while (to > base && to[-1] == L'\\') to--;
|
123
|
+
while (to > base && to[-1] != L'\\') to--;
|
124
|
+
}
|
125
|
+
} else {
|
126
|
+
if (*next == L'\\' && *from != L'\\')
|
127
|
+
len++;
|
128
|
+
|
129
|
+
if (to != from)
|
130
|
+
memmove(to, from, sizeof(wchar_t) * len);
|
131
|
+
|
132
|
+
to += len;
|
133
|
+
}
|
134
|
+
|
135
|
+
from += len;
|
136
|
+
|
137
|
+
while (*from == L'\\') from++;
|
138
|
+
}
|
139
|
+
|
140
|
+
/* Strip trailing backslashes */
|
141
|
+
while (to > base && to[-1] == L'\\') to--;
|
142
|
+
|
143
|
+
*to = L'\0';
|
144
|
+
|
145
|
+
return (to - path);
|
146
|
+
}
|
147
|
+
|
148
|
+
int git_win32_path__cwd(wchar_t *out, size_t len)
|
149
|
+
{
|
150
|
+
int cwd_len;
|
151
|
+
|
152
|
+
if ((cwd_len = path__cwd(out, len)) < 0)
|
153
|
+
return -1;
|
154
|
+
|
155
|
+
/* UNC paths */
|
156
|
+
if (wcsncmp(L"\\\\", out, 2) == 0) {
|
157
|
+
/* Our buffer must be at least 5 characters larger than the
|
158
|
+
* current working directory: we swallow one of the leading
|
159
|
+
* '\'s, but we we add a 'UNC' specifier to the path, plus
|
160
|
+
* a trailing directory separator, plus a NUL.
|
161
|
+
*/
|
162
|
+
if (cwd_len > MAX_PATH - 4) {
|
163
|
+
errno = ENAMETOOLONG;
|
164
|
+
return -1;
|
165
|
+
}
|
166
|
+
|
167
|
+
memmove(out+2, out, sizeof(wchar_t) * cwd_len);
|
168
|
+
out[0] = L'U';
|
169
|
+
out[1] = L'N';
|
170
|
+
out[2] = L'C';
|
171
|
+
|
172
|
+
cwd_len += 2;
|
173
|
+
}
|
174
|
+
|
175
|
+
/* Our buffer must be at least 2 characters larger than the current
|
176
|
+
* working directory. (One character for the directory separator,
|
177
|
+
* one for the null.
|
178
|
+
*/
|
179
|
+
else if (cwd_len > MAX_PATH - 2) {
|
180
|
+
errno = ENAMETOOLONG;
|
181
|
+
return -1;
|
182
|
+
}
|
183
|
+
|
184
|
+
return cwd_len;
|
185
|
+
}
|
186
|
+
|
187
|
+
int git_win32_path_from_utf8(git_win32_path out, const char *src)
|
188
|
+
{
|
189
|
+
wchar_t *dest = out;
|
190
|
+
|
191
|
+
/* All win32 paths are in NT-prefixed format, beginning with "\\?\". */
|
192
|
+
memcpy(dest, PATH__NT_NAMESPACE, sizeof(wchar_t) * PATH__NT_NAMESPACE_LEN);
|
193
|
+
dest += PATH__NT_NAMESPACE_LEN;
|
194
|
+
|
195
|
+
/* See if this is an absolute path (beginning with a drive letter) */
|
196
|
+
if (path__is_absolute(src)) {
|
197
|
+
if (git__utf8_to_16(dest, MAX_PATH, src) < 0)
|
198
|
+
return -1;
|
199
|
+
}
|
200
|
+
/* File-prefixed NT-style paths beginning with \\?\ */
|
201
|
+
else if (path__is_nt_namespace(src)) {
|
202
|
+
/* Skip the NT prefix, the destination already contains it */
|
203
|
+
if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0)
|
204
|
+
return -1;
|
205
|
+
}
|
206
|
+
/* UNC paths */
|
207
|
+
else if (path__is_unc(src)) {
|
208
|
+
memcpy(dest, L"UNC\\", sizeof(wchar_t) * 4);
|
209
|
+
dest += 4;
|
210
|
+
|
211
|
+
/* Skip the leading "\\" */
|
212
|
+
if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0)
|
213
|
+
return -1;
|
214
|
+
}
|
215
|
+
/* Absolute paths omitting the drive letter */
|
216
|
+
else if (src[0] == '\\' || src[0] == '/') {
|
217
|
+
if (path__cwd(dest, MAX_PATH) < 0)
|
218
|
+
return -1;
|
219
|
+
|
220
|
+
if (!path__is_absolute(dest)) {
|
221
|
+
errno = ENOENT;
|
222
|
+
return -1;
|
223
|
+
}
|
224
|
+
|
225
|
+
/* Skip the drive letter specification ("C:") */
|
226
|
+
if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0)
|
227
|
+
return -1;
|
228
|
+
}
|
229
|
+
/* Relative paths */
|
230
|
+
else {
|
231
|
+
int cwd_len;
|
232
|
+
|
233
|
+
if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0)
|
234
|
+
return -1;
|
235
|
+
|
236
|
+
dest[cwd_len++] = L'\\';
|
237
|
+
|
238
|
+
if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0)
|
239
|
+
return -1;
|
240
|
+
}
|
241
|
+
|
242
|
+
return git_win32_path_canonicalize(out);
|
243
|
+
}
|
244
|
+
|
245
|
+
int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
|
246
|
+
{
|
247
|
+
char *out = dest;
|
248
|
+
int len;
|
249
|
+
|
250
|
+
/* Strip NT namespacing "\\?\" */
|
251
|
+
if (path__is_nt_namespace(src)) {
|
252
|
+
src += 4;
|
253
|
+
|
254
|
+
/* "\\?\UNC\server\share" -> "\\server\share" */
|
255
|
+
if (wcsncmp(src, L"UNC\\", 4) == 0) {
|
256
|
+
src += 4;
|
257
|
+
|
258
|
+
memcpy(dest, "\\\\", 2);
|
259
|
+
out = dest + 2;
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
if ((len = git__utf16_to_8(out, GIT_WIN_PATH_UTF8, src)) < 0)
|
264
|
+
return len;
|
265
|
+
|
266
|
+
git_path_mkposix(dest);
|
267
|
+
|
268
|
+
return len;
|
269
|
+
}
|
270
|
+
|
271
|
+
char *git_win32_path_8dot3_name(const char *path)
|
272
|
+
{
|
273
|
+
git_win32_path longpath, shortpath;
|
274
|
+
wchar_t *start;
|
275
|
+
char *shortname;
|
276
|
+
int len, namelen = 1;
|
277
|
+
|
278
|
+
if (git_win32_path_from_utf8(longpath, path) < 0)
|
279
|
+
return NULL;
|
280
|
+
|
281
|
+
len = GetShortPathNameW(longpath, shortpath, GIT_WIN_PATH_UTF16);
|
282
|
+
|
283
|
+
while (len && shortpath[len-1] == L'\\')
|
284
|
+
shortpath[--len] = L'\0';
|
285
|
+
|
286
|
+
if (len == 0 || len >= GIT_WIN_PATH_UTF16)
|
287
|
+
return NULL;
|
288
|
+
|
289
|
+
for (start = shortpath + (len - 1);
|
290
|
+
start > shortpath && *(start-1) != '/' && *(start-1) != '\\';
|
291
|
+
start--)
|
292
|
+
namelen++;
|
293
|
+
|
294
|
+
/* We may not have actually been given a short name. But if we have,
|
295
|
+
* it will be in the ASCII byte range, so we don't need to worry about
|
296
|
+
* multi-byte sequences and can allocate naively.
|
297
|
+
*/
|
298
|
+
if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL)
|
299
|
+
return NULL;
|
300
|
+
|
301
|
+
if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0)
|
302
|
+
return NULL;
|
303
|
+
|
304
|
+
return shortname;
|
305
|
+
}
|