]> git.proxmox.com Git - libgit2.git/blame - src/win32/posix_w32.c
Removing test whose results are platform-dependent.
[libgit2.git] / src / win32 / posix_w32.c
CommitLineData
e1de726c 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
bb742ede
VM
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 */
44ef8b1b 7#include "../posix.h"
5ad739e8 8#include "path.h"
11d51ca6 9#include "utf-conv.h"
f79026b4 10#include <errno.h>
f978b748 11#include <io.h>
7998ae5a
PB
12#include <fcntl.h>
13
f79026b4
VM
14
15int p_unlink(const char *path)
16{
7998ae5a
PB
17 int ret = 0;
18 wchar_t* buf;
19
deafee7b
RB
20 if ((buf = gitwin_to_utf16(path)) != NULL) {
21 _wchmod(buf, 0666);
22 ret = _wunlink(buf);
23 git__free(buf);
24 }
7998ae5a
PB
25
26 return ret;
f79026b4
VM
27}
28
29int p_fsync(int fd)
30{
31 HANDLE fh = (HANDLE)_get_osfhandle(fd);
32
33 if (fh == INVALID_HANDLE_VALUE) {
34 errno = EBADF;
35 return -1;
36 }
37
38 if (!FlushFileBuffers(fh)) {
39 DWORD code = GetLastError();
40
41 if (code == ERROR_INVALID_HANDLE)
42 errno = EINVAL;
43 else
44 errno = EIO;
45
46 return -1;
47 }
48
49 return 0;
50}
51
52GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
53{
54 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
55 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
56 winTime /= 10000000; /* Nano to seconds resolution */
57 return (time_t)winTime;
58}
59
60static int do_lstat(const char *file_name, struct stat *buf)
61{
62 WIN32_FILE_ATTRIBUTE_DATA fdata;
11d51ca6 63 wchar_t* fbuf = gitwin_to_utf16(file_name);
deafee7b
RB
64 if (!fbuf)
65 return -1;
f79026b4 66
7998ae5a 67 if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
f79026b4
VM
68 int fMode = S_IREAD;
69
70 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
71 fMode |= S_IFDIR;
72 else
73 fMode |= S_IFREG;
74
75 if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
76 fMode |= S_IWRITE;
77
78 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
79 fMode |= S_IFLNK;
80
81 buf->st_ino = 0;
82 buf->st_gid = 0;
83 buf->st_uid = 0;
84 buf->st_nlink = 1;
85 buf->st_mode = (mode_t)fMode;
fdc8a7db 86 buf->st_size = ((git_off_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow;
f79026b4
VM
87 buf->st_dev = buf->st_rdev = (_getdrive() - 1);
88 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
89 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
90 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
7998ae5a 91
3286c408 92 git__free(fbuf);
deafee7b 93 return 0;
f79026b4
VM
94 }
95
3286c408 96 git__free(fbuf);
deafee7b 97 return -1;
f79026b4
VM
98}
99
100int p_lstat(const char *file_name, struct stat *buf)
101{
deafee7b
RB
102 int error;
103 size_t namelen;
104 char *alt_name;
f79026b4 105
deafee7b
RB
106 if (do_lstat(file_name, buf) == 0)
107 return 0;
f79026b4
VM
108
109 /* if file_name ended in a '/', Windows returned ENOENT;
110 * try again without trailing slashes
111 */
f79026b4
VM
112 namelen = strlen(file_name);
113 if (namelen && file_name[namelen-1] != '/')
deafee7b 114 return -1;
f79026b4
VM
115
116 while (namelen && file_name[namelen-1] == '/')
117 --namelen;
118
deafee7b
RB
119 if (!namelen)
120 return -1;
121
122 alt_name = git__strndup(file_name, namelen);
123 if (!alt_name)
124 return -1;
125
126 error = do_lstat(alt_name, buf);
f79026b4 127
deafee7b
RB
128 git__free(alt_name);
129 return error;
f79026b4
VM
130}
131
132int p_readlink(const char *link, char *target, size_t target_len)
133{
7998ae5a 134 typedef DWORD (WINAPI *fpath_func)(HANDLE, LPWSTR, DWORD, DWORD);
f79026b4
VM
135 static fpath_func pGetFinalPath = NULL;
136 HANDLE hFile;
137 DWORD dwRet;
7998ae5a
PB
138 wchar_t* link_w;
139 wchar_t* target_w;
deafee7b
RB
140 int error = 0;
141
142 assert(link && target && target_len > 0);
f79026b4
VM
143
144 /*
145 * Try to load the pointer to pGetFinalPath dynamically, because
146 * it is not available in platforms older than Vista
147 */
148 if (pGetFinalPath == NULL) {
149 HINSTANCE library = LoadLibrary("kernel32");
150
151 if (library != NULL)
7998ae5a 152 pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW");
f79026b4 153
deafee7b
RB
154 if (pGetFinalPath == NULL) {
155 giterr_set(GITERR_OS,
7998ae5a 156 "'GetFinalPathNameByHandleW' is not available in this platform");
deafee7b
RB
157 return -1;
158 }
f79026b4
VM
159 }
160
11d51ca6 161 link_w = gitwin_to_utf16(link);
deafee7b 162 GITERR_CHECK_ALLOC(link_w);
7998ae5a
PB
163
164 hFile = CreateFileW(link_w, // file to open
165 GENERIC_READ, // open for reading
166 FILE_SHARE_READ, // share for reading
167 NULL, // default security
168 OPEN_EXISTING, // existing file only
169 FILE_FLAG_BACKUP_SEMANTICS, // normal file
170 NULL); // no attr. template
171
3286c408 172 git__free(link_w);
f79026b4 173
deafee7b
RB
174 if (hFile == INVALID_HANDLE_VALUE) {
175 giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
176 return -1;
7998ae5a
PB
177 }
178
179 target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t));
deafee7b 180 GITERR_CHECK_ALLOC(target_w);
7998ae5a 181
44ef8b1b 182 dwRet = pGetFinalPath(hFile, target_w, (DWORD)target_len, 0x0);
deafee7b
RB
183 if (dwRet == 0 ||
184 dwRet >= target_len ||
185 !WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target,
44ef8b1b 186 (int)(target_len * sizeof(char)), NULL, NULL))
deafee7b 187 error = -1;
f79026b4 188
3286c408 189 git__free(target_w);
f79026b4
VM
190 CloseHandle(hFile);
191
deafee7b
RB
192 if (error)
193 return error;
194
195 /* Skip first 4 characters if they are "\\?\" */
196 if (dwRet > 4 &&
197 target[0] == '\\' && target[1] == '\\' &&
198 target[2] == '?' && target[3] == '\\')
199 {
200 unsigned int offset = 4;
201 dwRet -= 4;
202
203 /* \??\UNC\ */
204 if (dwRet > 7 &&
205 target[4] == 'U' && target[5] == 'N' && target[6] == 'C')
206 {
207 offset += 2;
208 dwRet -= 2;
209 target[offset] = '\\';
f79026b4 210 }
deafee7b
RB
211
212 memmove(target, target + offset, dwRet);
f79026b4
VM
213 }
214
215 target[dwRet] = '\0';
deafee7b 216
f79026b4
VM
217 return dwRet;
218}
219
3191ae89 220int p_open(const char *path, int flags, ...)
7998ae5a
PB
221{
222 int fd;
3191ae89 223 wchar_t* buf;
224 mode_t mode = 0;
225
226 buf = gitwin_to_utf16(path);
deafee7b
RB
227 if (!buf)
228 return -1;
3191ae89 229
230 if (flags & O_CREAT)
231 {
232 va_list arg_list;
233
234 va_start(arg_list, flags);
235 mode = va_arg(arg_list, mode_t);
236 va_end(arg_list);
237 }
238
239 fd = _wopen(buf, flags | _O_BINARY, mode);
240
3286c408 241 git__free(buf);
7998ae5a
PB
242 return fd;
243}
244
33127043 245int p_creat(const char *path, mode_t mode)
7998ae5a
PB
246{
247 int fd;
11d51ca6 248 wchar_t* buf = gitwin_to_utf16(path);
deafee7b
RB
249 if (!buf)
250 return -1;
7998ae5a 251 fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
3286c408 252 git__free(buf);
7998ae5a
PB
253 return fd;
254}
255
256int p_getcwd(char *buffer_out, size_t size)
257{
deafee7b 258 int ret;
44ef8b1b
RB
259 wchar_t* buf;
260
261 if ((size_t)((int)size) != size)
262 return -1;
263
264 buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size);
265 GITERR_CHECK_ALLOC(buf);
deafee7b 266
7998ae5a
PB
267 _wgetcwd(buf, (int)size);
268
deafee7b 269 ret = WideCharToMultiByte(
44ef8b1b 270 CP_UTF8, 0, buf, -1, buffer_out, (int)size, NULL, NULL);
7998ae5a 271
3286c408 272 git__free(buf);
deafee7b 273 return !ret ? -1 : 0;
7998ae5a
PB
274}
275
276int p_stat(const char* path, struct stat* buf)
277{
278 return do_lstat(path, buf);
279}
280
281int p_chdir(const char* path)
282{
11d51ca6 283 wchar_t* buf = gitwin_to_utf16(path);
deafee7b
RB
284 int ret;
285 if (!buf)
286 return -1;
287 ret = _wchdir(buf);
3286c408 288 git__free(buf);
7998ae5a
PB
289 return ret;
290}
291
33127043 292int p_chmod(const char* path, mode_t mode)
7998ae5a 293{
11d51ca6 294 wchar_t* buf = gitwin_to_utf16(path);
deafee7b
RB
295 int ret;
296 if (!buf)
297 return -1;
298 ret = _wchmod(buf, mode);
3286c408 299 git__free(buf);
7998ae5a
PB
300 return ret;
301}
302
303int p_rmdir(const char* path)
304{
11d51ca6 305 wchar_t* buf = gitwin_to_utf16(path);
deafee7b
RB
306 int ret;
307 if (!buf)
308 return -1;
309 ret = _wrmdir(buf);
3286c408 310 git__free(buf);
7998ae5a
PB
311 return ret;
312}
313
f79026b4
VM
314int p_hide_directory__w32(const char *path)
315{
cb8a7961 316 int res;
11d51ca6 317 wchar_t* buf = gitwin_to_utf16(path);
deafee7b
RB
318 if (!buf)
319 return -1;
f79026b4 320
cb8a7961 321 res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
3286c408 322 git__free(buf);
deafee7b
RB
323
324 return (res != 0) ? 0 : -1; /* MSDN states a "non zero" value indicates a success */
f79026b4
VM
325}
326
19ac1ed7 327char *p_realpath(const char *orig_path, char *buffer)
5ad739e8 328{
9abb5bca 329 int ret, buffer_sz = 0;
11d51ca6 330 wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
7998ae5a
PB
331 wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
332
deafee7b
RB
333 if (!orig_path_w || !buffer_w)
334 return NULL;
335
7998ae5a 336 ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
3286c408 337 git__free(orig_path_w);
7998ae5a 338
9abb5bca 339 /* According to MSDN, a return value equals to zero means a failure. */
340 if (ret == 0 || ret > GIT_PATH_MAX) {
97769280
RB
341 buffer = NULL;
342 goto done;
19ac1ed7 343 }
5ad739e8 344
97769280 345 if (buffer == NULL) {
9abb5bca 346 buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL);
97769280
RB
347
348 if (!buffer_sz ||
349 !(buffer = (char *)git__malloc(buffer_sz)) ||
350 !WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, buffer_sz, NULL, NULL))
351 {
352 git__free(buffer);
353 buffer = NULL;
9abb5bca 354 goto done;
97769280
RB
355 }
356 } else {
9abb5bca 357 if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) {
97769280 358 buffer = NULL;
9abb5bca 359 goto done;
360 }
361 }
362
363 if (!git_path_exists(buffer))
364 {
365 if (buffer_sz > 0)
366 git__free(buffer);
367
368 buffer = NULL;
369 errno = ENOENT;
7998ae5a 370 }
97769280
RB
371
372done:
3286c408 373 git__free(buffer_w);
97769280
RB
374 if (buffer)
375 git_path_mkposix(buffer);
19ac1ed7 376 return buffer;
5ad739e8
VM
377}
378
2fc78e70
VM
379int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
380{
ae2e4c6a 381#ifdef _MSC_VER
60bc2d20
VM
382 int len;
383
384 if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0)
e1de726c 385 return _vscprintf(format, argptr);
60bc2d20
VM
386
387 return len;
2fc78e70
VM
388#else /* MinGW */
389 return vsnprintf(buffer, count, format, argptr);
390#endif
391}
84dd3820
VM
392
393int p_snprintf(char *buffer, size_t count, const char *format, ...)
394{
395 va_list va;
396 int r;
397
398 va_start(va, format);
399 r = p_vsnprintf(buffer, count, format, va);
400 va_end(va);
401
402 return r;
403}
f978b748 404
33127043 405extern int p_creat(const char *path, mode_t mode);
2fcf9c82 406
f978b748
VM
407int p_mkstemp(char *tmp_path)
408{
f978b748 409#if defined(_MSC_VER)
489c3666 410 if (_mktemp_s(tmp_path, strlen(tmp_path) + 1) != 0)
deafee7b 411 return -1;
f978b748 412#else
c035ede2 413 if (_mktemp(tmp_path) == NULL)
deafee7b 414 return -1;
c035ede2 415#endif
f978b748
VM
416
417 return p_creat(tmp_path, 0744);
418}
222d057c
PB
419
420int p_setenv(const char* name, const char* value, int overwrite)
421{
422 if (overwrite != 1)
deafee7b 423 return -1;
222d057c 424
deafee7b 425 return (SetEnvironmentVariableA(name, value) == 0 ? -1 : 0);
222d057c 426}
dd44887a 427
33127043 428int p_access(const char* path, mode_t mode)
dd44887a 429{
11d51ca6 430 wchar_t *buf = gitwin_to_utf16(path);
dd44887a 431 int ret;
deafee7b
RB
432 if (!buf)
433 return -1;
dd44887a
CMN
434
435 ret = _waccess(buf, mode);
3286c408 436 git__free(buf);
dd44887a
CMN
437
438 return ret;
439}
0c49ec2d 440
deafee7b 441int p_rename(const char *from, const char *to)
0c49ec2d
CMN
442{
443 wchar_t *wfrom = gitwin_to_utf16(from);
444 wchar_t *wto = gitwin_to_utf16(to);
445 int ret;
446
deafee7b
RB
447 if (!wfrom || !wto)
448 return -1;
449
450 ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
0c49ec2d
CMN
451
452 git__free(wfrom);
453 git__free(wto);
454
455 return ret;
456}
44ef8b1b
RB
457
458int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
459{
460 if ((size_t)((int)length) != length)
461 return -1; /* giterr_set will be done by caller */
462
463 return recv(socket, buffer, (int)length, flags);
464}
465
466int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags)
467{
468 if ((size_t)((int)length) != length)
469 return -1; /* giterr_set will be done by caller */
470
471 return send(socket, buffer, (int)length, flags);
472}