Skip to content

Commit 2cd87ae

Browse files
Merge branch 'fastfetch-cli:dev' into emerge-set-diff
2 parents 5c70986 + 4e234c5 commit 2cd87ae

9 files changed

Lines changed: 303 additions & 35 deletions

File tree

src/common/impl/FFPlatform_windows.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static void getExePath(FFPlatform* platform)
2828
NULL);
2929
if (hPath != INVALID_HANDLE_VALUE)
3030
{
31-
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_OPENED);
31+
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
3232
if (len > 0 && len < MAX_PATH)
3333
{
3434
ffStrbufSetNWS(&platform->exePath, len, exePathW);

src/common/impl/path.c

Lines changed: 260 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "common/path.h"
22
#include "common/io.h"
3-
#include "common/stringUtils.h"
3+
#include "common/arrayUtils.h"
44

55
#if !_WIN32
66
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
@@ -49,6 +49,9 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
4949
}
5050
#else
5151
#include <windows.h>
52+
#include <winioctl.h>
53+
#include <errno.h>
54+
#include <stdalign.h>
5255

5356
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
5457
{
@@ -62,4 +65,260 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
6265
ffStrbufSetS(result, buffer);
6366
return NULL;
6467
}
68+
69+
static inline int winerr2Errno(DWORD err)
70+
{
71+
switch (err)
72+
{
73+
case ERROR_FILE_NOT_FOUND:
74+
case ERROR_PATH_NOT_FOUND:
75+
case ERROR_INVALID_NAME:
76+
return ENOENT;
77+
case ERROR_ACCESS_DENIED:
78+
case ERROR_SHARING_VIOLATION:
79+
case ERROR_LOCK_VIOLATION:
80+
return EACCES;
81+
case ERROR_BUFFER_OVERFLOW:
82+
case ERROR_INSUFFICIENT_BUFFER:
83+
return ENAMETOOLONG;
84+
case ERROR_INVALID_PARAMETER:
85+
case ERROR_NOT_A_REPARSE_POINT:
86+
return EINVAL;
87+
default:
88+
return EIO;
89+
}
90+
}
91+
92+
char* frealpath(HANDLE hFile, char* resolved_name)
93+
{
94+
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false))
95+
{
96+
errno = EINVAL;
97+
return NULL;
98+
}
99+
100+
wchar_t resolvedNameW[MAX_PATH + 4]; /* +4 for "\\\\?\\" prefix */
101+
DWORD lenW = GetFinalPathNameByHandleW(hFile, resolvedNameW, (DWORD)ARRAY_SIZE(resolvedNameW), FILE_NAME_NORMALIZED);
102+
103+
if (lenW == 0)
104+
{
105+
errno = winerr2Errno(GetLastError());
106+
return NULL;
107+
}
108+
if (lenW >= ARRAY_SIZE(resolvedNameW))
109+
{
110+
errno = E2BIG;
111+
return NULL;
112+
}
113+
lenW++; // Include null terminator
114+
115+
wchar_t* srcW = resolvedNameW;
116+
DWORD srcLenW = lenW;
117+
118+
if (srcLenW >= 8 && wcsncmp(resolvedNameW, L"\\\\?\\UNC\\", 8) == 0)
119+
{
120+
/* Convert "\\?\UNC\server\share" to "\\server\share" */
121+
srcW += 6;
122+
srcLenW -= 6;
123+
*srcW = L'\\';
124+
}
125+
else if (srcLenW >= 4 && wcsncmp(resolvedNameW, L"\\\\?\\", 4) == 0)
126+
{
127+
srcW += 4;
128+
srcLenW -= 4;
129+
}
130+
131+
if (resolved_name)
132+
{
133+
ULONG outBytes = 0;
134+
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
135+
{
136+
errno = E2BIG;
137+
return NULL;
138+
}
139+
140+
if (outBytes > MAX_PATH)
141+
{
142+
errno = E2BIG;
143+
return NULL;
144+
}
145+
146+
return resolved_name;
147+
}
148+
else
149+
{
150+
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
151+
char tmp[(MAX_PATH + 4) * 4];
152+
ULONG outBytes = 0;
153+
154+
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG)sizeof(tmp), &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
155+
{
156+
errno = E2BIG;
157+
return NULL;
158+
}
159+
160+
resolved_name = (char*)malloc(outBytes);
161+
if (!resolved_name)
162+
{
163+
errno = ENOMEM;
164+
return NULL;
165+
}
166+
167+
memcpy(resolved_name, tmp, outBytes);
168+
return resolved_name;
169+
}
170+
171+
return resolved_name;
172+
}
173+
174+
char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
175+
{
176+
if (!file_name)
177+
{
178+
errno = EINVAL;
179+
return NULL;
180+
}
181+
182+
wchar_t fileNameW[MAX_PATH];
183+
ULONG lenBytes = 0;
184+
185+
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG)sizeof(fileNameW), &lenBytes, file_name, (ULONG)strlen(file_name) + 1)))
186+
{
187+
errno = EINVAL;
188+
return NULL;
189+
}
190+
191+
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
192+
fileNameW,
193+
0,
194+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
195+
NULL,
196+
OPEN_EXISTING,
197+
FILE_FLAG_BACKUP_SEMANTICS,
198+
NULL);
199+
200+
if (hFile == INVALID_HANDLE_VALUE)
201+
{
202+
errno = winerr2Errno(GetLastError());
203+
return NULL;
204+
}
205+
206+
return frealpath(hFile, resolved_name);
207+
}
208+
209+
ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
210+
{
211+
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !buf || bufsiz == 0, false))
212+
{
213+
errno = EINVAL;
214+
return -1;
215+
}
216+
217+
alignas(REPARSE_DATA_BUFFER) BYTE reparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
218+
DWORD bytesReturned = 0;
219+
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL))
220+
{
221+
errno = winerr2Errno(GetLastError());
222+
return -1;
223+
}
224+
225+
REPARSE_DATA_BUFFER* rp = (REPARSE_DATA_BUFFER*) reparseBuf;
226+
const wchar_t* targetW = NULL;
227+
USHORT targetBytes = 0;
228+
229+
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
230+
{
231+
if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 0)
232+
{
233+
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
234+
(rp->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t));
235+
targetBytes = rp->SymbolicLinkReparseBuffer.PrintNameLength;
236+
}
237+
else
238+
{
239+
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
240+
(rp->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
241+
targetBytes = rp->SymbolicLinkReparseBuffer.SubstituteNameLength;
242+
243+
if (targetBytes >= 8 &&
244+
wcsncmp(targetW, L"\\??\\", 4) == 0)
245+
{
246+
targetW += 4;
247+
targetBytes -= 8;
248+
}
249+
}
250+
}
251+
else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
252+
{
253+
if (rp->MountPointReparseBuffer.PrintNameLength > 0)
254+
{
255+
targetW = rp->MountPointReparseBuffer.PathBuffer +
256+
(rp->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t));
257+
targetBytes = rp->MountPointReparseBuffer.PrintNameLength;
258+
}
259+
else
260+
{
261+
targetW = rp->MountPointReparseBuffer.PathBuffer +
262+
(rp->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
263+
targetBytes = rp->MountPointReparseBuffer.SubstituteNameLength;
264+
265+
if (targetBytes >= 8 &&
266+
wcsncmp(targetW, L"\\??\\", 4) == 0)
267+
{
268+
targetW += 4;
269+
targetBytes -= 8;
270+
}
271+
}
272+
}
273+
else
274+
{
275+
errno = EINVAL;
276+
return -1;
277+
}
278+
279+
ULONG outBytes = 0;
280+
if (!NT_SUCCESS(RtlUnicodeToUTF8N(buf, (ULONG) bufsiz, &outBytes, targetW, targetBytes)))
281+
{
282+
errno = E2BIG;
283+
return -1;
284+
}
285+
286+
// Not null-terminated
287+
return (ssize_t) outBytes;
288+
}
289+
290+
ssize_t readlink(const char* path, char* buf, size_t bufsiz)
291+
{
292+
if (!path || !buf || bufsiz == 0)
293+
{
294+
errno = EINVAL;
295+
return -1;
296+
}
297+
298+
wchar_t pathW[MAX_PATH];
299+
ULONG pathWBytes = 0;
300+
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathW, (ULONG) sizeof(pathW), &pathWBytes, path, (ULONG) strlen(path) + 1)))
301+
{
302+
errno = EINVAL;
303+
return -1;
304+
}
305+
306+
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
307+
pathW,
308+
0,
309+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
310+
NULL,
311+
OPEN_EXISTING,
312+
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
313+
NULL
314+
);
315+
316+
if (hFile == INVALID_HANDLE_VALUE)
317+
{
318+
errno = winerr2Errno(GetLastError());
319+
return -1;
320+
}
321+
322+
return freadlink(hFile, buf, bufsiz);
323+
}
65324
#endif

src/common/path.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,10 @@ static inline bool ffIsAbsolutePath(const char* path)
1313
return path[0] == '/';
1414
#endif
1515
}
16+
17+
#if _WIN32
18+
char* frealpath(void* __restrict hFile, char* __restrict resolved_name /*MAX_PATH*/);
19+
char* realpath(const char* __restrict file_name, char* __restrict resolved_name /*MAX_PATH*/);
20+
ssize_t freadlink(void* hFile, char* buf, size_t bufsiz);
21+
ssize_t readlink(const char* path, char* buf, size_t bufsiz);
22+
#endif

src/detection/editor/editor.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@
77

88
#include <stdlib.h>
99

10-
#ifdef _WIN32
11-
static inline char* realpath(const char* restrict file_name, char* restrict resolved_name)
12-
{
13-
assert(resolved_name != NULL);
14-
return _fullpath(resolved_name, file_name, _MAX_PATH);
15-
}
16-
#endif
17-
1810
static bool extractNvimVersionFromBinary(const char* str, FF_MAYBE_UNUSED uint32_t len, void* userdata)
1911
{
2012
if (!ffStrStartsWith(str, "NVIM v")) return true;

src/detection/locale/locale.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
#include "fastfetch.h"
44

5-
void ffDetectLocale(FFstrbuf* result);
5+
const char* ffDetectLocale(FFstrbuf* result);

src/detection/locale/locale_linux.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22

33
#include <locale.h>
44

5-
void ffDetectLocale(FFstrbuf* result)
5+
const char* ffDetectLocale(FFstrbuf* result)
66
{
77
ffStrbufAppendS(result, getenv("LC_ALL"));
88
if(result->length > 0)
9-
return;
9+
return NULL;
1010

1111
ffStrbufAppendS(result, getenv("LANG"));
1212
if(result->length > 0)
13-
return;
13+
return NULL;
1414

1515
ffStrbufAppendS(result, setlocale(LC_TIME, NULL));
16+
if(result->length > 0)
17+
return NULL;
18+
19+
return "Failed to detect locale";
1620
}

src/detection/locale/locale_windows.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
#include "common/windows/unicode.h"
33

44
#include <windows.h>
5-
#include <locale.h>
65

7-
void ffDetectLocale(FFstrbuf* result)
6+
const char* ffDetectLocale(FFstrbuf* result)
87
{
98
wchar_t name[LOCALE_NAME_MAX_LENGTH];
109
int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH);
11-
if (size > 1) // including '\0'
12-
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
10+
if (size <= 1) // including '\0'
11+
return "GetUserDefaultLocaleName() failed";
12+
13+
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
14+
15+
return NULL;
1316
}

0 commit comments

Comments
 (0)