Files

95 lines
3.4 KiB
C++

#pragma once
#include <windows.h>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <span>
#include <stdexcept>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <unordered_map>
#include <vector>
namespace wl {
// All narrow application strings, index names, IPC and redirected text are UTF-8.
// UTF-16 is used only when interfacing with Windows' W/Shell APIs and UI controls.
constexpr uint32_t no_row = UINT32_MAX;
constexpr uint32_t deleted_attribute = 0x80000000;
class Error : public std::runtime_error { public: using std::runtime_error::runtime_error; };
inline void require_utf8_process() {
if (GetACP() != CP_UTF8) throw Error("WLocate requires the embedded UTF-8 manifest and Windows 10 version 1903 or later");
}
struct Handle {
HANDLE value = INVALID_HANDLE_VALUE;
Handle() = default;
explicit Handle(HANDLE h) : value(h) {}
~Handle() { reset(); }
Handle(const Handle&) = delete;
Handle& operator=(const Handle&) = delete;
Handle(Handle&& h) noexcept : value(std::exchange(h.value, INVALID_HANDLE_VALUE)) {}
Handle& operator=(Handle&& h) noexcept { if (this != &h) { reset(); value = std::exchange(h.value, INVALID_HANDLE_VALUE); } return *this; }
explicit operator bool() const { return value != nullptr && value != INVALID_HANDLE_VALUE; }
void reset(HANDLE h = INVALID_HANDLE_VALUE) { if (*this) CloseHandle(value); value = h; }
};
std::string utf8(std::wstring_view value);
std::wstring wide(std::string_view value);
std::string fold(std::string_view value);
std::string win_error(DWORD code = GetLastError());
std::wstring module_path();
std::filesystem::path data_directory();
uint64_t filetime_now();
uint64_t filetime_value(FILETIME value);
bool is_admin();
void log(std::string_view text);
bool read_exact(HANDLE file, void* data, size_t size);
bool write_exact(HANDLE file, const void* data, size_t size);
std::string filename(std::string_view path);
std::string directory(std::string_view path);
std::string normalize_path(std::string value);
// Trigram presence filter. Collisions only cause extra checks, never false negatives.
inline uint64_t name_bloom(std::string_view value) {
uint64_t mask = 0;
for (size_t i = 2; i < value.size(); ++i) {
uint32_t gram = uint8_t(value[i - 2]) | (uint32_t(uint8_t(value[i - 1])) << 8) | (uint32_t(uint8_t(value[i])) << 16);
gram ^= gram >> 11; gram *= 0x9E3779B1u; mask |= 1ull << (gram >> 26);
}
return mask;
}
struct Result {
std::string path;
uint64_t size = 0, modified = 0, created = 0, accessed = 0;
uint32_t attributes = 0;
};
enum QueryFlag : uint32_t {
MatchCase = 1, MatchPath = 2, Regex = 4, WholeWord = 8,
Basename = 16, AllPatterns = 32, CountOnly = 64, Existing = 128,
NonExisting = 256, EverythingSyntax = 512
};
enum class Sort : uint32_t { Name, Path, Size, Modified, Created, Extension, None };
struct Request {
uint32_t operation = 0;
uint32_t flags = 0;
uint64_t limit = UINT64_MAX, offset = 0;
Sort sort = Sort::Name;
bool descending = false;
uint32_t timeout_ms = 120000;
std::vector<std::string> patterns;
};
struct Reply {
uint64_t total = 0, generation = 0, search_us = 0;
std::vector<Result> results;
std::string message;
};
}