#include "../strbuf.h"
#include "../run-command.h"
#include "../cache.h"
+#include "win32/lazyload.h"
#define HCAST(type, handle) ((type)(intptr_t)handle)
}
}
+/* Normalizes NT paths as returned by some low-level APIs. */
+static wchar_t *normalize_ntpath(wchar_t *wbuf)
+{
+ int i;
+ /* fix absolute path prefixes */
+ if (wbuf[0] == '\\') {
+ /* strip NT namespace prefixes */
+ if (!wcsncmp(wbuf, L"\\??\\", 4) ||
+ !wcsncmp(wbuf, L"\\\\?\\", 4))
+ wbuf += 4;
+ else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
+ wbuf += 12;
+ /* replace remaining '...UNC\' with '\\' */
+ if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
+ wbuf += 2;
+ *wbuf = '\\';
+ }
+ }
+ /* convert backslashes to slashes */
+ for (i = 0; wbuf[i]; i++)
+ if (wbuf[i] == '\\')
+ wbuf[i] = '/';
+ return wbuf;
+}
+
int mingw_unlink(const char *pathname)
{
int ret, tries = 0;
return winTime - 116444736000000000LL;
}
- static inline time_t filetime_to_time_t(const FILETIME *ft)
+ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
{
- return (time_t)(filetime_to_hnsec(ft) / 10000000);
+ long long hnsec = filetime_to_hnsec(ft);
+ ts->tv_sec = (time_t)(hnsec / 10000000);
+ ts->tv_nsec = (hnsec % 10000000) * 100;
}
/**
buf->st_size = fdata.nFileSizeLow |
(((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
- buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
- buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
- buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
+ filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+ filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+ filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
WIN32_FIND_DATAW findbuf;
HANDLE handle = FindFirstFileW(wfilename, &findbuf);
return do_lstat(follow, alt_name, buf);
}
+ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
+ {
+ BY_HANDLE_FILE_INFORMATION fdata;
+
+ if (!GetFileInformationByHandle(hnd, &fdata)) {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ }
+
+ buf->st_ino = 0;
+ buf->st_gid = 0;
+ buf->st_uid = 0;
+ buf->st_nlink = 1;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+ buf->st_size = fdata.nFileSizeLow |
+ (((off_t)fdata.nFileSizeHigh)<<32);
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+ filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+ filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+ filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
+ return 0;
+ }
+
int mingw_lstat(const char *file_name, struct stat *buf)
{
return do_stat_internal(0, file_name, buf);
int mingw_fstat(int fd, struct stat *buf)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
- BY_HANDLE_FILE_INFORMATION fdata;
+ DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
- if (fh == INVALID_HANDLE_VALUE) {
- errno = EBADF;
- return -1;
- }
- /* direct non-file handles to MS's fstat() */
- if (GetFileType(fh) != FILE_TYPE_DISK)
- return _fstati64(fd, buf);
+ switch (type) {
+ case FILE_TYPE_DISK:
+ return get_file_info_by_handle(fh, buf);
- if (GetFileInformationByHandle(fh, &fdata)) {
- buf->st_ino = 0;
- buf->st_gid = 0;
- buf->st_uid = 0;
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_PIPE:
+ /* initialize stat fields */
+ memset(buf, 0, sizeof(*buf));
buf->st_nlink = 1;
- buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
- buf->st_size = fdata.nFileSizeLow |
- (((off_t)fdata.nFileSizeHigh)<<32);
- buf->st_dev = buf->st_rdev = 0; /* not used by Git */
- buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
- buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
- buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
+
+ if (type == FILE_TYPE_CHAR) {
+ buf->st_mode = _S_IFCHR;
+ } else {
+ buf->st_mode = _S_IFIFO;
+ if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
+ buf->st_size = avail;
+ }
return 0;
+
+ default:
+ errno = EBADF;
+ return -1;
}
- errno = EBADF;
- return -1;
}
static inline void time_t_to_filetime(time_t t, FILETIME *ft)
char *mingw_getcwd(char *pointer, int len)
{
- wchar_t wpointer[MAX_PATH];
- if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+ wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
+ DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+
+ if (!ret || ret >= ARRAY_SIZE(cwd)) {
+ errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
+ return NULL;
+ }
+ ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
+ if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
+ HANDLE hnd = CreateFileW(cwd, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (hnd == INVALID_HANDLE_VALUE)
+ return NULL;
+ ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
+ CloseHandle(hnd);
+ if (!ret || ret >= ARRAY_SIZE(wpointer))
+ return NULL;
+ if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
+ return NULL;
+ return pointer;
+ }
+ if (!ret || ret >= ARRAY_SIZE(wpointer))
return NULL;
if (xwcstoutf(pointer, wpointer, len) < 0)
return NULL;
WSAGetLastError());
for (name = libraries; *name; name++) {
- ipv6_dll = LoadLibrary(*name);
+ ipv6_dll = LoadLibraryExA(*name, NULL,
+ LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!ipv6_dll)
continue;
return si.dwAllocationGranularity;
}
+/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */
+enum EXTENDED_NAME_FORMAT {
+ NameDisplay = 3,
+ NameUserPrincipal = 8
+};
+
+static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
+{
+ DECLARE_PROC_ADDR(secur32.dll, BOOL, GetUserNameExW,
+ enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
+ static wchar_t wbuffer[1024];
+ DWORD len;
+
+ if (!INIT_PROC_ADDR(GetUserNameExW))
+ return NULL;
+
+ len = ARRAY_SIZE(wbuffer);
+ if (GetUserNameExW(type, wbuffer, &len)) {
+ char *converted = xmalloc((len *= 3));
+ if (xwcstoutf(converted, wbuffer, len) >= 0)
+ return converted;
+ free(converted);
+ }
+
+ return NULL;
+}
+
+char *mingw_query_user_email(void)
+{
+ return get_extended_user_info(NameUserPrincipal);
+}
+
struct passwd *getpwuid(int uid)
{
+ static unsigned initialized;
static char user_name[100];
- static struct passwd p;
+ static struct passwd *p;
+ DWORD len;
+
+ if (initialized)
+ return p;
- DWORD len = sizeof(user_name);
- if (!GetUserName(user_name, &len))
+ len = sizeof(user_name);
+ if (!GetUserName(user_name, &len)) {
+ initialized = 1;
return NULL;
- p.pw_name = user_name;
- p.pw_gecos = "unknown";
- p.pw_dir = NULL;
- return &p;
+ }
+
+ p = xmalloc(sizeof(*p));
+ p->pw_name = user_name;
+ p->pw_gecos = get_extended_user_info(NameDisplay);
+ if (!p->pw_gecos)
+ p->pw_gecos = "unknown";
+ p->pw_dir = NULL;
+
+ initialized = 1;
+ return p;
}
static HANDLE timer_event;
}
/*
- * Use mingw specific stat()/lstat()/fstat() implementations on Windows.
+ * Use mingw specific stat()/lstat()/fstat() implementations on Windows,
+ * including our own struct stat with 64 bit st_size and nanosecond-precision
+ * file times.
*/
#ifndef __MINGW64_VERSION_MAJOR
#define off_t off64_t
#define lseek _lseeki64
+ struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+ };
#endif
- /* use struct stat with 64 bit st_size */
+ struct mingw_stat {
+ _dev_t st_dev;
+ _ino_t st_ino;
+ _mode_t st_mode;
+ short st_nlink;
+ short st_uid;
+ short st_gid;
+ _dev_t st_rdev;
+ off64_t st_size;
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ };
+
+ #define st_atime st_atim.tv_sec
+ #define st_mtime st_mtim.tv_sec
+ #define st_ctime st_ctim.tv_sec
+
#ifdef stat
#undef stat
#endif
- #define stat _stati64
+ #define stat mingw_stat
int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_stat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf);
#endif
#define lstat mingw_lstat
- #ifndef _stati64
- # define _stati64(x,y) mingw_stat(x,y)
- #elif defined (_USE_32BIT_TIME_T)
- # define _stat32i64(x,y) mingw_stat(x,y)
- #else
- # define _stat64(x,y) mingw_stat(x,y)
- #endif
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
int mingw_offset_1st_component(const char *path);
#define offset_1st_component mingw_offset_1st_component
#define PATH_SEP ';'
+extern char *mingw_query_user_email(void);
+#define query_user_email mingw_query_user_email
#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
#define PRIuMAX "I64u"
#define PRId64 "I64d"