w32_util.h 5.05 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 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/**
 * Removes any trailing backslashes from a path, except in the case of a drive
 * letter path (C:\, D:\, etc.). This function cannot fail.
 *
 * @param path The path which should be trimmed.
 * @return The length of the modified string (<= the input length)
 */
size_t git_win32__path_trim_end(wchar_t *str, size_t len);

/**
 * Removes any of the following namespace prefixes from a path,
 * if found: "\??\", "\\?\", "\\?\UNC\". This function cannot fail.
 *
 * @param path The path which should be converted.
 * @return The length of the modified string (<= the input length)
 */
78
size_t git_win32__canonicalize_path(wchar_t *str, size_t len);
79

80
/**
81
 * Converts a FILETIME structure to a struct timespec.
82 83
 *
 * @param FILETIME A pointer to a FILETIME
84
 * @param ts A pointer to the timespec structure to fill in
85
 */
86 87 88
GIT_INLINE(void) git_win32__filetime_to_timespec(
	const FILETIME *ft,
	struct timespec *ts)
89 90 91
{
	long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
	winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
92 93 94 95 96 97
	ts->tv_sec = (time_t)(winTime / 10000000);
#ifdef GIT_USE_NSEC
	ts->tv_nsec = (winTime % 10000000) * 100;
#else
	ts->tv_nsec = 0;
#endif
98 99
}

100
GIT_INLINE(void) git_win32__timeval_to_filetime(
101
	FILETIME *ft, const struct p_timeval tv)
102 103 104 105 106 107 108 109
{
	long long ticks = (tv.tv_sec * 10000000LL) +
		(tv.tv_usec * 10LL) + 116444736000000000LL;

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

110
GIT_INLINE(void) git_win32__stat_init(
111
	struct stat *st,
112 113 114 115 116 117
	DWORD dwFileAttributes,
	DWORD nFileSizeHigh,
	DWORD nFileSizeLow,
	FILETIME ftCreationTime,
	FILETIME ftLastAccessTime,
	FILETIME ftLastWriteTime)
118 119 120
{
	mode_t mode = S_IREAD;

121 122 123
	memset(st, 0, sizeof(struct stat));

	if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
124 125 126 127
		mode |= S_IFDIR;
	else
		mode |= S_IFREG;

128
	if ((dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
129 130 131 132 133 134 135
		mode |= S_IWRITE;

	st->st_ino = 0;
	st->st_gid = 0;
	st->st_uid = 0;
	st->st_nlink = 1;
	st->st_mode = mode;
136
	st->st_size = ((git_off_t)nFileSizeHigh << 32) + nFileSizeLow;
137 138
	st->st_dev = _getdrive() - 1;
	st->st_rdev = st->st_dev;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	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);
169 170 171 172 173 174 175 176

	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,
177
			 * not counting the NULL terminator */
178
			if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
179
				giterr_set(GITERR_OS, "could not convert reparse point name for '%ls'", path);
180 181 182 183 184 185 186 187
				return -1;
			}
		}
	}

	return 0;
}

188
#endif