1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "w32_util.h"
9 
10 /**
11  * Creates a FindFirstFile(Ex) filter string from a UTF-8 path.
12  * The filter string enumerates all items in the directory.
13  *
14  * @param dest The buffer to receive the filter string.
15  * @param src The UTF-8 path of the directory to enumerate.
16  * @return True if the filter string was created successfully; false otherwise
17  */
git_win32__findfirstfile_filter(git_win32_path dest,const char * src)18 bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src)
19 {
20 	static const wchar_t suffix[] = L"\\*";
21 	int len = git_win32_path_from_utf8(dest, src);
22 
23 	/* Ensure the path was converted */
24 	if (len < 0)
25 		return false;
26 
27 	/* Ensure that the path does not end with a trailing slash,
28 	 * because we're about to add one. Don't rely our trim_end
29 	 * helper, because we want to remove the backslash even for
30 	 * drive letter paths, in this case. */
31 	if (len > 0 &&
32 		(dest[len - 1] == L'/' || dest[len - 1] == L'\\')) {
33 		dest[len - 1] = L'\0';
34 		len--;
35 	}
36 
37 	/* Ensure we have enough room to add the suffix */
38 	if ((size_t)len >= GIT_WIN_PATH_UTF16 - CONST_STRLEN(suffix))
39 		return false;
40 
41 	wcscat(dest, suffix);
42 	return true;
43 }
44 
45 /**
46  * Ensures the given path (file or folder) has the +H (hidden) attribute set.
47  *
48  * @param path The path which should receive the +H bit.
49  * @return 0 on success; -1 on failure
50  */
git_win32__set_hidden(const char * path,bool hidden)51 int git_win32__set_hidden(const char *path, bool hidden)
52 {
53 	git_win32_path buf;
54 	DWORD attrs, newattrs;
55 
56 	if (git_win32_path_from_utf8(buf, path) < 0)
57 		return -1;
58 
59 	attrs = GetFileAttributesW(buf);
60 
61 	/* Ensure the path exists */
62 	if (attrs == INVALID_FILE_ATTRIBUTES)
63 		return -1;
64 
65 	if (hidden)
66 		newattrs = attrs | FILE_ATTRIBUTE_HIDDEN;
67 	else
68 		newattrs = attrs & ~FILE_ATTRIBUTE_HIDDEN;
69 
70 	if (attrs != newattrs && !SetFileAttributesW(buf, newattrs)) {
71 		git_error_set(GIT_ERROR_OS, "failed to %s hidden bit for '%s'",
72 			hidden ? "set" : "unset", path);
73 		return -1;
74 	}
75 
76 	return 0;
77 }
78 
git_win32__hidden(bool * out,const char * path)79 int git_win32__hidden(bool *out, const char *path)
80 {
81 	git_win32_path buf;
82 	DWORD attrs;
83 
84 	if (git_win32_path_from_utf8(buf, path) < 0)
85 		return -1;
86 
87 	attrs = GetFileAttributesW(buf);
88 
89 	/* Ensure the path exists */
90 	if (attrs == INVALID_FILE_ATTRIBUTES)
91 		return -1;
92 
93 	*out = (attrs & FILE_ATTRIBUTE_HIDDEN) ? true : false;
94 	return 0;
95 }
96 
git_win32__file_attribute_to_stat(struct stat * st,const WIN32_FILE_ATTRIBUTE_DATA * attrdata,const wchar_t * path)97 int git_win32__file_attribute_to_stat(
98 	struct stat *st,
99 	const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
100 	const wchar_t *path)
101 {
102 	git_win32__stat_init(st,
103 		attrdata->dwFileAttributes,
104 		attrdata->nFileSizeHigh,
105 		attrdata->nFileSizeLow,
106 		attrdata->ftCreationTime,
107 		attrdata->ftLastAccessTime,
108 		attrdata->ftLastWriteTime);
109 
110 	if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
111 		git_win32_path target;
112 
113 		if (git_win32_path_readlink_w(target, path) >= 0) {
114 			st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK;
115 
116 			/* st_size gets the UTF-8 length of the target name, in bytes,
117 			 * not counting the NULL terminator */
118 			if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
119 				git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path);
120 				return -1;
121 			}
122 		}
123 	}
124 
125 	return 0;
126 }
127