w32_util.h 4.42 KB
Newer Older
1 2 3 4 5 6 7
/*
 * 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.
 */

8 9
#ifndef INCLUDE_win32_w32_util_h__
#define INCLUDE_win32_w32_util_h__
10

11 12
#include "common.h"

13
#include "utf-conv.h"
14
#include "posix.h"
15
#include "path_w32.h"
16

17 18 19 20 21 22 23 24 25 26 27 28
/*

#include "common.h"
#include "path.h"
#include "path_w32.h"
#include "utf-conv.h"
#include "posix.h"
#include "reparse.h"
#include "dir.h"
*/


29 30 31 32 33
GIT_INLINE(bool) git_win32__isalpha(wchar_t c)
{
	return ((c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z'));
}

34 35 36 37 38 39 40 41 42 43 44
/**
 * Creates a FindFirstFile(Ex) filter string from a UTF-8 path.
 * The filter string enumerates all items in the directory.
 *
 * @param dest The buffer to receive the filter string.
 * @param src The UTF-8 path of the directory to enumerate.
 * @return True if the filter string was created successfully; false otherwise
 */
bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src);

/**
45 46
 * Ensures the given path (file or folder) has the +H (hidden) attribute set
 * or unset.
47
 *
48 49
 * @param path The path that should receive the +H bit.
 * @param hidden true to set +H, false to unset it
50 51
 * @return 0 on success; -1 on failure
 */
52 53 54 55 56 57 58 59 60
extern int git_win32__set_hidden(const char *path, bool hidden);

/**
 * Determines if the given file or folder has the hidden attribute set.
 * @param hidden pointer to store hidden value
 * @param path The path that should be queried for hiddenness.
 * @return 0 on success or an error code.
 */
extern int git_win32__hidden(bool *hidden, const char *path);
61

62
/**
63
 * Converts a FILETIME structure to a struct timespec.
64 65
 *
 * @param FILETIME A pointer to a FILETIME
66
 * @param ts A pointer to the timespec structure to fill in
67
 */
68 69 70
GIT_INLINE(void) git_win32__filetime_to_timespec(
	const FILETIME *ft,
	struct timespec *ts)
71 72 73
{
	long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
	winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
74 75 76 77 78 79
	ts->tv_sec = (time_t)(winTime / 10000000);
#ifdef GIT_USE_NSEC
	ts->tv_nsec = (winTime % 10000000) * 100;
#else
	ts->tv_nsec = 0;
#endif
80 81
}

82
GIT_INLINE(void) git_win32__timeval_to_filetime(
83
	FILETIME *ft, const struct p_timeval tv)
84 85 86 87 88 89 90 91
{
	long long ticks = (tv.tv_sec * 10000000LL) +
		(tv.tv_usec * 10LL) + 116444736000000000LL;

	ft->dwHighDateTime = ((ticks >> 32) & 0xffffffffLL);
	ft->dwLowDateTime = (ticks & 0xffffffffLL);
}

92
GIT_INLINE(void) git_win32__stat_init(
93
	struct stat *st,
94 95 96 97 98 99
	DWORD dwFileAttributes,
	DWORD nFileSizeHigh,
	DWORD nFileSizeLow,
	FILETIME ftCreationTime,
	FILETIME ftLastAccessTime,
	FILETIME ftLastWriteTime)
100 101 102
{
	mode_t mode = S_IREAD;

103 104 105
	memset(st, 0, sizeof(struct stat));

	if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
106 107 108 109
		mode |= S_IFDIR;
	else
		mode |= S_IFREG;

110
	if ((dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
111 112 113 114 115 116 117
		mode |= S_IWRITE;

	st->st_ino = 0;
	st->st_gid = 0;
	st->st_uid = 0;
	st->st_nlink = 1;
	st->st_mode = mode;
118
	st->st_size = ((git_off_t)nFileSizeHigh << 32) + nFileSizeLow;
119 120
	st->st_dev = _getdrive() - 1;
	st->st_rdev = st->st_dev;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	git_win32__filetime_to_timespec(&ftLastAccessTime, &(st->st_atim));
	git_win32__filetime_to_timespec(&ftLastWriteTime, &(st->st_mtim));
	git_win32__filetime_to_timespec(&ftCreationTime, &(st->st_ctim));
}

GIT_INLINE(void) git_win32__file_information_to_stat(
	struct stat *st,
	const BY_HANDLE_FILE_INFORMATION *fileinfo)
{
	git_win32__stat_init(st,
		fileinfo->dwFileAttributes,
		fileinfo->nFileSizeHigh,
		fileinfo->nFileSizeLow,
		fileinfo->ftCreationTime,
		fileinfo->ftLastAccessTime,
		fileinfo->ftLastWriteTime);
}

GIT_INLINE(int) git_win32__file_attribute_to_stat(
	struct stat *st,
	const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
	const wchar_t *path)
{
	git_win32__stat_init(st,
		attrdata->dwFileAttributes,
		attrdata->nFileSizeHigh,
		attrdata->nFileSizeLow,
		attrdata->ftCreationTime,
		attrdata->ftLastAccessTime,
		attrdata->ftLastWriteTime);
151 152 153 154 155 156 157 158

	if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
		git_win32_path target;

		if (git_win32_path_readlink_w(target, path) >= 0) {
			st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK;

			/* st_size gets the UTF-8 length of the target name, in bytes,
159
			 * not counting the NULL terminator */
160
			if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
161
				git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path);
162 163 164 165 166 167 168 169
				return -1;
			}
		}
	}

	return 0;
}

170
#endif