w32_util.h 5.02 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * 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.
 */

#ifndef INCLUDE_w32_util_h__
#define INCLUDE_w32_util_h__

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

15 16 17 18 19 20 21 22 23 24 25 26
/*

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


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

32 33 34 35 36 37 38 39 40 41 42
/**
 * 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);

/**
43 44
 * Ensures the given path (file or folder) has the +H (hidden) attribute set
 * or unset.
45
 *
46 47
 * @param path The path that should receive the +H bit.
 * @param hidden true to set +H, false to unset it
48 49
 * @return 0 on success; -1 on failure
 */
50 51 52 53 54 55 56 57 58
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);
59

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
/**
 * 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)
 */
76
size_t git_win32__canonicalize_path(wchar_t *str, size_t len);
77

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

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

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

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

119 120 121
	memset(st, 0, sizeof(struct stat));

	if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
122 123 124 125
		mode |= S_IFDIR;
	else
		mode |= S_IFREG;

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

	st->st_ino = 0;
	st->st_gid = 0;
	st->st_uid = 0;
	st->st_nlink = 1;
	st->st_mode = mode;
134
	st->st_size = ((git_off_t)nFileSizeHigh << 32) + nFileSizeLow;
135 136
	st->st_dev = _getdrive() - 1;
	st->st_rdev = st->st_dev;
137 138 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
	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);
167 168 169 170 171 172 173 174

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

	return 0;
}

186
#endif