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