]> git.proxmox.com Git - libgit2.git/blame - src/win32/posix_w32.c
Merge pull request #464 from rtyley/development
[libgit2.git] / src / win32 / posix_w32.c
CommitLineData
bb742ede
VM
1/*
2 * Copyright (C) 2009-2011 the libgit2 contributors
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 */
f79026b4 7#include "posix.h"
5ad739e8 8#include "path.h"
7998ae5a 9#include "utf8-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
20 buf = conv_utf8_to_utf16(path);
21 _wchmod(buf, 0666);
22 ret = _wunlink(buf);
23 free(buf);
24
25 return ret;
f79026b4
VM
26}
27
28int p_fsync(int fd)
29{
30 HANDLE fh = (HANDLE)_get_osfhandle(fd);
31
32 if (fh == INVALID_HANDLE_VALUE) {
33 errno = EBADF;
34 return -1;
35 }
36
37 if (!FlushFileBuffers(fh)) {
38 DWORD code = GetLastError();
39
40 if (code == ERROR_INVALID_HANDLE)
41 errno = EINVAL;
42 else
43 errno = EIO;
44
45 return -1;
46 }
47
48 return 0;
49}
50
51GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
52{
53 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
54 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
55 winTime /= 10000000; /* Nano to seconds resolution */
56 return (time_t)winTime;
57}
58
59static int do_lstat(const char *file_name, struct stat *buf)
60{
61 WIN32_FILE_ATTRIBUTE_DATA fdata;
7998ae5a 62 wchar_t* fbuf = conv_utf8_to_utf16(file_name);
f79026b4 63
7998ae5a 64 if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
f79026b4
VM
65 int fMode = S_IREAD;
66
67 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
68 fMode |= S_IFDIR;
69 else
70 fMode |= S_IFREG;
71
72 if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
73 fMode |= S_IWRITE;
74
75 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
76 fMode |= S_IFLNK;
77
78 buf->st_ino = 0;
79 buf->st_gid = 0;
80 buf->st_uid = 0;
81 buf->st_nlink = 1;
82 buf->st_mode = (mode_t)fMode;
83 buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
84 buf->st_dev = buf->st_rdev = (_getdrive() - 1);
85 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
86 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
87 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
7998ae5a
PB
88
89 free(fbuf);
f79026b4
VM
90 return GIT_SUCCESS;
91 }
92
7998ae5a 93 free(fbuf);
f79026b4 94
7998ae5a
PB
95 switch (GetLastError()) {
96 case ERROR_ACCESS_DENIED:
97 case ERROR_SHARING_VIOLATION:
98 case ERROR_LOCK_VIOLATION:
99 case ERROR_SHARING_BUFFER_EXCEEDED:
100 return GIT_EOSERR;
101
102 case ERROR_BUFFER_OVERFLOW:
103 case ERROR_NOT_ENOUGH_MEMORY:
104 return GIT_ENOMEM;
105
106 default:
107 return GIT_EINVALIDPATH;
f79026b4
VM
108 }
109}
110
111int p_lstat(const char *file_name, struct stat *buf)
112{
113 int namelen, error;
114 char alt_name[GIT_PATH_MAX];
115
116 if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS)
117 return GIT_SUCCESS;
118
119 /* if file_name ended in a '/', Windows returned ENOENT;
120 * try again without trailing slashes
121 */
122 if (error != GIT_EINVALIDPATH)
123 return git__throw(GIT_EOSERR, "Failed to lstat file");
124
125 namelen = strlen(file_name);
126 if (namelen && file_name[namelen-1] != '/')
127 return git__throw(GIT_EOSERR, "Failed to lstat file");
128
129 while (namelen && file_name[namelen-1] == '/')
130 --namelen;
131
132 if (!namelen || namelen >= GIT_PATH_MAX)
133 return git__throw(GIT_ENOMEM, "Failed to lstat file");
134
135 memcpy(alt_name, file_name, namelen);
136 alt_name[namelen] = 0;
137 return do_lstat(alt_name, buf);
138}
139
140int p_readlink(const char *link, char *target, size_t target_len)
141{
7998ae5a 142 typedef DWORD (WINAPI *fpath_func)(HANDLE, LPWSTR, DWORD, DWORD);
f79026b4
VM
143 static fpath_func pGetFinalPath = NULL;
144 HANDLE hFile;
145 DWORD dwRet;
7998ae5a
PB
146 wchar_t* link_w;
147 wchar_t* target_w;
f79026b4
VM
148
149 /*
150 * Try to load the pointer to pGetFinalPath dynamically, because
151 * it is not available in platforms older than Vista
152 */
153 if (pGetFinalPath == NULL) {
154 HINSTANCE library = LoadLibrary("kernel32");
155
156 if (library != NULL)
7998ae5a 157 pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW");
f79026b4
VM
158
159 if (pGetFinalPath == NULL)
160 return git__throw(GIT_EOSERR,
7998ae5a 161 "'GetFinalPathNameByHandleW' is not available in this platform");
f79026b4
VM
162 }
163
7998ae5a
PB
164 link_w = conv_utf8_to_utf16(link);
165
166 hFile = CreateFileW(link_w, // file to open
167 GENERIC_READ, // open for reading
168 FILE_SHARE_READ, // share for reading
169 NULL, // default security
170 OPEN_EXISTING, // existing file only
171 FILE_FLAG_BACKUP_SEMANTICS, // normal file
172 NULL); // no attr. template
173
174 free(link_w);
f79026b4
VM
175
176 if (hFile == INVALID_HANDLE_VALUE)
177 return GIT_EOSERR;
178
7998ae5a
PB
179 if (target_len <= 0) {
180 return GIT_EINVALIDARGS;
181 }
182
183 target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t));
184
185 dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0);
186 if (dwRet >= target_len) {
187 free(target_w);
188 CloseHandle(hFile);
f79026b4 189 return GIT_ENOMEM;
7998ae5a
PB
190 }
191
192 if (!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, target_len * sizeof(char), NULL, NULL)) {
193 free(target_w);
194 return GIT_EOSERR;
195 }
f79026b4 196
7998ae5a 197 free(target_w);
f79026b4
VM
198 CloseHandle(hFile);
199
200 if (dwRet > 4) {
201 /* Skip first 4 characters if they are "\\?\" */
87d9869f 202 if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') {
f79026b4
VM
203 char tmp[GIT_PATH_MAX];
204 unsigned int offset = 4;
205 dwRet -= 4;
206
207 /* \??\UNC\ */
208 if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') {
209 offset += 2;
210 dwRet -= 2;
211 target[offset] = '\\';
212 }
213
214 memcpy(tmp, target + offset, dwRet);
215 memcpy(target, tmp, dwRet);
216 }
217 }
218
219 target[dwRet] = '\0';
220 return dwRet;
221}
222
7998ae5a
PB
223int p_open(const char *path, int flags)
224{
225 int fd;
226 wchar_t* buf = conv_utf8_to_utf16(path);
227 fd = _wopen(buf, flags | _O_BINARY);
228
229 free(buf);
230 return fd;
231}
232
233int p_creat(const char *path, int mode)
234{
235 int fd;
236 wchar_t* buf = conv_utf8_to_utf16(path);
237 fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
238
239 free(buf);
240 return fd;
241}
242
243int p_getcwd(char *buffer_out, size_t size)
244{
245 wchar_t* buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size);
246 _wgetcwd(buf, (int)size);
247
248 if (!WideCharToMultiByte(CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL)) {
249 free(buf);
250 return GIT_EOSERR;
251 }
252
253 free(buf);
254 return GIT_SUCCESS;
255}
256
257int p_stat(const char* path, struct stat* buf)
258{
259 return do_lstat(path, buf);
260}
261
262int p_chdir(const char* path)
263{
264 wchar_t* buf = conv_utf8_to_utf16(path);
265 int ret = _wchdir(buf);
266
267 free(buf);
268 return ret;
269}
270
271int p_chmod(const char* path, int mode)
272{
273 wchar_t* buf = conv_utf8_to_utf16(path);
274 int ret = _wchmod(buf, mode);
275
276 free(buf);
277 return ret;
278}
279
280int p_rmdir(const char* path)
281{
282 wchar_t* buf = conv_utf8_to_utf16(path);
283 int ret = _wrmdir(buf);
284
285 free(buf);
286 return ret;
287}
288
f79026b4
VM
289int p_hide_directory__w32(const char *path)
290{
291 int error;
7998ae5a 292 wchar_t* buf = conv_utf8_to_utf16(path);
f79026b4 293
7998ae5a 294 error = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0 ?
87d9869f 295 GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */
f79026b4 296
7998ae5a
PB
297 free(buf);
298
f79026b4
VM
299 if (error < GIT_SUCCESS)
300 error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path);
301
302 return error;
303}
304
19ac1ed7 305char *p_realpath(const char *orig_path, char *buffer)
5ad739e8 306{
19ac1ed7 307 int ret, alloc = 0;
7998ae5a
PB
308 wchar_t* orig_path_w = conv_utf8_to_utf16(orig_path);
309 wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
310
19ac1ed7
VM
311 if (buffer == NULL) {
312 buffer = (char *)git__malloc(GIT_PATH_MAX);
313 alloc = 1;
314 }
315
7998ae5a
PB
316 ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
317 free(orig_path_w);
318
19ac1ed7 319 if (!ret || ret > GIT_PATH_MAX) {
7998ae5a 320 free(buffer_w);
19ac1ed7 321 if (alloc) free(buffer);
7998ae5a 322
19ac1ed7
VM
323 return NULL;
324 }
5ad739e8 325
7998ae5a
PB
326 if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) {
327 free(buffer_w);
328 if (alloc) free(buffer);
329 }
330
331 free(buffer_w);
5ad739e8 332 git_path_mkposix(buffer);
19ac1ed7 333 return buffer;
5ad739e8
VM
334}
335
2fc78e70
VM
336int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
337{
ae2e4c6a 338#ifdef _MSC_VER
2fc78e70
VM
339 int len = _vsnprintf(buffer, count, format, argptr);
340 return (len < 0) ? _vscprintf(format, argptr) : len;
341#else /* MinGW */
342 return vsnprintf(buffer, count, format, argptr);
343#endif
344}
84dd3820
VM
345
346int p_snprintf(char *buffer, size_t count, const char *format, ...)
347{
348 va_list va;
349 int r;
350
351 va_start(va, format);
352 r = p_vsnprintf(buffer, count, format, va);
353 va_end(va);
354
355 return r;
356}
f978b748 357
2fcf9c82
VM
358extern int p_creat(const char *path, int mode);
359
f978b748
VM
360int p_mkstemp(char *tmp_path)
361{
f978b748 362#if defined(_MSC_VER)
c035ede2
VM
363 if (_mktemp_s(tmp_path, GIT_PATH_MAX) != 0)
364 return GIT_EOSERR;
f978b748 365#else
c035ede2 366 if (_mktemp(tmp_path) == NULL)
f978b748 367 return GIT_EOSERR;
c035ede2 368#endif
f978b748
VM
369
370 return p_creat(tmp_path, 0744);
371}
222d057c
PB
372
373int p_setenv(const char* name, const char* value, int overwrite)
374{
375 if (overwrite != 1)
376 return EINVAL;
377
378 return (SetEnvironmentVariableA(name, value) == 0 ? GIT_EOSERR : GIT_SUCCESS);
379}
dd44887a
CMN
380
381int p_access(const char* path, int mode)
382{
383 wchar_t *buf = conv_utf8_to_utf16(path);
384 int ret;
385
386 ret = _waccess(buf, mode);
387 free(buf);
388
389 return ret;
390}