2 * Copyright (C) 2009-2011 the libgit2 contributors
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.
12 int p_unlink(const char *path
)
20 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
22 if (fh
== INVALID_HANDLE_VALUE
) {
27 if (!FlushFileBuffers(fh
)) {
28 DWORD code
= GetLastError();
30 if (code
== ERROR_INVALID_HANDLE
)
41 GIT_INLINE(time_t) filetime_to_time_t(const FILETIME
*ft
)
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
;
49 static int do_lstat(const char *file_name
, struct stat
*buf
)
51 WIN32_FILE_ATTRIBUTE_DATA fdata
;
53 if (GetFileAttributesExA(file_name
, GetFileExInfoStandard
, &fdata
)) {
56 if (fdata
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
61 if (!(fdata
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
64 if (fdata
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
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
));
80 switch (GetLastError()) {
81 case ERROR_ACCESS_DENIED
:
82 case ERROR_SHARING_VIOLATION
:
83 case ERROR_LOCK_VIOLATION
:
84 case ERROR_SHARING_BUFFER_EXCEEDED
:
87 case ERROR_BUFFER_OVERFLOW
:
88 case ERROR_NOT_ENOUGH_MEMORY
:
92 return GIT_EINVALIDPATH
;
96 int p_lstat(const char *file_name
, struct stat
*buf
)
99 char alt_name
[GIT_PATH_MAX
];
101 if ((error
= do_lstat(file_name
, buf
)) == GIT_SUCCESS
)
104 /* if file_name ended in a '/', Windows returned ENOENT;
105 * try again without trailing slashes
107 if (error
!= GIT_EINVALIDPATH
)
108 return git__throw(GIT_EOSERR
, "Failed to lstat file");
110 namelen
= strlen(file_name
);
111 if (namelen
&& file_name
[namelen
-1] != '/')
112 return git__throw(GIT_EOSERR
, "Failed to lstat file");
114 while (namelen
&& file_name
[namelen
-1] == '/')
117 if (!namelen
|| namelen
>= GIT_PATH_MAX
)
118 return git__throw(GIT_ENOMEM
, "Failed to lstat file");
120 memcpy(alt_name
, file_name
, namelen
);
121 alt_name
[namelen
] = 0;
122 return do_lstat(alt_name
, buf
);
125 int p_readlink(const char *link
, char *target
, size_t target_len
)
127 typedef DWORD (WINAPI
*fpath_func
)(HANDLE
, LPTSTR
, DWORD
, DWORD
);
128 static fpath_func pGetFinalPath
= NULL
;
133 * Try to load the pointer to pGetFinalPath dynamically, because
134 * it is not available in platforms older than Vista
136 if (pGetFinalPath
== NULL
) {
137 HINSTANCE library
= LoadLibrary("kernel32");
140 pGetFinalPath
= (fpath_func
)GetProcAddress(library
, "GetFinalPathNameByHandleA");
142 if (pGetFinalPath
== NULL
)
143 return git__throw(GIT_EOSERR
,
144 "'GetFinalPathNameByHandleA' is not available in this platform");
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
155 if (hFile
== INVALID_HANDLE_VALUE
)
158 dwRet
= pGetFinalPath(hFile
, target
, target_len
, 0x0);
159 if (dwRet
>= target_len
)
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;
172 if (dwRet
> 7 && target
[4] == 'U' && target
[5] == 'N' && target
[6] == 'C') {
175 target
[offset
] = '\\';
178 memcpy(tmp
, target
+ offset
, dwRet
);
179 memcpy(target
, tmp
, dwRet
);
183 target
[dwRet
] = '\0';
187 int p_hide_directory__w32(const char *path
)
191 error
= SetFileAttributes(path
, FILE_ATTRIBUTE_HIDDEN
) != 0 ?
192 GIT_SUCCESS
: GIT_ERROR
; /* MSDN states a "non zero" value indicates a success */
194 if (error
< GIT_SUCCESS
)
195 error
= git__throw(GIT_EOSERR
, "Failed to hide directory '%s'", path
);
200 char *p_realpath(const char *orig_path
, char *buffer
)
204 if (buffer
== NULL
) {
205 buffer
= (char *)git__malloc(GIT_PATH_MAX
);
209 ret
= GetFullPathName(orig_path
, GIT_PATH_MAX
, buffer
, NULL
);
210 if (!ret
|| ret
> GIT_PATH_MAX
) {
211 if (alloc
) free(buffer
);
215 git_path_mkposix(buffer
);
219 int p_vsnprintf(char *buffer
, size_t count
, const char *format
, va_list argptr
)
222 int len
= _vsnprintf(buffer
, count
, format
, argptr
);
223 return (len
< 0) ? _vscprintf(format
, argptr
) : len
;
225 return vsnprintf(buffer
, count
, format
, argptr
);
229 int p_snprintf(char *buffer
, size_t count
, const char *format
, ...)
234 va_start(va
, format
);
235 r
= p_vsnprintf(buffer
, count
, format
, va
);
241 extern int p_creat(const char *path
, int mode
);
243 int p_mkstemp(char *tmp_path
)
245 #if defined(_MSC_VER)
246 if (_mktemp_s(tmp_path
, GIT_PATH_MAX
) != 0)
249 if (_mktemp(tmp_path
) == NULL
)
253 return p_creat(tmp_path
, 0744);