rugged 0.21.2 → 0.21.4

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.
@@ -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
+ }
@@ -0,0 +1,82 @@
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
+ #ifndef INCLUDE_git_path_w32_h__
8
+ #define INCLUDE_git_path_w32_h__
9
+
10
+ #include "common.h"
11
+
12
+ /*
13
+ * Provides a large enough buffer to support Windows paths: MAX_PATH is
14
+ * 260, corresponding to a maximum path length of 259 characters plus a
15
+ * NULL terminator. Prefixing with "\\?\" adds 4 characters, but if the
16
+ * original was a UNC path, then we turn "\\server\share" into
17
+ * "\\?\UNC\server\share". So we replace the first two characters with
18
+ * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
19
+ */
20
+ #define GIT_WIN_PATH_UTF16 MAX_PATH+6
21
+
22
+ /* Maximum size of a UTF-8 Win32 path. We remove the "\\?\" or "\\?\UNC\"
23
+ * prefixes for presentation, bringing us back to 259 (non-NULL)
24
+ * characters. UTF-8 does have 4-byte sequences, but they are encoded in
25
+ * UTF-16 using surrogate pairs, which takes up the space of two characters.
26
+ * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
27
+ * (6 bytes) than one surrogate pair (4 bytes).
28
+ */
29
+ #define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
30
+
31
+ /*
32
+ * The length of a Windows "shortname", for 8.3 compatibility.
33
+ */
34
+ #define GIT_WIN_PATH_SHORTNAME 13
35
+
36
+ /* Win32 path types */
37
+ typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
38
+ typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
39
+
40
+ /**
41
+ * Create a Win32 path (in UCS-2 format) from a UTF-8 string.
42
+ *
43
+ * @param dest The buffer to receive the wide string.
44
+ * @param src The UTF-8 string to convert.
45
+ * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
46
+ */
47
+ extern int git_win32_path_from_utf8(git_win32_path dest, const char *src);
48
+
49
+ /**
50
+ * Canonicalize a Win32 UCS-2 path so that it is suitable for delivery to the
51
+ * Win32 APIs: remove multiple directory separators, squashing to a single one,
52
+ * strip trailing directory separators, ensure directory separators are all
53
+ * canonical (always backslashes, never forward slashes) and process any
54
+ * directory entries of '.' or '..'.
55
+ *
56
+ * This processes the buffer in place.
57
+ *
58
+ * @param path The buffer to process
59
+ * @return The new length of the buffer, in wchar_t's (not counting the NULL terminator)
60
+ */
61
+ extern int git_win32_path_canonicalize(git_win32_path path);
62
+
63
+ /**
64
+ * Create an internal format (posix-style) UTF-8 path from a Win32 UCS-2 path.
65
+ *
66
+ * @param dest The buffer to receive the UTF-8 string.
67
+ * @param src The wide string to convert.
68
+ * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
69
+ */
70
+ extern int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src);
71
+
72
+ /**
73
+ * Get the short name for the terminal path component in the given path.
74
+ * For example, given "C:\Foo\Bar\Asdf.txt", this will return the short name
75
+ * for the file "Asdf.txt".
76
+ *
77
+ * @param path The given path in UTF-8
78
+ * @return The name of the shortname for the given path
79
+ */
80
+ extern char *git_win32_path_8dot3_name(const char *path);
81
+
82
+ #endif
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include "common.h"
11
11
  #include "../posix.h"
12
+ #include "path_w32.h"
12
13
  #include "utf-conv.h"
13
14
  #include "dir.h"
14
15
 
@@ -7,6 +7,7 @@
7
7
  #include "../posix.h"
8
8
  #include "../fileops.h"
9
9
  #include "path.h"
10
+ #include "path_w32.h"
10
11
  #include "utf-conv.h"
11
12
  #include "repository.h"
12
13
  #include "reparse.h"
@@ -31,29 +32,13 @@
31
32
  /* GetFinalPathNameByHandleW signature */
32
33
  typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD);
33
34
 
34
- /* Helper function which converts UTF-8 paths to UTF-16.
35
- * On failure, errno is set. */
36
- static int utf8_to_16_with_errno(git_win32_path dest, const char *src)
37
- {
38
- int len = git_win32_path_from_utf8(dest, src);
39
-
40
- if (len < 0) {
41
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
42
- errno = ENAMETOOLONG;
43
- else
44
- errno = EINVAL; /* Bad code point, presumably */
45
- }
46
-
47
- return len;
48
- }
49
-
50
35
  int p_mkdir(const char *path, mode_t mode)
51
36
  {
52
37
  git_win32_path buf;
53
38
 
54
39
  GIT_UNUSED(mode);
55
40
 
56
- if (utf8_to_16_with_errno(buf, path) < 0)
41
+ if (git_win32_path_from_utf8(buf, path) < 0)
57
42
  return -1;
58
43
 
59
44
  return _wmkdir(buf);
@@ -64,7 +49,7 @@ int p_unlink(const char *path)
64
49
  git_win32_path buf;
65
50
  int error;
66
51
 
67
- if (utf8_to_16_with_errno(buf, path) < 0)
52
+ if (git_win32_path_from_utf8(buf, path) < 0)
68
53
  return -1;
69
54
 
70
55
  error = _wunlink(buf);
@@ -271,7 +256,7 @@ static int do_lstat(const char *path, struct stat *buf, bool posixly_correct)
271
256
  git_win32_path path_w;
272
257
  int len;
273
258
 
274
- if ((len = utf8_to_16_with_errno(path_w, path)) < 0)
259
+ if ((len = git_win32_path_from_utf8(path_w, path)) < 0)
275
260
  return -1;
276
261
 
277
262
  git_win32__path_trim_end(path_w, len);
@@ -302,7 +287,7 @@ int p_readlink(const char *path, char *buf, size_t bufsiz)
302
287
  * could occur in the middle of the encoding of a code point,
303
288
  * we need to buffer the result on the stack. */
304
289
 
305
- if (utf8_to_16_with_errno(path_w, path) < 0 ||
290
+ if (git_win32_path_from_utf8(path_w, path) < 0 ||
306
291
  readlink_w(target_w, path_w) < 0 ||
307
292
  (len = git_win32_path_to_utf8(target, target_w)) < 0)
308
293
  return -1;
@@ -326,7 +311,7 @@ int p_open(const char *path, int flags, ...)
326
311
  git_win32_path buf;
327
312
  mode_t mode = 0;
328
313
 
329
- if (utf8_to_16_with_errno(buf, path) < 0)
314
+ if (git_win32_path_from_utf8(buf, path) < 0)
330
315
  return -1;
331
316
 
332
317
  if (flags & O_CREAT) {
@@ -344,7 +329,7 @@ int p_creat(const char *path, mode_t mode)
344
329
  {
345
330
  git_win32_path buf;
346
331
 
347
- if (utf8_to_16_with_errno(buf, path) < 0)
332
+ if (git_win32_path_from_utf8(buf, path) < 0)
348
333
  return -1;
349
334
 
350
335
  return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | STANDARD_OPEN_FLAGS, mode);
@@ -442,7 +427,7 @@ int p_stat(const char* path, struct stat* buf)
442
427
  git_win32_path path_w;
443
428
  int len;
444
429
 
445
- if ((len = utf8_to_16_with_errno(path_w, path)) < 0)
430
+ if ((len = git_win32_path_from_utf8(path_w, path)) < 0)
446
431
  return -1;
447
432
 
448
433
  git_win32__path_trim_end(path_w, len);
@@ -462,7 +447,7 @@ int p_chdir(const char* path)
462
447
  {
463
448
  git_win32_path buf;
464
449
 
465
- if (utf8_to_16_with_errno(buf, path) < 0)
450
+ if (git_win32_path_from_utf8(buf, path) < 0)
466
451
  return -1;
467
452
 
468
453
  return _wchdir(buf);
@@ -472,7 +457,7 @@ int p_chmod(const char* path, mode_t mode)
472
457
  {
473
458
  git_win32_path buf;
474
459
 
475
- if (utf8_to_16_with_errno(buf, path) < 0)
460
+ if (git_win32_path_from_utf8(buf, path) < 0)
476
461
  return -1;
477
462
 
478
463
  return _wchmod(buf, mode);
@@ -483,7 +468,7 @@ int p_rmdir(const char* path)
483
468
  git_win32_path buf;
484
469
  int error;
485
470
 
486
- if (utf8_to_16_with_errno(buf, path) < 0)
471
+ if (git_win32_path_from_utf8(buf, path) < 0)
487
472
  return -1;
488
473
 
489
474
  error = _wrmdir(buf);
@@ -512,7 +497,7 @@ char *p_realpath(const char *orig_path, char *buffer)
512
497
  {
513
498
  git_win32_path orig_path_w, buffer_w;
514
499
 
515
- if (utf8_to_16_with_errno(orig_path_w, orig_path) < 0)
500
+ if (git_win32_path_from_utf8(orig_path_w, orig_path) < 0)
516
501
  return NULL;
517
502
 
518
503
  /* Note that if the path provided is a relative path, then the current directory
@@ -533,20 +518,17 @@ char *p_realpath(const char *orig_path, char *buffer)
533
518
  return NULL;
534
519
  }
535
520
 
536
- /* Convert the path to UTF-8. */
537
- if (buffer) {
538
- /* If the caller provided a buffer, then it is assumed to be GIT_WIN_PATH_UTF8
539
- * characters in size. If it isn't, then we may overflow. */
540
- if (git__utf16_to_8(buffer, GIT_WIN_PATH_UTF8, buffer_w) < 0)
541
- return NULL;
542
- } else {
543
- /* If the caller did not provide a buffer, then we allocate one for the caller
544
- * from the heap. */
545
- if (git__utf16_to_8_alloc(&buffer, buffer_w) < 0)
546
- return NULL;
521
+ if (!buffer && !(buffer = git__malloc(GIT_WIN_PATH_UTF8))) {
522
+ errno = ENOMEM;
523
+ return NULL;
547
524
  }
548
525
 
549
- /* Convert backslashes to forward slashes */
526
+ /* Convert the path to UTF-8. If the caller provided a buffer, then it
527
+ * is assumed to be GIT_WIN_PATH_UTF8 characters in size. If it isn't,
528
+ * then we may overflow. */
529
+ if (git_win32_path_to_utf8(buffer, buffer_w) < 0)
530
+ return NULL;
531
+
550
532
  git_path_mkposix(buffer);
551
533
 
552
534
  return buffer;
@@ -579,6 +561,7 @@ int p_snprintf(char *buffer, size_t count, const char *format, ...)
579
561
  return r;
580
562
  }
581
563
 
564
+ /* TODO: wut? */
582
565
  int p_mkstemp(char *tmp_path)
583
566
  {
584
567
  #if defined(_MSC_VER)
@@ -596,7 +579,7 @@ int p_access(const char* path, mode_t mode)
596
579
  {
597
580
  git_win32_path buf;
598
581
 
599
- if (utf8_to_16_with_errno(buf, path) < 0)
582
+ if (git_win32_path_from_utf8(buf, path) < 0)
600
583
  return -1;
601
584
 
602
585
  return _waccess(buf, mode);
@@ -610,8 +593,8 @@ int p_rename(const char *from, const char *to)
610
593
  int rename_succeeded;
611
594
  int error;
612
595
 
613
- if (utf8_to_16_with_errno(wfrom, from) < 0 ||
614
- utf8_to_16_with_errno(wto, to) < 0)
596
+ if (git_win32_path_from_utf8(wfrom, from) < 0 ||
597
+ git_win32_path_from_utf8(wto, to) < 0)
615
598
  return -1;
616
599
 
617
600
  /* wait up to 50ms if file is locked by another thread or process */
@@ -26,6 +26,14 @@ GIT_INLINE(DWORD) get_wc_flags(void)
26
26
  return flags;
27
27
  }
28
28
 
29
+ GIT_INLINE(void) git__set_errno(void)
30
+ {
31
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
32
+ errno = ENAMETOOLONG;
33
+ else
34
+ errno = EINVAL;
35
+ }
36
+
29
37
  /**
30
38
  * Converts a UTF-8 string to wide characters.
31
39
  *
@@ -36,10 +44,15 @@ GIT_INLINE(DWORD) get_wc_flags(void)
36
44
  */
37
45
  int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
38
46
  {
47
+ int len;
48
+
39
49
  /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
40
50
  * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
41
51
  * length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */
42
- return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1;
52
+ if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0)
53
+ git__set_errno();
54
+
55
+ return len;
43
56
  }
44
57
 
45
58
  /**
@@ -52,10 +65,15 @@ int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
52
65
  */
53
66
  int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src)
54
67
  {
68
+ int len;
69
+
55
70
  /* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
56
71
  * turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
57
72
  * length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */
58
- return WideCharToMultiByte(CP_UTF8, get_wc_flags(), src, -1, dest, (int)dest_size, NULL, NULL) - 1;
73
+ if ((len = WideCharToMultiByte(CP_UTF8, get_wc_flags(), src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0)
74
+ git__set_errno();
75
+
76
+ return len;
59
77
  }
60
78
 
61
79
  /**
@@ -76,17 +94,23 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
76
94
  /* Length of -1 indicates NULL termination of the input string */
77
95
  utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0);
78
96
 
79
- if (!utf16_size)
97
+ if (!utf16_size) {
98
+ git__set_errno();
80
99
  return -1;
100
+ }
81
101
 
82
102
  *dest = git__malloc(utf16_size * sizeof(wchar_t));
83
103
 
84
- if (!*dest)
104
+ if (!*dest) {
105
+ errno = ENOMEM;
85
106
  return -1;
107
+ }
86
108
 
87
109
  utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size);
88
110
 
89
111
  if (!utf16_size) {
112
+ git__set_errno();
113
+
90
114
  git__free(*dest);
91
115
  *dest = NULL;
92
116
  }
@@ -116,17 +140,23 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
116
140
  /* Length of -1 indicates NULL termination of the input string */
117
141
  utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, NULL, 0, NULL, NULL);
118
142
 
119
- if (!utf8_size)
143
+ if (!utf8_size) {
144
+ git__set_errno();
120
145
  return -1;
146
+ }
121
147
 
122
148
  *dest = git__malloc(utf8_size);
123
149
 
124
- if (!*dest)
150
+ if (!*dest) {
151
+ errno = ENOMEM;
125
152
  return -1;
153
+ }
126
154
 
127
155
  utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, *dest, utf8_size, NULL, NULL);
128
156
 
129
157
  if (!utf8_size) {
158
+ git__set_errno();
159
+
130
160
  git__free(*dest);
131
161
  *dest = NULL;
132
162
  }