Packages (Windows): improves performance for directory enumeration

This commit is contained in:
李通洲
2025-12-08 16:42:14 +08:00
parent 100cd9a72b
commit 0b6ca158ea
2 changed files with 68 additions and 24 deletions
+52 -24
View File
@@ -2,35 +2,63 @@
#include "common/processing.h"
#include "util/stringUtils.h"
#include "util/path.h"
#include "util/windows/unicode.h"
#include "util/mallocHelper.h"
#include "common/io/io.h"
#include <handleapi.h>
#include <fileapi.h>
#include <Windows.h>
#include "util/windows/nt.h"
#include <ntstatus.h>
static uint32_t getNumElements(const char* searchPath /* including `\*` suffix */, DWORD type, const char* ignore)
static uint32_t getNumElements(const char* searchPath, DWORD type, const wchar_t* ignore)
{
uint32_t counter = 0;
bool flag = ignore == NULL;
WIN32_FIND_DATAA wfd;
HANDLE hFind = FindFirstFileA(searchPath, &wfd);
FF_AUTO_CLOSE_FD HANDLE dfd = CreateFileA(searchPath, FILE_LIST_DIRECTORY | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (dfd == INVALID_HANDLE_VALUE) return 0;
if (hFind != INVALID_HANDLE_VALUE)
{
do // Managed to locate and create an handle to that folder.
bool flag = ignore == NULL;
uint32_t counter = 0;
uint8_t buffer[64 * 1024] __attribute__((aligned(8))); // Required for WoA
BOOLEAN firstScan = TRUE;
while (true) {
IO_STATUS_BLOCK ioStatus = {};
NTSTATUS status = NtQueryDirectoryFile(
dfd,
NULL, NULL, NULL,
&ioStatus,
buffer, ARRAY_SIZE(buffer),
FileDirectoryInformation,
FALSE,
NULL,
firstScan
);
firstScan = FALSE;
if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) break;
for (FILE_DIRECTORY_INFORMATION* entry = (FILE_DIRECTORY_INFORMATION*) buffer;
;
entry = (FILE_DIRECTORY_INFORMATION*) ((uint8_t*) entry + entry->NextEntryOffset))
{
if(!(wfd.dwFileAttributes & type)) continue;
if(!flag && ffStrEqualsIgnCase(ignore, wfd.cFileName))
if (!(entry->FileAttributes & type)) continue;
if (!flag && _wcsicmp(entry->FileName, ignore) == 0)
{
flag = true;
continue;
}
counter++;
} while (FindNextFileA(hFind, &wfd));
FindClose(hFind);
if(type == FILE_ATTRIBUTE_DIRECTORY && counter >= 2)
counter -= 2; // accounting for . and ..
counter++;
if (entry->NextEntryOffset == 0) break;
}
if (status == STATUS_SUCCESS) break; // No next page
}
if(type == FILE_ATTRIBUTE_DIRECTORY && counter >= 2)
counter -= 2; // accounting for . and ..
return counter;
}
@@ -65,8 +93,8 @@ static void detectScoop(FFPackagesResult* result)
ffStrbufSet(&scoopPath, &instance.state.platform.homeDir);
ffStrbufAppendS(&scoopPath, "/scoop");
}
ffStrbufAppendS(&scoopPath, "/apps/*");
result->scoopUser = getNumElements(scoopPath.chars, FILE_ATTRIBUTE_DIRECTORY, "scoop");
ffStrbufAppendS(&scoopPath, "/apps/");
result->scoopUser = getNumElements(scoopPath.chars, FILE_ATTRIBUTE_DIRECTORY, L"scoop");
}
{
@@ -78,8 +106,8 @@ static void detectScoop(FFPackagesResult* result)
ffStrbufSetS(&scoopPath, getenv("ProgramData"));
ffStrbufAppendS(&scoopPath, "/scoop");
}
ffStrbufAppendS(&scoopPath, "/apps/*");
result->scoopGlobal = getNumElements(scoopPath.chars, FILE_ATTRIBUTE_DIRECTORY, "scoop");
ffStrbufAppendS(&scoopPath, "/apps/");
result->scoopGlobal = getNumElements(scoopPath.chars, FILE_ATTRIBUTE_DIRECTORY, L"scoop");
}
}
@@ -91,8 +119,8 @@ static void detectChoco(FF_MAYBE_UNUSED FFPackagesResult* result)
char chocoPath[MAX_PATH + 3];
char* pend = ffStrCopy(chocoPath, chocoInstall, ARRAY_SIZE(chocoPath));
ffStrCopy(pend, "/lib/*", ARRAY_SIZE(chocoPath) - (size_t) (pend - chocoPath));
result->choco = getNumElements(chocoPath, FILE_ATTRIBUTE_DIRECTORY, "choco");
ffStrCopy(pend, "/lib/", ARRAY_SIZE(chocoPath) - (size_t) (pend - chocoPath));
result->choco = getNumElements(chocoPath, FILE_ATTRIBUTE_DIRECTORY, L"choco");
}
static void detectPacman(FFPackagesResult* result)
@@ -104,7 +132,7 @@ static void detectPacman(FFPackagesResult* result)
// MSYS2
char pacmanPath[MAX_PATH + 3];
char* pend = ffStrCopy(pacmanPath, msystemPrefix, ARRAY_SIZE(pacmanPath));
ffStrCopy(pend, "/../var/lib/pacman/local/*", ARRAY_SIZE(pacmanPath) - (size_t) (pend - pacmanPath));
ffStrCopy(pend, "/../var/lib/pacman/local/", ARRAY_SIZE(pacmanPath) - (size_t) (pend - pacmanPath));
result->pacman = getNumElements(pacmanPath, FILE_ATTRIBUTE_DIRECTORY, NULL);
}
+16
View File
@@ -232,3 +232,19 @@ typedef struct _D3DKMT_NODEMETADATA
static_assert(sizeof(D3DKMT_NODEMETADATA) == 0x4E, "D3DKMT_NODEMETADATA structure size mismatch");
#endif
NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan);