]> git.proxmox.com Git - libgit2.git/blob - src/win32/posix.c
Merge pull request #400 from boyski/fixup-examples
[libgit2.git] / src / win32 / posix.c
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 */
7 #include "posix.h"
8 #include "path.h"
9 #include <errno.h>
10 #include <io.h>
11
12 int p_unlink(const char *path)
13 {
14 chmod(path, 0666);
15 return unlink(path);
16 }
17
18 int p_fsync(int fd)
19 {
20 HANDLE fh = (HANDLE)_get_osfhandle(fd);
21
22 if (fh == INVALID_HANDLE_VALUE) {
23 errno = EBADF;
24 return -1;
25 }
26
27 if (!FlushFileBuffers(fh)) {
28 DWORD code = GetLastError();
29
30 if (code == ERROR_INVALID_HANDLE)
31 errno = EINVAL;
32 else
33 errno = EIO;
34
35 return -1;
36 }
37
38 return 0;
39 }
40
41 GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
42 {
43 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
44 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
45 winTime /= 10000000; /* Nano to seconds resolution */
46 return (time_t)winTime;
47 }
48
49 static int do_lstat(const char *file_name, struct stat *buf)
50 {
51 WIN32_FILE_ATTRIBUTE_DATA fdata;
52
53 if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
54 int fMode = S_IREAD;
55
56 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
57 fMode |= S_IFDIR;
58 else
59 fMode |= S_IFREG;
60
61 if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
62 fMode |= S_IWRITE;
63
64 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
65 fMode |= S_IFLNK;
66
67 buf->st_ino = 0;
68 buf->st_gid = 0;
69 buf->st_uid = 0;
70 buf->st_nlink = 1;
71 buf->st_mode = (mode_t)fMode;
72 buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
73 buf->st_dev = buf->st_rdev = (_getdrive() - 1);
74 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
75 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
76 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
77 return GIT_SUCCESS;
78 }
79
80 switch (GetLastError()) {
81 case ERROR_ACCESS_DENIED:
82 case ERROR_SHARING_VIOLATION:
83 case ERROR_LOCK_VIOLATION:
84 case ERROR_SHARING_BUFFER_EXCEEDED:
85 return GIT_EOSERR;
86
87 case ERROR_BUFFER_OVERFLOW:
88 case ERROR_NOT_ENOUGH_MEMORY:
89 return GIT_ENOMEM;
90
91 default:
92 return GIT_EINVALIDPATH;
93 }
94 }
95
96 int p_lstat(const char *file_name, struct stat *buf)
97 {
98 int namelen, error;
99 char alt_name[GIT_PATH_MAX];
100
101 if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS)
102 return GIT_SUCCESS;
103
104 /* if file_name ended in a '/', Windows returned ENOENT;
105 * try again without trailing slashes
106 */
107 if (error != GIT_EINVALIDPATH)
108 return git__throw(GIT_EOSERR, "Failed to lstat file");
109
110 namelen = strlen(file_name);
111 if (namelen && file_name[namelen-1] != '/')
112 return git__throw(GIT_EOSERR, "Failed to lstat file");
113
114 while (namelen && file_name[namelen-1] == '/')
115 --namelen;
116
117 if (!namelen || namelen >= GIT_PATH_MAX)
118 return git__throw(GIT_ENOMEM, "Failed to lstat file");
119
120 memcpy(alt_name, file_name, namelen);
121 alt_name[namelen] = 0;
122 return do_lstat(alt_name, buf);
123 }
124
125 int p_readlink(const char *link, char *target, size_t target_len)
126 {
127 typedef DWORD (WINAPI *fpath_func)(HANDLE, LPTSTR, DWORD, DWORD);
128 static fpath_func pGetFinalPath = NULL;
129 HANDLE hFile;
130 DWORD dwRet;
131
132 /*
133 * Try to load the pointer to pGetFinalPath dynamically, because
134 * it is not available in platforms older than Vista
135 */
136 if (pGetFinalPath == NULL) {
137 HINSTANCE library = LoadLibrary("kernel32");
138
139 if (library != NULL)
140 pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleA");
141
142 if (pGetFinalPath == NULL)
143 return git__throw(GIT_EOSERR,
144 "'GetFinalPathNameByHandleA' is not available in this platform");
145 }
146
147 hFile = CreateFile(link, // file to open
148 GENERIC_READ, // open for reading
149 FILE_SHARE_READ, // share for reading
150 NULL, // default security
151 OPEN_EXISTING, // existing file only
152 FILE_FLAG_BACKUP_SEMANTICS, // normal file
153 NULL); // no attr. template
154
155 if (hFile == INVALID_HANDLE_VALUE)
156 return GIT_EOSERR;
157
158 dwRet = pGetFinalPath(hFile, target, target_len, 0x0);
159 if (dwRet >= target_len)
160 return GIT_ENOMEM;
161
162 CloseHandle(hFile);
163
164 if (dwRet > 4) {
165 /* Skip first 4 characters if they are "\\?\" */
166 if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') {
167 char tmp[GIT_PATH_MAX];
168 unsigned int offset = 4;
169 dwRet -= 4;
170
171 /* \??\UNC\ */
172 if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') {
173 offset += 2;
174 dwRet -= 2;
175 target[offset] = '\\';
176 }
177
178 memcpy(tmp, target + offset, dwRet);
179 memcpy(target, tmp, dwRet);
180 }
181 }
182
183 target[dwRet] = '\0';
184 return dwRet;
185 }
186
187 int p_hide_directory__w32(const char *path)
188 {
189 int error;
190
191 error = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) != 0 ?
192 GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */
193
194 if (error < GIT_SUCCESS)
195 error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path);
196
197 return error;
198 }
199
200 char *p_realpath(const char *orig_path, char *buffer)
201 {
202 int ret, alloc = 0;
203
204 if (buffer == NULL) {
205 buffer = (char *)git__malloc(GIT_PATH_MAX);
206 alloc = 1;
207 }
208
209 ret = GetFullPathName(orig_path, GIT_PATH_MAX, buffer, NULL);
210 if (!ret || ret > GIT_PATH_MAX) {
211 if (alloc) free(buffer);
212 return NULL;
213 }
214
215 git_path_mkposix(buffer);
216 return buffer;
217 }
218
219 int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
220 {
221 #ifdef _MSC_VER
222 int len = _vsnprintf(buffer, count, format, argptr);
223 return (len < 0) ? _vscprintf(format, argptr) : len;
224 #else /* MinGW */
225 return vsnprintf(buffer, count, format, argptr);
226 #endif
227 }
228
229 int p_snprintf(char *buffer, size_t count, const char *format, ...)
230 {
231 va_list va;
232 int r;
233
234 va_start(va, format);
235 r = p_vsnprintf(buffer, count, format, va);
236 va_end(va);
237
238 return r;
239 }
240
241 extern int p_creat(const char *path, int mode);
242
243 int p_mkstemp(char *tmp_path)
244 {
245 #if defined(_MSC_VER)
246 if (_mktemp_s(tmp_path, GIT_PATH_MAX) != 0)
247 return GIT_EOSERR;
248 #else
249 if (_mktemp(tmp_path) == NULL)
250 return GIT_EOSERR;
251 #endif
252
253 return p_creat(tmp_path, 0744);
254 }