Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32/posix_w32.c')
-rw-r--r--src/win32/posix_w32.c411
1 files changed, 257 insertions, 154 deletions
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 10de70da8..4d56299f7 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 the libgit2 contributors
+ * Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
@@ -7,23 +7,18 @@
#include "../posix.h"
#include "path.h"
#include "utf-conv.h"
+#include "repository.h"
#include <errno.h>
#include <io.h>
#include <fcntl.h>
-
+#include <ws2tcpip.h>
int p_unlink(const char *path)
{
- int ret = 0;
- wchar_t* buf;
-
- if ((buf = gitwin_to_utf16(path)) != NULL) {
- _wchmod(buf, 0666);
- ret = _wunlink(buf);
- git__free(buf);
- }
-
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ _wchmod(buf, 0666);
+ return _wunlink(buf);
}
int p_fsync(int fd)
@@ -57,16 +52,32 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
return (time_t)winTime;
}
-static int do_lstat(const char *file_name, struct stat *buf)
+#define WIN32_IS_WSEP(CH) ((CH) == L'/' || (CH) == L'\\')
+
+static int do_lstat(
+ const char *file_name, struct stat *buf, int posix_enotdir)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
- wchar_t* fbuf = gitwin_to_utf16(file_name);
- if (!fbuf)
- return -1;
+ wchar_t fbuf[GIT_WIN_PATH], lastch;
+ int flen;
+
+ flen = git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name);
+
+ /* truncate trailing slashes */
+ for (; flen > 0; --flen) {
+ lastch = fbuf[flen - 1];
+ if (WIN32_IS_WSEP(lastch))
+ fbuf[flen - 1] = L'\0';
+ else if (lastch != L'\0')
+ break;
+ }
if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
int fMode = S_IREAD;
+ if (!buf)
+ return 0;
+
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
fMode |= S_IFDIR;
else
@@ -89,44 +100,59 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
- git__free(fbuf);
- return 0;
- }
+ /* Windows symlinks have zero file size, call readlink to determine
+ * the length of the path pointed to, which we expect everywhere else
+ */
+ if (S_ISLNK(fMode)) {
+ char target[GIT_WIN_PATH];
+ int readlink_result;
- git__free(fbuf);
- return -1;
-}
+ readlink_result = p_readlink(file_name, target, GIT_WIN_PATH);
-int p_lstat(const char *file_name, struct stat *buf)
-{
- int error;
- size_t namelen;
- char *alt_name;
+ if (readlink_result == -1)
+ return -1;
- if (do_lstat(file_name, buf) == 0)
- return 0;
+ buf->st_size = strlen(target);
+ }
- /* if file_name ended in a '/', Windows returned ENOENT;
- * try again without trailing slashes
- */
- namelen = strlen(file_name);
- if (namelen && file_name[namelen-1] != '/')
- return -1;
+ return 0;
+ }
- while (namelen && file_name[namelen-1] == '/')
- --namelen;
+ errno = ENOENT;
- if (!namelen)
- return -1;
+ /* We need POSIX behavior, then ENOTDIR must set when any of the folders in the
+ * file path is a regular file,otherwise ENOENT must be set.
+ */
+ if (posix_enotdir) {
+ /* scan up path until we find an existing item */
+ while (1) {
+ /* remove last directory component */
+ for (--flen; flen > 0 && !WIN32_IS_WSEP(fbuf[flen]); --flen);
+
+ if (flen <= 0)
+ break;
+
+ fbuf[flen] = L'\0';
+
+ if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
+ if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ errno = ENOTDIR;
+ break;
+ }
+ }
+ }
- alt_name = git__strndup(file_name, namelen);
- if (!alt_name)
- return -1;
+ return -1;
+}
- error = do_lstat(alt_name, buf);
+int p_lstat(const char *filename, struct stat *buf)
+{
+ return do_lstat(filename, buf, 0);
+}
- git__free(alt_name);
- return error;
+int p_lstat_posixly(const char *filename, struct stat *buf)
+{
+ return do_lstat(filename, buf, 1);
}
int p_readlink(const char *link, char *target, size_t target_len)
@@ -135,7 +161,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
static fpath_func pGetFinalPath = NULL;
HANDLE hFile;
DWORD dwRet;
- wchar_t* link_w;
+ wchar_t link_w[GIT_WIN_PATH];
wchar_t* target_w;
int error = 0;
@@ -146,10 +172,10 @@ int p_readlink(const char *link, char *target, size_t target_len)
* it is not available in platforms older than Vista
*/
if (pGetFinalPath == NULL) {
- HINSTANCE library = LoadLibrary("kernel32");
+ HMODULE module = GetModuleHandle("kernel32");
- if (library != NULL)
- pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW");
+ if (module != NULL)
+ pGetFinalPath = (fpath_func)GetProcAddress(module, "GetFinalPathNameByHandleW");
if (pGetFinalPath == NULL) {
giterr_set(GITERR_OS,
@@ -158,8 +184,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
}
}
- link_w = gitwin_to_utf16(link);
- GITERR_CHECK_ALLOC(link_w);
+ git__utf8_to_16(link_w, GIT_WIN_PATH, link);
hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading
@@ -169,8 +194,6 @@ int p_readlink(const char *link, char *target, size_t target_len)
FILE_FLAG_BACKUP_SEMANTICS, // normal file
NULL); // no attr. template
- git__free(link_w);
-
if (hFile == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
return -1;
@@ -217,46 +240,43 @@ int p_readlink(const char *link, char *target, size_t target_len)
return dwRet;
}
+int p_symlink(const char *old, const char *new)
+{
+ /* Real symlinks on NTFS require admin privileges. Until this changes,
+ * libgit2 just creates a text file with the link target in the contents.
+ */
+ return git_futils_fake_symlink(old, new);
+}
+
int p_open(const char *path, int flags, ...)
{
- int fd;
- wchar_t* buf;
+ wchar_t buf[GIT_WIN_PATH];
mode_t mode = 0;
- buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
- if (flags & O_CREAT)
- {
+ if (flags & O_CREAT) {
va_list arg_list;
va_start(arg_list, flags);
- mode = va_arg(arg_list, mode_t);
+ mode = (mode_t)va_arg(arg_list, int);
va_end(arg_list);
}
- fd = _wopen(buf, flags | _O_BINARY, mode);
-
- git__free(buf);
- return fd;
+ return _wopen(buf, flags | _O_BINARY, mode);
}
int p_creat(const char *path, mode_t mode)
{
- int fd;
- wchar_t* buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
- fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
- git__free(buf);
- return fd;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
}
int p_getcwd(char *buffer_out, size_t size)
{
int ret;
- wchar_t* buf;
+ wchar_t *buf;
if ((size_t)((int)size) != size)
return -1;
@@ -275,104 +295,78 @@ int p_getcwd(char *buffer_out, size_t size)
int p_stat(const char* path, struct stat* buf)
{
- return do_lstat(path, buf);
+ return do_lstat(path, buf, 0);
}
int p_chdir(const char* path)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wchdir(buf);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wchdir(buf);
}
int p_chmod(const char* path, mode_t mode)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wchmod(buf, mode);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wchmod(buf, mode);
}
int p_rmdir(const char* path)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wrmdir(buf);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wrmdir(buf);
}
int p_hide_directory__w32(const char *path)
{
- int res;
- wchar_t* buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
-
- res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
- git__free(buf);
-
- return (res != 0) ? 0 : -1; /* MSDN states a "non zero" value indicates a success */
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1;
}
char *p_realpath(const char *orig_path, char *buffer)
{
- int ret, buffer_sz = 0;
- wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
- wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
+ int ret;
+ wchar_t orig_path_w[GIT_WIN_PATH];
+ wchar_t buffer_w[GIT_WIN_PATH];
- if (!orig_path_w || !buffer_w)
- return NULL;
+ git__utf8_to_16(orig_path_w, GIT_WIN_PATH, orig_path);
- ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
- git__free(orig_path_w);
+ /* Implicitly use GetCurrentDirectory which can be a threading issue */
+ ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH, buffer_w, NULL);
/* According to MSDN, a return value equals to zero means a failure. */
- if (ret == 0 || ret > GIT_PATH_MAX) {
+ if (ret == 0 || ret > GIT_WIN_PATH)
buffer = NULL;
- goto done;
+
+ else if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) {
+ buffer = NULL;
+ errno = ENOENT;
}
- if (buffer == NULL) {
- buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL);
+ else if (buffer == NULL) {
+ int buffer_sz = WideCharToMultiByte(
+ CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL);
if (!buffer_sz ||
!(buffer = (char *)git__malloc(buffer_sz)) ||
- !WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, buffer_sz, NULL, NULL))
+ !WideCharToMultiByte(
+ CP_UTF8, 0, buffer_w, -1, buffer, buffer_sz, NULL, NULL))
{
git__free(buffer);
buffer = NULL;
- goto done;
- }
- } else {
- if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) {
- buffer = NULL;
- goto done;
}
}
- if (!git_path_exists(buffer))
- {
- if (buffer_sz > 0)
- git__free(buffer);
-
+ else if (!WideCharToMultiByte(
+ CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL))
buffer = NULL;
- errno = ENOENT;
- }
-done:
- git__free(buffer_w);
if (buffer)
git_path_mkposix(buffer);
+
return buffer;
}
@@ -381,7 +375,8 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
#ifdef _MSC_VER
int len;
- if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0)
+ if (count == 0 ||
+ (len = _vsnprintf_s(buffer, count, _TRUNCATE, format, argptr)) < 0)
return _vscprintf(format, argptr);
return len;
@@ -414,7 +409,7 @@ int p_mkstemp(char *tmp_path)
return -1;
#endif
- return p_creat(tmp_path, 0744);
+ return p_creat(tmp_path, 0744); //-V536
}
int p_setenv(const char* name, const char* value, int overwrite)
@@ -427,32 +422,19 @@ int p_setenv(const char* name, const char* value, int overwrite)
int p_access(const char* path, mode_t mode)
{
- wchar_t *buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
-
- ret = _waccess(buf, mode);
- git__free(buf);
-
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _waccess(buf, mode);
}
int p_rename(const char *from, const char *to)
{
- wchar_t *wfrom = gitwin_to_utf16(from);
- wchar_t *wto = gitwin_to_utf16(to);
- int ret;
-
- if (!wfrom || !wto)
- return -1;
-
- ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
-
- git__free(wfrom);
- git__free(wto);
+ wchar_t wfrom[GIT_WIN_PATH];
+ wchar_t wto[GIT_WIN_PATH];
- return ret;
+ git__utf8_to_16(wfrom, GIT_WIN_PATH, from);
+ git__utf8_to_16(wto, GIT_WIN_PATH, to);
+ return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
}
int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
@@ -470,3 +452,124 @@ int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags)
return send(socket, buffer, (int)length, flags);
}
+
+/**
+ * Borrowed from http://old.nabble.com/Porting-localtime_r-and-gmtime_r-td15282276.html
+ * On Win32, `gmtime_r` doesn't exist but `gmtime` is threadsafe, so we can use that
+ */
+struct tm *
+p_localtime_r (const time_t *timer, struct tm *result)
+{
+ struct tm *local_result;
+ local_result = localtime (timer);
+
+ if (local_result == NULL || result == NULL)
+ return NULL;
+
+ memcpy (result, local_result, sizeof (struct tm));
+ return result;
+}
+struct tm *
+p_gmtime_r (const time_t *timer, struct tm *result)
+{
+ struct tm *local_result;
+ local_result = gmtime (timer);
+
+ if (local_result == NULL || result == NULL)
+ return NULL;
+
+ memcpy (result, local_result, sizeof (struct tm));
+ return result;
+}
+
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
+#else
+#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
+#endif
+
+#ifndef _TIMEZONE_DEFINED
+#define _TIMEZONE_DEFINED
+struct timezone
+{
+ int tz_minuteswest; /* minutes W of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+#endif
+
+int p_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ unsigned __int64 tmpres = 0;
+ static int tzflag;
+
+ if (NULL != tv)
+ {
+ GetSystemTimeAsFileTime(&ft);
+
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+
+ /*converting file time to unix epoch*/
+ tmpres /= 10; /*convert into microseconds*/
+ tmpres -= DELTA_EPOCH_IN_MICROSECS;
+ tv->tv_sec = (long)(tmpres / 1000000UL);
+ tv->tv_usec = (long)(tmpres % 1000000UL);
+ }
+
+ if (NULL != tz)
+ {
+ if (!tzflag)
+ {
+ _tzset();
+ tzflag++;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ return 0;
+}
+
+int p_inet_pton(int af, const char* src, void* dst)
+{
+ union {
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ } sa;
+ int srcsize;
+
+ switch(af)
+ {
+ case AF_INET:
+ sa.sin.sin_family = AF_INET;
+ srcsize = (int)sizeof(sa.sin);
+ break;
+ case AF_INET6:
+ sa.sin6.sin6_family = AF_INET6;
+ srcsize = (int)sizeof(sa.sin6);
+ break;
+ default:
+ errno = WSAEPFNOSUPPORT;
+ return -1;
+ }
+
+ if (WSAStringToAddress((LPSTR)src, af, NULL, (struct sockaddr *) &sa, &srcsize) != 0)
+ {
+ errno = WSAGetLastError();
+ return -1;
+ }
+
+ switch(af)
+ {
+ case AF_INET:
+ memcpy(dst, &sa.sin.sin_addr, sizeof(sa.sin.sin_addr));
+ break;
+ case AF_INET6:
+ memcpy(dst, &sa.sin6.sin6_addr, sizeof(sa.sin6.sin6_addr));
+ break;
+ }
+
+ return 1;
+}