Merge pull request #2244 from fastfetch-cli/dev

Release: v2.61.0
This commit is contained in:
Carter Li
2026-03-28 14:10:34 +08:00
committed by GitHub
200 changed files with 5499 additions and 2330 deletions
+19 -30
View File
@@ -38,7 +38,7 @@ jobs:
run: uname -a
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_THREADS=OFF
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -93,7 +93,7 @@ jobs:
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev rpm ninja-build
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
- name: install linuxbrew packages
run: |
@@ -107,7 +107,7 @@ jobs:
languages: c
- name: configure project
run: CC=gcc-13 CXX=g++-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -190,7 +190,7 @@ jobs:
run: cmake --version
- name: configure project
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_DIRECTX_HEADERS=Off .
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -237,17 +237,17 @@ jobs:
id: runcmd
with:
arch: armv7
distro: ubuntu20.04
distro: ubuntu22.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
add-apt-repository -y ppa:ubuntu-toolchain-r/test
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -283,7 +283,7 @@ jobs:
uname -a
apt-get update && apt-get install -y wget
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -326,7 +326,7 @@ jobs:
apt-get update && apt-get install -y software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -413,10 +413,10 @@ jobs:
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --format json
- name: run flashfetch
run: time ./flashfetch
@@ -690,7 +690,7 @@ jobs:
path: ./fastfetch-*.*
windows-hosts:
name: Windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
name: Windows-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
@@ -703,22 +703,11 @@ jobs:
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
win7-compat-flag: OFF
win7-compat-postfix: ""
- arch: amd64
runs-on: windows-latest
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
win7-compat-flag: ON
win7-compat-postfix: "-win7"
- arch: aarch64
runs-on: windows-11-arm
msystem: CLANGARM64
msystem-lower: clangarm64
msys-arch: aarch64
win7-compat-flag: OFF
win7-compat-postfix: ""
defaults:
run:
shell: msys2 {0}
@@ -731,13 +720,13 @@ jobs:
with:
msystem: ${{ matrix.msystem }}
update: true
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa mingw-w64-clang-${{ matrix.msys-arch }}-directx-headers
- name: print msys version
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_WIN7_COMPAT=${{ matrix.win7-compat-flag }} .
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose -j4
@@ -768,7 +757,7 @@ jobs:
name: upload artifacts for signing
uses: actions/upload-artifact@v7
with:
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
name: fastfetch-windows-${{ matrix.arch }}
path: |
*.dll
fastfetch.exe
@@ -787,16 +776,16 @@ jobs:
output-artifact-directory: '.'
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload true artifacts
uses: actions/upload-artifact@v7
with:
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
path: ./fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.*
name: fastfetch-windows-${{ matrix.arch }}
path: ./fastfetch-windows-${{ matrix.arch }}.*
overwrite: true
release:
+31
View File
@@ -1,3 +1,34 @@
# 2.61.0
Changes:
* Support for Windows 7 and 8 has been removed.
* Windows 8.1 is now the oldest version supported by fastfetch.
* The GPU module on WSL no longer relies on `DXCore`.
* The `directx-headers` dependency is no longer required.
* Fastfetch on Linux is now pure C; a C++ compiler is no longer required.
* GPU type detection is now slightly less accurate, but detection speed should be slightly faster.
* The GPU module on Windows now uses `DXCore` for more accurate GPU type detection (requires Windows 10 or later).
* This feature is built only when `DXCore` headers are available, which requires installing `mingw-w64-<msystem>-x86_64-directx-headers` on MSYS2.
Features:
* Adds a `brightness` option for color display configuration (#2238, Colors)
* Adds support for detecting Bluetooth keyboards on Linux (#2220, Keyboard)
* Adds support for detecting GlazeWM (WM, macOS)
* Adds a `showEmptySlots` option to display empty memory slots on Linux (#2222, PhysicalMemory)
* Adds marketing product name detection on Asahi Linux (Host, Linux)
* Adds support for new M5 Mac models (Host, macOS)
* Improves SMBIOS robustness by validating malformed data and improving error handling
* Improves reliability when terminating child processes (Processing, Windows)
* Improves Intel Mac support by querying SMBIOS data directly (Global, macOS)
* Includes numerous internal cleanups and optimizations
Bugfixes:
* Fixes missing memory devices on some machines (PhysicalMemory)
* Fixes CPUCache deduplication for shared caches (#2228, CPUCache, Linux)
* Fixes WM version reporting for niri (#2218, WM, Linux)
* Fixes SSID decoding issues from `iw` output (Wifi, Linux)
* Fixes the CMD code page being changed after running fastfetch on Windows (#2245, Windows)
# 2.60.0
Changes:
+34 -30
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.60.0
VERSION 2.61.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -89,7 +89,6 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR Ope
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR ANDROID OR GNU" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
@@ -107,7 +106,7 @@ option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `pyt
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
option(ENABLE_LIBZFS "Enable libzfs" ON)
if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" OFF)
option(ENABLE_WIN81_COMPAT "Enable legacy Windows compatibility (Windows 8.1 and later; Windows 7 unsupported)" ON)
endif()
if(APPLE)
option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF)
@@ -159,7 +158,7 @@ set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=retu
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion")
if(WIN32 OR Haiku OR ENABLE_DIRECTX_HEADERS)
if(WIN32 OR Haiku)
enable_language(CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
@@ -168,8 +167,8 @@ endif()
if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id")
if(ENABLE_WIN7_COMPAT)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,6,--minor-os-version,1")
if(ENABLE_WIN81_COMPAT)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,6,--minor-os-version,3")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,10,--minor-os-version,0")
endif()
@@ -305,7 +304,8 @@ if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids
RESULT_VARIABLE PYTHON_PCIIDS_RETCODE)
if(NOT PYTHON_PCIIDS_RETCODE EQUAL 0)
file(REMOVE "${PROJECT_BINARY_DIR}/fastfetch_pciids.c.inc")
message(FATAL_ERROR "Failed to generate 'fastfetch_pciids.c.inc'")
message(WARNING "Failed to generate 'fastfetch_pciids.c.inc'")
set(ENABLE_EMBEDDED_PCIIDS OFF)
endif()
else()
message(WARNING "Python3 is not found, 'fastfetch_pciids.c.inc' will not be generated")
@@ -325,7 +325,8 @@ if(ENABLE_EMBEDDED_AMDGPUIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_amd
RESULT_VARIABLE PYTHON_AMDGPUIDS_RETCODE)
if(NOT PYTHON_AMDGPUIDS_RETCODE EQUAL 0)
file(REMOVE "${PROJECT_BINARY_DIR}/fastfetch_amdgpuids.c.inc")
message(FATAL_ERROR "Failed to generate 'fastfetch_amdgpuids.c.inc'")
message(WARNING "Failed to generate 'fastfetch_amdgpuids.c.inc'")
set(ENABLE_EMBEDDED_AMDGPUIDS OFF)
endif()
else()
message(WARNING "Python3 is not found, 'fastfetch_amdgpuids.c.inc' will not be generated")
@@ -413,6 +414,7 @@ set(LIBFASTFETCH_SRC
src/detection/editor/editor.c
src/detection/font/font.c
src/detection/gpu/gpu.c
src/detection/host/host_mac.c
src/detection/media/media.c
src/detection/netio/netio.c
src/detection/opencl/opencl.c
@@ -559,9 +561,9 @@ if(LINUX)
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gpu/gpu_wsl.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
src/detection/host/host_mac.c
src/detection/icons/icons_linux.c
src/detection/initsystem/initsystem_linux.c
src/detection/keyboard/keyboard_linux.c
@@ -720,7 +722,6 @@ elseif(FreeBSD)
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
src/detection/host/host_mac.c
src/detection/lm/lm_linux.c
src/detection/icons/icons_linux.c
src/detection/initsystem/initsystem_linux.c
@@ -947,14 +948,11 @@ elseif(APPLE)
src/common/apple/osascript.m
src/common/apple/smc_temps.c
src/detection/battery/battery_apple.c
src/detection/bios/bios_apple.c
src/detection/bluetooth/bluetooth_apple.m
src/detection/bluetoothradio/bluetoothradio_apple.m
src/detection/board/board_apple.c
src/detection/bootmgr/bootmgr_apple.c
src/detection/brightness/brightness_apple.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_apple.c
src/detection/cpu/cpu_apple.c
src/detection/cpucache/cpucache_apple.c
src/detection/cpuusage/cpuusage_apple.c
@@ -962,14 +960,11 @@ elseif(APPLE)
src/detection/disk/disk_bsd.c
src/detection/dns/dns_apple.c
src/detection/physicaldisk/physicaldisk_apple.c
src/detection/physicalmemory/physicalmemory_apple.m
src/detection/diskio/diskio_apple.c
src/detection/displayserver/displayserver_apple.c
src/detection/font/font_apple.m
src/detection/gpu/gpu_apple.c
src/detection/gpu/gpu_apple.m
src/detection/host/host_apple.c
src/detection/host/host_mac.c
src/detection/icons/icons_nosupport.c
src/detection/initsystem/initsystem_linux.c
src/detection/keyboard/keyboard_apple.c
@@ -1005,6 +1000,24 @@ elseif(APPLE)
src/detection/wmtheme/wmtheme_apple.m
src/detection/camera/camera_apple.m
)
# CMAKE_SYSTEM_PROCESSOR has been normalized before
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
list(APPEND LIBFASTFETCH_SRC
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
src/detection/chassis/chassis_windows.c
src/detection/host/host_windows.c
src/detection/physicalmemory/physicalmemory_linux.c
)
else()
list(APPEND LIBFASTFETCH_SRC
src/detection/bios/bios_apple.c
src/detection/board/board_apple.c
src/detection/chassis/chassis_apple.c
src/detection/host/host_apple.c
src/detection/physicalmemory/physicalmemory_apple.m
)
endif()
elseif(WIN32)
list(APPEND LIBFASTFETCH_SRC
src/common/impl/io_windows.c
@@ -1043,7 +1056,7 @@ elseif(WIN32)
src/detection/dns/dns_windows.c
src/detection/font/font_windows.c
src/detection/gpu/gpu_windows.c
src/detection/host/host_mac.c
src/detection/gpu/gpu_windows.cpp
src/detection/host/host_windows.c
src/detection/icons/icons_windows.c
src/detection/initsystem/initsystem_nosupport.c
@@ -1313,11 +1326,6 @@ elseif(GNU)
)
endif()
if(ENABLE_DIRECTX_HEADERS)
message(STATUS "Enabling DirectX headers for WSL")
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_wsl.cpp)
endif()
# Proprietary GPU driver APIs
if(LINUX OR FreeBSD OR WIN32)
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c)
@@ -1463,10 +1471,10 @@ if(WIN32)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MSVC_MSIZE=1)
endif()
if(ENABLE_WIN7_COMPAT)
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=1)
if(ENABLE_WIN81_COMPAT)
target_compile_definitions(libfastfetch PUBLIC FF_WIN81_COMPAT=1)
else()
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=0)
target_compile_definitions(libfastfetch PUBLIC FF_WIN81_COMPAT=0)
endif()
else()
check_function_exists(malloc_usable_size HAVE_MALLOC_USABLE_SIZE)
@@ -1659,10 +1667,6 @@ ff_lib_enable(ELF
"libelf"
"libelf"
)
ff_lib_enable(DIRECTX_HEADERS
"DirectX-Headers"
"DirectX-Headers"
)
if(ENABLE_THREADS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
@@ -1738,7 +1742,7 @@ elseif(WIN32)
PRIVATE "winbrand"
PRIVATE "secur32"
)
if(NOT ENABLE_WIN7_COMPAT)
if(NOT ENABLE_WIN81_COMPAT)
target_link_libraries(libfastfetch
PRIVATE "mincore"
)
+3 -1
View File
@@ -13,7 +13,9 @@
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
[![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-red)](README-cn.md)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris).
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 8.1+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris).
> Note: Fastfetch is only actively tested on x86-64 and aarch64 platforms. It may work on other platforms but is not guaranteed to do so.
<img src="screenshots/example1.png" width="49%" align="left" />
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
+27 -3
View File
@@ -342,7 +342,7 @@
"type": "string"
},
"displayFormat": {
"description": "Output format of the module `Display`. See Wiki for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)",
"description": "Output format of the module `Display`. See Wiki for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)\n 25. {dpi}: DPI",
"type": "string"
},
"diskFormat": {
@@ -450,7 +450,7 @@
"type": "string"
},
"physicalmemoryFormat": {
"description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled",
"description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled\n 12. {is-installed}: True if a memory module is installed in the slot",
"type": "string"
},
"playerFormat": {
@@ -2044,7 +2044,7 @@
"default": 0
},
"block": {
"description": "Set behavior of block printing",
"description": "Set behavior of block printing. Only works when symbol is set to `block` or `background`",
"type": "object",
"additionalProperties": false,
"properties": {
@@ -2067,6 +2067,25 @@
}
}
},
"brightness": {
"description": "Set the brightness of colors. Works together with the block color range to determine which colors are displayed",
"type": "string",
"oneOf": [
{
"const": "default",
"description": "Use the default setting (block/background: 0-15, others: 8-1)"
},
{
"const": "light",
"description": "Use ANSI bright foreground colors (codes 90-97, not color indices 9-15)"
},
{
"const": "normal",
"description": "Use normal ANSI colors (30-37; standard foreground colors, corresponding to color indices 0-7)"
}
],
"default": "default"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -3650,6 +3669,11 @@
"const": "physicalmemory",
"description": "Print system physical memory devices"
},
"showEmptySlots": {
"description": "Set if uninstalled memory slots should be printed",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
+3
View File
@@ -6,6 +6,9 @@ def main(amdgpu_ids_path: str):
with open(amdgpu_ids_path, 'r') as f:
full_text = f.read()
if full_text == '':
sys.exit(f'Error: {amdgpu_ids_path} file is empty')
products = []
for line in full_text.split('\n'):
if not line or line[0] == '#' or not ',\t' in line:
+3
View File
@@ -18,6 +18,9 @@ def main(keep_vendor_list: set, pci_ids_path: str):
with open(pci_ids_path, 'r') as f:
full_text = f.read()
if full_text == '':
sys.exit(f'Error: {pci_ids_path} file is empty')
dev_list_text = full_text[:full_text.rfind('\n\n\n')] # remove known classes
for line in dev_list_text.split('\n'):
if not line or line[0] == '#':
+9
View File
@@ -106,6 +106,15 @@ static inline void ffListClear(FFlist* list)
list->length = 0;
}
static inline void ffListReserve(FFlist* list, uint32_t newCapacity)
{
if (__builtin_expect(newCapacity <= list->capacity, false))
return;
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * list->elementSize);
list->capacity = newCapacity;
}
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
assert(sizeof(itemType) == (listVar).elementSize); \
for(itemType* itemVarName = (itemType*)(listVar).data; \
+4
View File
@@ -230,6 +230,7 @@ static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
}
// Despite the name, this function resets strbuf to the initial/unallocated state
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
{
if(strbuf->allocated > 0)
@@ -627,4 +628,7 @@ static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
// Returns true if the strbuf is modified
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
#define FF_STRBUF_AUTO_DESTROY FFstrbuf __attribute__((__cleanup__(ffStrbufDestroy)))
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include "common/FFstrbuf.h"
// For ffRegReadValue(s)
// If length is 0, data will be allocated with malloc() and must be freed by the caller
// Otherwise, data must point to a buffer of at least length bytes, and the actual length of the data will be written to length.
typedef struct FFArgBuffer
{
void* data;
uint32_t length;
} FFArgBuffer;
typedef enum __attribute__((__packed__)) FFArgType
{
FF_ARG_TYPE_NULL = 0,
FF_ARG_TYPE_UINT,
FF_ARG_TYPE_UINT64,
FF_ARG_TYPE_UINT16,
FF_ARG_TYPE_UINT8,
FF_ARG_TYPE_INT,
FF_ARG_TYPE_STRING,
FF_ARG_TYPE_STRBUF,
FF_ARG_TYPE_FLOAT,
FF_ARG_TYPE_DOUBLE,
FF_ARG_TYPE_LIST,
FF_ARG_TYPE_BOOL,
FF_ARG_TYPE_BUFFER,
} FFArgType;
#define FF_ARG(variable, var_name) { _Generic((variable), \
uint32_t: FF_ARG_TYPE_UINT, \
uint64_t: FF_ARG_TYPE_UINT64, \
uint16_t: FF_ARG_TYPE_UINT16, \
uint8_t: FF_ARG_TYPE_UINT8, \
int32_t: FF_ARG_TYPE_INT, \
char*: FF_ARG_TYPE_STRING, \
const char*: FF_ARG_TYPE_STRING, \
FFstrbuf: FF_ARG_TYPE_STRBUF, \
float: FF_ARG_TYPE_FLOAT, \
double: FF_ARG_TYPE_DOUBLE, \
FFlist: FF_ARG_TYPE_LIST, \
bool: FF_ARG_TYPE_BOOL, \
FFArgBuffer: FF_ARG_TYPE_BUFFER \
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
+3 -1
View File
@@ -29,5 +29,7 @@ static inline const char* ffFindFileName(const char* file)
#define FF_DEBUG(format, ...) FF_DEBUG_PRINT(__FILE__, __LINE__, format, ##__VA_ARGS__)
#if _WIN32
const char* ffDebugWin32Error(unsigned long errorCode);
const char* ffDebugWin32Error(DWORD errorCode);
const char* ffDebugNtStatus(NTSTATUS status);
const char* ffDebugHResult(HRESULT hr);
#endif
+1
View File
@@ -10,3 +10,4 @@ void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint3
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week);
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length);
+2 -33
View File
@@ -1,41 +1,10 @@
#pragma once
#include "common/FFstrbuf.h"
typedef enum __attribute__((__packed__)) FFformatArgType
{
FF_FORMAT_ARG_TYPE_NULL = 0,
FF_FORMAT_ARG_TYPE_UINT,
FF_FORMAT_ARG_TYPE_UINT64,
FF_FORMAT_ARG_TYPE_UINT16,
FF_FORMAT_ARG_TYPE_UINT8,
FF_FORMAT_ARG_TYPE_INT,
FF_FORMAT_ARG_TYPE_STRING,
FF_FORMAT_ARG_TYPE_STRBUF,
FF_FORMAT_ARG_TYPE_FLOAT,
FF_FORMAT_ARG_TYPE_DOUBLE,
FF_FORMAT_ARG_TYPE_LIST,
FF_FORMAT_ARG_TYPE_BOOL
} FFformatArgType;
#define FF_FORMAT_ARG(variable, var_name) { _Generic((variable), \
uint32_t: FF_FORMAT_ARG_TYPE_UINT, \
uint64_t: FF_FORMAT_ARG_TYPE_UINT64, \
uint16_t: FF_FORMAT_ARG_TYPE_UINT16, \
uint8_t: FF_FORMAT_ARG_TYPE_UINT8, \
int32_t: FF_FORMAT_ARG_TYPE_INT, \
char*: FF_FORMAT_ARG_TYPE_STRING, \
const char*: FF_FORMAT_ARG_TYPE_STRING, \
FFstrbuf: FF_FORMAT_ARG_TYPE_STRBUF, \
float: FF_FORMAT_ARG_TYPE_FLOAT, \
double: FF_FORMAT_ARG_TYPE_DOUBLE, \
FFlist: FF_FORMAT_ARG_TYPE_LIST, \
bool: FF_FORMAT_ARG_TYPE_BOOL \
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
#include "common/argType.h"
typedef struct FFformatarg
{
FFformatArgType type;
FFArgType type;
const void* value;
const char* name; // argument name, must start with an alphabet
} FFformatarg;
+45 -52
View File
@@ -1,12 +1,12 @@
#include "FFPlatform_private.h"
#include "common/io.h"
#include "common/library.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/windows/nt.h"
#include <stdalign.h>
#include <windows.h>
#include <shlobj.h>
#include <sddl.h>
@@ -17,20 +17,32 @@
static void getExePath(FFPlatform* platform)
{
wchar_t exePathW[MAX_PATH];
DWORD exePathWLen = GetModuleFileNameW(NULL, exePathW, MAX_PATH);
if (exePathWLen == 0 || exePathWLen >= MAX_PATH) return;
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(exePathW, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(
ffGetPeb()->ProcessParameters->ImagePathName.Buffer,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (hPath != INVALID_HANDLE_VALUE)
{
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_OPENED);
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
if (len > 0 && len < MAX_PATH)
exePathWLen = len;
{
ffStrbufSetNWS(&platform->exePath, len, exePathW);
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
ffStrbufSubstrAfter(&platform->exePath, 3);
}
}
if (platform->exePath.length == 0)
{
PCUNICODE_STRING imagePathName = &ffGetPeb()->ProcessParameters->ImagePathName;
ffStrbufSetNWS(&platform->exePath, imagePathName->Length / sizeof(wchar_t), imagePathName->Buffer);
}
ffStrbufSetNWS(&platform->exePath, exePathWLen, exePathW);
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
ffStrbufSubstrAfter(&platform->exePath, 3);
ffStrbufReplaceAllC(&platform->exePath, '\\', '/');
}
@@ -145,30 +157,18 @@ static void getUserName(FFPlatform* platform)
size = ARRAY_SIZE(buffer);
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
{
ffStrbufSetWS(&platform->userName, buffer);
size = 0;
DWORD refDomainSize = 0;
SID_NAME_USE sidNameUse = SidTypeUnknown;
LookupAccountNameW(NULL, buffer, NULL, &size, NULL, &refDomainSize, &sidNameUse);
if (size > 0)
{
FF_AUTO_FREE PSID sid = (PSID) malloc(size);
FF_AUTO_FREE LPWSTR refDomain = (LPWSTR) malloc(refDomainSize * sizeof(wchar_t));
if (LookupAccountNameW(NULL, buffer, sid, &size, refDomain, &refDomainSize, &sidNameUse))
{
LPWSTR sidString;
if (ConvertSidToStringSidW(sid, &sidString))
{
ffStrbufSetWS(&platform->sid, sidString);
LocalFree(sidString);
}
}
}
}
else
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
alignas(TOKEN_USER) char buf[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size)))
{
TOKEN_USER* tokenUser = (TOKEN_USER*) buf;
UNICODE_STRING sidString = { .Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer) };
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE)))
ffStrbufSetNWS(&platform->sid, sidString.Length / sizeof(wchar_t), sidString.Buffer);
}
}
static void getHostName(FFPlatform* platform)
@@ -199,7 +199,7 @@ static void getUserShell(FFPlatform* platform)
static const char* detectWine(void)
{
const char * __cdecl wine_get_version(void);
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
if (!hntdll) return NULL;
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
if (!ffwine_get_version) return NULL;
@@ -208,30 +208,28 @@ static const char* detectWine(void)
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
{
FF_HKEY_AUTO_DESTROY hKey = NULL;
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
return;
uint32_t ubr = 0;
ffRegReadUint(hKey, L"UBR", &ubr, NULL);
ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
FF_ARG(ubr, L"UBR"),
FF_ARG(info->version, L"BuildLabEx"),
}, NULL);
ffStrbufAppendF(&info->release,
PPEB_FULL peb = ffGetPeb();
ffStrbufSetF(&info->release,
"%u.%u.%u.%u",
(unsigned) SharedUserData->NtMajorVersion,
(unsigned) SharedUserData->NtMinorVersion,
(unsigned) SharedUserData->NtBuildNumber,
(unsigned) peb->OSMajorVersion,
(unsigned) peb->OSMinorVersion,
(unsigned) peb->OSBuildNumber,
(unsigned) ubr);
ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL);
const char* wineVersion = detectWine();
if (wineVersion)
{
if (instance.config.general.detectVersion)
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
ffStrbufSetStatic(&info->name, "Wine");
}
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
ffStrbufSetStatic(&info->name, "WIN32_NT");
}
@@ -303,12 +301,7 @@ static void getSystemArchitecture(FFPlatformSysinfo* info)
static void getCwd(FFPlatform* platform)
{
#if _WIN64
static_assert(
offsetof(RTL_USER_PROCESS_PARAMETERS, Reserved2[5]) == 0x38,
"CurrentDirectory should be at offset 0x38 in RTL_USER_PROCESS_PARAMETERS. Structure layout mismatch detected.");
#endif
PCURDIR cwd = (PCURDIR) &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Reserved2[5];
PCURDIR cwd = &ffGetPeb()->ProcessParameters->CurrentDirectory;
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
@@ -316,7 +309,7 @@ static void getCwd(FFPlatform* platform)
void ffPlatformInitImpl(FFPlatform* platform)
{
platform->pid = (uint32_t) GetCurrentProcessId();
platform->pid = (uint32_t) (uintptr_t) ffGetTeb()->ClientId.UniqueProcess;
getExePath(platform);
getCwd(platform);
getHomeDir(platform);
+1 -5
View File
@@ -6,11 +6,7 @@
void* ffListAdd(FFlist* list)
{
if(list->length == list->capacity)
{
list->capacity = list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2;
// realloc(NULL, newSize) is same as malloc(newSize)
list->data = realloc(list->data, (size_t)list->capacity * list->elementSize);
}
ffListReserve(list, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
++list->length;
return ffListGet(list, list->length - 1);
+42
View File
@@ -1,5 +1,6 @@
#include "common/FFstrbuf.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
#include <ctype.h>
#include <inttypes.h>
@@ -915,3 +916,44 @@ bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLeng
return false;
}
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf)
{
assert(strbuf);
if (strbuf->length < 4)
return false;
// Static string must be converted first.
assert(strbuf->allocated > 0);
bool changed = false;
uint32_t read = 0;
uint32_t write = 0;
while (read < strbuf->length)
{
if (
read + 3 < strbuf->length &&
strbuf->chars[read] == '\\' &&
strbuf->chars[read + 1] == 'x'
)
{
int8_t hi = ffHexCharToInt(strbuf->chars[read + 2]);
int8_t lo = ffHexCharToInt(strbuf->chars[read + 3]);
if (hi >= 0 && lo >= 0)
{
strbuf->chars[write++] = (char) ((hi << 4) | lo);
read += 4;
changed = true;
continue;
}
}
strbuf->chars[write++] = strbuf->chars[read++];
}
strbuf->length = write;
strbuf->chars[write] = '\0';
return changed;
}
+9 -8
View File
@@ -21,18 +21,19 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st
if (hFile == INVALID_HANDLE_VALUE)
return "CreateFileA() failed";
FF_AUTO_CLOSE_FD HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMap)
return "CreateFileMappingW() failed";
FF_AUTO_CLOSE_FD HANDLE hSection = NULL;
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile)))
return "NtCreateSection() failed";
void* base = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (!base)
return "MapViewOfFile() failed";
PVOID base = NULL;
SIZE_T viewSize = 0;
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY)))
return "NtMapViewOfSection() failed";
PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base);
if (!ntHeaders)
{
UnmapViewOfFile(base);
NtUnmapViewOfSection(NtCurrentProcess(), base);
return "RtlImageNtHeader() failed";
}
@@ -61,6 +62,6 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st
}
}
UnmapViewOfFile(base);
NtUnmapViewOfSection(NtCurrentProcess(), base);
return NULL;
}
+26 -4
View File
@@ -10,7 +10,7 @@ const char* ffDebugWin32Error(DWORD errorCode)
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD) errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
0,
buffer,
sizeof(buffer),
NULL);
@@ -19,10 +19,32 @@ const char* ffDebugWin32Error(DWORD errorCode)
snprintf(buffer, sizeof(buffer), "Unknown error code (%lu)", errorCode);
} else {
// Remove trailing newline
if (buffer[len - 1] == '\n') buffer[len - 1] = '\0';
if (buffer[len - 2] == '\r') buffer[len - 2] = '\0';
snprintf(buffer + len - 2, sizeof(buffer) - len + 2, " (%lu)", errorCode);
while (len > 0 && (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')) {
buffer[--len] = '\0';
}
snprintf(buffer + len, sizeof(buffer) - len + 2, " (%lu)", errorCode);
}
return buffer;
}
const char* ffDebugNtStatus(NTSTATUS status)
{
return ffDebugWin32Error(RtlNtStatusToDosError(status));
}
static inline DWORD HRESULTToWin32Error(HRESULT hr)
{
if (SUCCEEDED(hr))
return ERROR_SUCCESS;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
return HRESULT_CODE(hr);
return ERROR_INTERNAL_ERROR;
}
const char* ffDebugHResult(HRESULT hr)
{
return ffDebugWin32Error(HRESULTToWin32Error(hr));
}
+13
View File
@@ -128,3 +128,16 @@ bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length)
}
return false;
}
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length)
{
if (length < 128 || length % 128 != 0) return false;
static const uint8_t edidHeader[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
if (memcmp(edid, edidHeader, sizeof(edidHeader)) != 0) return false;
uint8_t sum = 0;
for (uint32_t i = 0; i < 128; i++) sum += edid[i];
return sum == 0;
}
+29 -22
View File
@@ -10,37 +10,37 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
{
switch(formatarg->type)
{
case FF_FORMAT_ARG_TYPE_INT:
case FF_ARG_TYPE_INT:
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT:
case FF_ARG_TYPE_UINT:
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT64:
case FF_ARG_TYPE_UINT64:
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT16:
case FF_ARG_TYPE_UINT16:
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT8:
case FF_ARG_TYPE_UINT8:
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_STRING:
case FF_ARG_TYPE_STRING:
ffStrbufAppendS(buffer, (const char*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_STRBUF:
case FF_ARG_TYPE_STRBUF:
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_FLOAT:
case FF_ARG_TYPE_FLOAT:
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_DOUBLE:
case FF_ARG_TYPE_DOUBLE:
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_BOOL:
case FF_ARG_TYPE_BOOL:
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
break;
case FF_FORMAT_ARG_TYPE_LIST:
case FF_ARG_TYPE_LIST:
{
const FFlist* list = (const FFlist*) formatarg->value;
for(uint32_t i = 0; i < list->length; i++)
@@ -51,8 +51,15 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
}
break;
}
case FF_ARG_TYPE_BUFFER:
{
// Placeholder for binary data, just print the size for now
const FFArgBuffer* argBuffer = (const FFArgBuffer*) formatarg->value;
ffStrbufAppendF(buffer, "buffer(%u bytes)", argBuffer->length);
break;
}
default:
if(formatarg->type != FF_FORMAT_ARG_TYPE_NULL)
if(formatarg->type != FF_ARG_TYPE_NULL)
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
break;
}
@@ -107,16 +114,16 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_BOOL && *(bool*)arg->value) ||
(arg->type == FF_FORMAT_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
(arg->type == FF_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
(arg->type == FF_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
(arg->type == FF_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
(arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
(arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
(arg->type == FF_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
(arg->type == FF_ARG_TYPE_BOOL && *(bool*)arg->value) ||
(arg->type == FF_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
);
}
+19 -13
View File
@@ -55,12 +55,15 @@ void ffInitInstance(void)
setlocale(LC_TIME, "");
#endif
initState(&instance.state);
defaultConfig();
initState(&instance.state);
}
static volatile bool ffDisableLinewrap = true;
static volatile bool ffHideCursor = true;
#if _WIN32
static volatile UINT oldCp = CP_UTF8;
#endif
static void resetConsole(void)
{
@@ -70,12 +73,15 @@ static void resetConsole(void)
if(ffHideCursor)
fputs("\033[?25h", stdout);
#if defined(_WIN32)
fflush(stdout);
#endif
if(instance.state.dynamicInterval > 0)
fputs("\033[?1049l", stdout); // Disable alternate buffer
#if defined(_WIN32)
fflush(stdout);
if(oldCp != CP_UTF8)
SetConsoleOutputCP(oldCp);
#endif
}
#ifdef _WIN32
@@ -106,9 +112,12 @@ void ffStart(void)
SetConsoleCtrlHandler(consoleHandler, TRUE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdout, &mode);
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
SetConsoleOutputCP(CP_UTF8);
if (GetConsoleMode(hStdout, &mode))
{
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
oldCp = GetConsoleOutputCP();
if (oldCp != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
}
#else
if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0);
struct sigaction action = { .sa_handler = exitSignalHandler };
@@ -237,9 +246,6 @@ void ffListFeatures(void)
#if FF_HAVE_LIBZFS
"libzfs\n"
#endif
#if FF_HAVE_DIRECTX_HEADERS
"Directx Headers\n"
#endif
#if FF_USE_SYSTEM_YYJSON
"System yyjson\n"
#endif
@@ -252,8 +258,8 @@ void ffListFeatures(void)
#if FF_HAVE_EMBEDDED_PCIIDS
"Embedded pciids\n"
#endif
#if FF_WIN7_COMPAT
"Windows 7 Compatibility\n"
#if FF_WIN81_COMPAT
"Windows 8.1 Compatibility\n"
#endif
#if FF_APPLE_MEMSIZE_USABLE
"Apple memsize_usable\n"
-36
View File
@@ -97,42 +97,6 @@ bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
return buffer->length > 0;
}
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
{
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
if(fd == -1)
return -1;
return ffReadFDData(fd, dataSize, data);
}
ssize_t ffReadFileDataRelative(int dfd, const char* fileName, size_t dataSize, void* data)
{
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if(fd == -1)
return -1;
return ffReadFDData(fd, dataSize, data);
}
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
{
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
if(fd == -1)
return false;
return ffAppendFDBuffer(fd, buffer);
}
bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
{
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if(fd == -1)
return false;
return ffAppendFDBuffer(fd, buffer);
}
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
{
bool result = false;
+179 -68
View File
@@ -1,32 +1,172 @@
#include "common/io.h"
#include "fastfetch.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/windows/nt.h"
#include "common/windows/unicode.h"
#include <windows.h>
#include "common/windows/nt.h"
#include <ntstatus.h>
static void createSubfolders(const char* fileName)
static bool createSubfolders(wchar_t* fileName)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
char *token = NULL;
while((token = strchr(fileName, '/')) != NULL)
HANDLE hRoot = ffGetPeb()->ProcessParameters->CurrentDirectory.Handle;
bool closeRoot = false;
wchar_t* ptr = fileName;
// Absolute drive path: C:\...
if (ffCharIsEnglishAlphabet((char)ptr[0]) && ptr[1] == L':' && ptr[2] == L'\\')
{
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
CreateDirectoryA(path.chars, NULL);
fileName = token + 1;
wchar_t saved = ptr[3];
ptr[3] = L'\0';
hRoot = CreateFileW(
fileName,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
ptr[3] = saved;
if (hRoot == INVALID_HANDLE_VALUE)
return false;
closeRoot = true;
ptr += 3; // skip "C:\"
}
// UNC path: \\server\share\...
else if (ptr[0] == L'\\' && ptr[1] == L'\\')
{
wchar_t* serverEnd = wcschr(ptr + 2, L'\\');
if (serverEnd == NULL)
return false;
wchar_t* shareEnd = wcschr(serverEnd + 1, L'\\');
if (shareEnd == NULL)
return true; // no parent subfolder exists before file name
wchar_t saved = *shareEnd;
*shareEnd = L'\0';
hRoot = CreateFileW(
fileName,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
*shareEnd = saved;
if (hRoot == INVALID_HANDLE_VALUE)
return false;
closeRoot = true;
ptr = shareEnd + 1; // first component under share
}
// Rooted path on current drive: \foo\bar
else if (ptr[0] == L'\\')
{
UNICODE_STRING* dosPath = &ffGetPeb()->ProcessParameters->CurrentDirectory.DosPath;
wchar_t driveRoot[] = { dosPath->Buffer[0], L':', L'\\', L'\0' };
hRoot = CreateFileW(
driveRoot,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (hRoot == INVALID_HANDLE_VALUE)
return false;
closeRoot = true;
ptr++; // skip leading '\'
}
while (true)
{
wchar_t* token = wcschr(ptr, L'\\');
if (token == NULL)
break;
// Skip empty path segments caused by duplicated '\'
if (token == ptr)
{
ptr = token + 1;
continue;
}
HANDLE hNew = INVALID_HANDLE_VALUE;
IO_STATUS_BLOCK iosb = {};
NTSTATUS status = NtCreateFile(
&hNew,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
&(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
.RootDirectory = hRoot,
.ObjectName = &(UNICODE_STRING) {
.Buffer = ptr,
.Length = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
.MaximumLength = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
},
.Attributes = OBJ_CASE_INSENSITIVE,
},
&iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(status))
{
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
NtClose(hRoot);
return false;
}
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
NtClose(hRoot);
hRoot = hNew;
closeRoot = true;
ptr = token + 1;
}
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
NtClose(hRoot);
return true;
}
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
{
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
wchar_t fileNameW[MAX_PATH];
ULONG len = 0;
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
return false;
for (ULONG i = 0; i < len / sizeof(wchar_t); ++i)
{
if (fileNameW[i] == L'/')
fileNameW[i] = L'\\';
}
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_PATH_NOT_FOUND)
{
createSubfolders(fileName);
handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!createSubfolders(fileNameW))
return false;
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
return false;
}
@@ -70,12 +210,13 @@ static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
{
LARGE_INTEGER fileSize;
if(!GetFileSizeEx(handle, &fileSize))
fileSize.QuadPart = 0;
FILE_STANDARD_INFORMATION fileInfo;
IO_STATUS_BLOCK iosb;
if(!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation)))
fileInfo.EndOfFile.QuadPart = 0;
if (fileSize.QuadPart > 0)
readWithLength(handle, buffer, (uint32_t)fileSize.QuadPart);
if (fileInfo.EndOfFile.QuadPart > 0)
readWithLength(handle, buffer, (uint32_t)fileInfo.EndOfFile.QuadPart);
else
readUntilEOF(handle, buffer);
@@ -84,24 +225,6 @@ bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
return buffer->length > 0;
}
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
{
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(handle == INVALID_HANDLE_VALUE)
return -1;
return ffReadFDData(handle, dataSize, data);
}
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
{
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(handle == INVALID_HANDLE_VALUE)
return false;
return ffAppendFDBuffer(handle, buffer);
}
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory)
{
assert(fileNameLen <= 0x7FFF);
@@ -128,38 +251,22 @@ HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool d
return hFile;
}
HANDLE openat(HANDLE dfd, const char* fileName, bool directory)
HANDLE openat(HANDLE dfd, const char* fileName, int oflag)
{
wchar_t fileNameW[MAX_PATH];
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, fileNameW, ARRAY_SIZE(fileNameW));
if (len == 0) return INVALID_HANDLE_VALUE;
ULONG len;
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
return INVALID_HANDLE_VALUE;
// Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator
len /= sizeof(wchar_t); // convert from bytes to characters
for (int i = 0; i < len - 1; ++i)
for (uint32_t i = 0; i < len - 1; ++i)
{
if (fileNameW[i] == L'/')
fileNameW[i] = L'\\';
}
return openatW(dfd, fileNameW, (uint16_t)(len - 1), directory);
}
bool ffAppendFileBufferRelative(HANDLE dfd, const char* fileName, FFstrbuf* buffer)
{
HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);
if(fd == INVALID_HANDLE_VALUE)
return false;
return ffAppendFDBuffer(fd, buffer);
}
ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize, void* data)
{
HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);
if(fd == INVALID_HANDLE_VALUE)
return -1;
return ffReadFDData(fd, dataSize, data);
return openatW(dfd, fileNameW, (uint16_t)(len - 1), !!(oflag & O_DIRECTORY));
}
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
@@ -172,13 +279,17 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out)
}
}
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
if (length <= 1) return false;
wchar_t pathInW[MAX_PATH], pathOutW[MAX_PATH];
ULONG len = (ULONG) strlen(in);
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathInW, (ULONG) sizeof(pathInW), &len, in, len)))
return false;
len /= sizeof(wchar_t); // convert from bytes to characters
ffStrbufClear(out);
ffStrbufEnsureFree(out, (uint32_t)length);
ExpandEnvironmentStringsA(in, out->chars, length);
out->length = (uint32_t)length - 1;
size_t outLen; // in characters, including null terminator
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen)))
return false;
ffStrbufSetNWS(out, (uint32_t) outLen - 1, pathOutW);
return true;
}
@@ -308,10 +419,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
while (true)
{
if (WaitForSingleObjectEx(hInput, FF_IO_TERM_RESP_WAIT_MS, TRUE) != WAIT_OBJECT_0)
if (NtWaitForSingleObject(hInput, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) FF_IO_TERM_RESP_WAIT_MS * -10000 }) != STATUS_WAIT_0)
{
SetConsoleMode(hInput, inputMode);
return "WaitForSingleObject() failed or timeout";
return "NtWaitForSingleObject() failed or timeout";
}
// Ignore all unexpected input events
@@ -350,7 +461,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
va_list cargs;
va_copy(cargs, args);
int ret = vsscanf(buffer, format, args);
int ret = vsscanf(buffer, format, cargs);
va_end(cargs);
if (ret <= 0)
+86 -1
View File
@@ -1,6 +1,13 @@
#include "fastfetch.h"
#include "common/library.h"
#if _WIN32
#include "common/debug.h"
#include "common/windows/nt.h"
#include <errno.h>
#include <ntstatus.h>
#endif
#ifndef FF_DISABLE_DLOPEN
#include <stdarg.h>
@@ -36,7 +43,7 @@ static void* libraryLoad(const char* path, int maxVersion)
if (pathLen == instance.state.platform.exePath.length)
return result;
char absPath[MAX_PATH + 1];
char absPath[MAX_PATH * 2];
strcpy(mempcpy(absPath, instance.state.platform.exePath.chars, pathLen + 1), path);
return dlopen(absPath, FF_DLOPEN_FLAGS);
@@ -92,3 +99,81 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...)
}
#endif
#if _WIN32
void* dlopen(const char* path, FF_MAYBE_UNUSED int mode)
{
wchar_t pathW[MAX_PATH + 1];
ULONG pathWBytes = 0;
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t)strlen(path) + 1);
if (!NT_SUCCESS(status))
{
FF_DEBUG("RtlUTF8ToUnicodeN failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
return NULL;
}
PVOID module = NULL;
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
.MaximumLength = (USHORT) pathWBytes,
.Buffer = pathW,
}, &module);
if (!NT_SUCCESS(status))
{
FF_DEBUG("LdrLoadDll failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
return NULL;
}
return module;
}
int dlclose(void* handle)
{
NTSTATUS status = LdrUnloadDll(handle);
if (!NT_SUCCESS(status))
{
FF_DEBUG("LdrUnloadDll failed for handle %p with status 0x%08lX: %s", handle, status, ffDebugNtStatus(status));
return -1;
}
return 0;
}
void* dlsym(void* handle, const char* symbol)
{
void* address;
USHORT symbolBytes = (USHORT) strlen(symbol) + 1;
NTSTATUS status = LdrGetProcedureAddress(handle, &(ANSI_STRING) {
.Length = symbolBytes - sizeof(char),
.MaximumLength = symbolBytes,
.Buffer = (char*) symbol,
}, 0, &address);
if (!NT_SUCCESS(status))
{
FF_DEBUG("LdrGetProcedureAddress failed for symbol %s with status 0x%08lX: %s", symbol, status, ffDebugNtStatus(status));
return NULL;
}
return address;
}
void* ffLibraryGetModule(const wchar_t* libraryFileName)
{
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
void* module = NULL;
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t)) + sizeof(wchar_t);
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
.Length = libraryFileNameBytes - sizeof(wchar_t),
.MaximumLength = libraryFileNameBytes,
.Buffer = (wchar_t*) libraryFileName,
}, &module);
if (!NT_SUCCESS(status))
{
FF_DEBUG("LdrGetDllHandle failed for library %ls with status 0x%08lX: %s", libraryFileName, status, ffDebugNtStatus(status));
return NULL;
}
return module;
}
#endif
+13 -8
View File
@@ -108,8 +108,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
#else
"sendto()"
#endif
" %s (sent=%zd, errno=%d: %s)", errno == 0 ? "succeeded" : "was in progress",
sent, errno, strerror(errno));
" %s (sent=%zd, %s)", errno == 0 ? "succeeded" : "was in progress", sent, strerror(errno));
freeaddrinfo(state->addr);
state->addr = NULL;
ffStrbufDestroy(&state->command);
@@ -122,7 +121,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
#else
"sendto()"
#endif
" failed: %s (errno=%d)", strerror(errno), errno);
" failed: %s", strerror(errno));
#ifdef __APPLE__
return "connectx() failed";
#else
@@ -143,7 +142,7 @@ static const char* connectAndSend(FFNetworkingState* state)
FF_DEBUG("Attempting connect() to server...");
if(connect(state->sockfd, state->addr->ai_addr, state->addr->ai_addrlen) == -1)
{
FF_DEBUG("connect() failed: %s (errno=%d)", strerror(errno), errno);
FF_DEBUG("connect() failed: %s", strerror(errno));
ret = "connect() failed";
goto error;
}
@@ -152,7 +151,7 @@ static const char* connectAndSend(FFNetworkingState* state)
FF_DEBUG("Attempting to send %u bytes of data...", state->command.length);
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
{
FF_DEBUG("send() failed: %s (errno=%d)", strerror(errno), errno);
FF_DEBUG("send() failed: %s", strerror(errno));
ret = "send() failed";
goto error;
}
@@ -227,7 +226,7 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
state->sockfd = socket(state->addr->ai_family, state->addr->ai_socktype, state->addr->ai_protocol);
if(state->sockfd == -1)
{
FF_DEBUG("socket() failed: %s (errno=%d)", strerror(errno), errno);
FF_DEBUG("socket() failed: %s", strerror(errno));
ret = "socket() failed";
goto error;
}
@@ -399,7 +398,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
else if (pollRes == -1)
{
FF_DEBUG("poll() failed: %s (errno=%d)", strerror(errno), errno);
FF_DEBUG("poll() failed: %s", strerror(errno));
close(state->sockfd);
state->sockfd = -1;
return "poll() failed";
@@ -417,6 +416,12 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
#endif
if (shutdown(state->sockfd, SHUT_WR) == -1)
{
FF_DEBUG("Failed to shutdown socket send: %s", strerror(errno));
// Not a critical error, continue anyway
}
FF_DEBUG("Starting data reception");
FF_MAYBE_UNUSED int recvCount = 0;
uint32_t contentLength = 0;
@@ -434,7 +439,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
if (received == 0) {
FF_DEBUG("Connection closed (received=0)");
} else {
FF_DEBUG("Reception failed: %s (errno=%d)", strerror(errno), errno);
FF_DEBUG("Reception failed: %s", strerror(errno));
}
break;
}
+43 -25
View File
@@ -24,19 +24,19 @@ static const char* initWsaData(WSADATA* wsaData)
}
//Dummy socket needed for WSAIoctl
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
SOCKET sockfd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
if(sockfd == INVALID_SOCKET) {
FF_DEBUG("socket(AF_INET, SOCK_STREAM) failed");
FF_DEBUG("WSASocketW(AF_INET, SOCK_STREAM) failed");
WSACleanup();
return "socket(AF_INET, SOCK_STREAM) failed";
return "WSASocketW(AF_INET, SOCK_STREAM) failed";
}
DWORD dwBytes;
GUID guid = WSAID_CONNECTEX;
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0) {
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0) {
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
closesocket(sockfd);
WSACleanup();
@@ -92,26 +92,33 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
return "initWsaData() failed before";
}
struct addrinfo* addr;
struct addrinfo hints = {
ADDRINFOW* addr;
ADDRINFOW hints = {
.ai_flags = AI_NUMERICSERV,
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_NUMERICSERV,
};
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
if(getaddrinfo(host, "80", &hints, &addr) != 0)
wchar_t hostW[256];
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), NULL, host, (ULONG) strlen(host) + 1)))
{
FF_DEBUG("getaddrinfo() failed");
return "getaddrinfo() failed";
FF_DEBUG("Failed to convert host to wide string: %s", host);
return "Failed to convert host to wide string";
}
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
if(GetAddrInfoW(hostW, L"80", &hints, &addr) != 0)
{
FF_DEBUG("GetAddrInfoW() failed");
return "GetAddrInfoW() failed";
}
state->sockfd = WSASocketW(addr->ai_family, addr->ai_socktype, addr->ai_protocol, NULL, 0, 0);
if(state->sockfd == INVALID_SOCKET)
{
FF_DEBUG("socket() failed");
freeaddrinfo(addr);
return "socket() failed";
FF_DEBUG("WSASocketW() failed");
FreeAddrInfoW(addr);
return "WSASocketW() failed";
}
DWORD flag = 1;
@@ -143,7 +150,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
{
FF_DEBUG("bind() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
closesocket(state->sockfd);
freeaddrinfo(addr);
FreeAddrInfoW(addr);
state->sockfd = INVALID_SOCKET;
return "bind() failed";
}
@@ -156,7 +163,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
if (state->overlapped.hEvent == WSA_INVALID_EVENT) {
FF_DEBUG("WSACreateEvent() failed");
closesocket(state->sockfd);
freeaddrinfo(addr);
FreeAddrInfoW(addr);
state->sockfd = INVALID_SOCKET;
return "WSACreateEvent() failed";
}
@@ -200,7 +207,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
state->command.chars, state->command.length, &sent, &state->overlapped);
freeaddrinfo(addr);
FreeAddrInfoW(addr);
addr = NULL;
if(!result)
@@ -251,7 +258,8 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
} else {
FF_DEBUG("WSAWaitForMultipleEvents failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
}
CancelIo((HANDLE) state->sockfd);
if (CancelIoEx((HANDLE) state->sockfd, &state->overlapped))
WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, 10, TRUE);
WSACloseEvent(state->overlapped.hEvent);
closesocket(state->sockfd);
ffStrbufDestroy(&state->command);
@@ -279,6 +287,12 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
// Not a critical error, continue anyway
}
if (shutdown(state->sockfd, SD_SEND) == SOCKET_ERROR)
{
FF_DEBUG("Failed to shutdown socket send: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
// Not a critical error, continue anyway
}
if(timeout > 0)
{
FF_DEBUG("Setting receive timeout: %u ms", timeout);
@@ -302,10 +316,14 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
++recvCount, buffer->length, ffStrbufGetFree(buffer));
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int)ffStrbufGetFree(buffer), 0);
DWORD received = 0, recvFlags = 0;
int recvResult = WSARecv(state->sockfd, &(WSABUF) {
.buf = buffer->chars + buffer->length,
.len = (ULONG) ffStrbufGetFree(buffer),
}, 1, &received, &recvFlags, NULL, NULL);
if (received <= 0) {
if (received == 0) {
if (recvResult == SOCKET_ERROR || received == 0) {
if (recvResult == 0 && received == 0) {
FF_DEBUG("Connection closed (received=0)");
} else {
FF_DEBUG("Reception failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
@@ -316,7 +334,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
FF_DEBUG("Successfully received %u bytes of data, total: %u bytes", (unsigned) received, buffer->length);
// Check if HTTP header end marker is found
if (headerEnd == 0) {
+260 -1
View File
@@ -1,6 +1,6 @@
#include "common/path.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/arrayUtils.h"
#if !_WIN32
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
@@ -49,6 +49,9 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
}
#else
#include <windows.h>
#include <winioctl.h>
#include <errno.h>
#include <stdalign.h>
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
{
@@ -62,4 +65,260 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
ffStrbufSetS(result, buffer);
return NULL;
}
static inline int winerr2Errno(DWORD err)
{
switch (err)
{
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_INVALID_NAME:
return ENOENT;
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
return EACCES;
case ERROR_BUFFER_OVERFLOW:
case ERROR_INSUFFICIENT_BUFFER:
return ENAMETOOLONG;
case ERROR_INVALID_PARAMETER:
case ERROR_NOT_A_REPARSE_POINT:
return EINVAL;
default:
return EIO;
}
}
char* frealpath(HANDLE hFile, char* resolved_name)
{
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false))
{
errno = EINVAL;
return NULL;
}
wchar_t resolvedNameW[MAX_PATH + 4]; /* +4 for "\\\\?\\" prefix */
DWORD lenW = GetFinalPathNameByHandleW(hFile, resolvedNameW, (DWORD)ARRAY_SIZE(resolvedNameW), FILE_NAME_NORMALIZED);
if (lenW == 0)
{
errno = winerr2Errno(GetLastError());
return NULL;
}
if (lenW >= ARRAY_SIZE(resolvedNameW))
{
errno = E2BIG;
return NULL;
}
lenW++; // Include null terminator
wchar_t* srcW = resolvedNameW;
DWORD srcLenW = lenW;
if (srcLenW >= 8 && wcsncmp(resolvedNameW, L"\\\\?\\UNC\\", 8) == 0)
{
/* Convert "\\?\UNC\server\share" to "\\server\share" */
srcW += 6;
srcLenW -= 6;
*srcW = L'\\';
}
else if (srcLenW >= 4 && wcsncmp(resolvedNameW, L"\\\\?\\", 4) == 0)
{
srcW += 4;
srcLenW -= 4;
}
if (resolved_name)
{
ULONG outBytes = 0;
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
{
errno = E2BIG;
return NULL;
}
if (outBytes > MAX_PATH)
{
errno = E2BIG;
return NULL;
}
return resolved_name;
}
else
{
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
char tmp[(MAX_PATH + 4) * 4];
ULONG outBytes = 0;
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG)sizeof(tmp), &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
{
errno = E2BIG;
return NULL;
}
resolved_name = (char*)malloc(outBytes);
if (!resolved_name)
{
errno = ENOMEM;
return NULL;
}
memcpy(resolved_name, tmp, outBytes);
return resolved_name;
}
return resolved_name;
}
char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
{
if (!file_name)
{
errno = EINVAL;
return NULL;
}
wchar_t fileNameW[MAX_PATH];
ULONG lenBytes = 0;
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG)sizeof(fileNameW), &lenBytes, file_name, (ULONG)strlen(file_name) + 1)))
{
errno = EINVAL;
return NULL;
}
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
fileNameW,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
errno = winerr2Errno(GetLastError());
return NULL;
}
return frealpath(hFile, resolved_name);
}
ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
{
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !buf || bufsiz == 0, false))
{
errno = EINVAL;
return -1;
}
alignas(REPARSE_DATA_BUFFER) BYTE reparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned = 0;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL))
{
errno = winerr2Errno(GetLastError());
return -1;
}
REPARSE_DATA_BUFFER* rp = (REPARSE_DATA_BUFFER*) reparseBuf;
const wchar_t* targetW = NULL;
USHORT targetBytes = 0;
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
{
if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 0)
{
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
(rp->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t));
targetBytes = rp->SymbolicLinkReparseBuffer.PrintNameLength;
}
else
{
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
(rp->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
targetBytes = rp->SymbolicLinkReparseBuffer.SubstituteNameLength;
if (targetBytes >= 8 &&
wcsncmp(targetW, L"\\??\\", 4) == 0)
{
targetW += 4;
targetBytes -= 8;
}
}
}
else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
{
if (rp->MountPointReparseBuffer.PrintNameLength > 0)
{
targetW = rp->MountPointReparseBuffer.PathBuffer +
(rp->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t));
targetBytes = rp->MountPointReparseBuffer.PrintNameLength;
}
else
{
targetW = rp->MountPointReparseBuffer.PathBuffer +
(rp->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
targetBytes = rp->MountPointReparseBuffer.SubstituteNameLength;
if (targetBytes >= 8 &&
wcsncmp(targetW, L"\\??\\", 4) == 0)
{
targetW += 4;
targetBytes -= 8;
}
}
}
else
{
errno = EINVAL;
return -1;
}
ULONG outBytes = 0;
if (!NT_SUCCESS(RtlUnicodeToUTF8N(buf, (ULONG) bufsiz, &outBytes, targetW, targetBytes)))
{
errno = E2BIG;
return -1;
}
// Not null-terminated
return (ssize_t) outBytes;
}
ssize_t readlink(const char* path, char* buf, size_t bufsiz)
{
if (!path || !buf || bufsiz == 0)
{
errno = EINVAL;
return -1;
}
wchar_t pathW[MAX_PATH];
ULONG pathWBytes = 0;
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathW, (ULONG) sizeof(pathW), &pathWBytes, path, (ULONG) strlen(path) + 1)))
{
errno = EINVAL;
return -1;
}
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
pathW,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
errno = winerr2Errno(GetLastError());
return -1;
}
return freadlink(hFile, buf, bufsiz);
}
#endif
+2 -2
View File
@@ -47,8 +47,8 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
{
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
FF_PARSE_FORMAT_STRING_CHECKED(&key, &moduleArgs->key, ((FFformatarg[]) {
FF_FORMAT_ARG(moduleIndex, "index"),
FF_FORMAT_ARG(moduleArgs->keyIcon, "icon"),
FF_ARG(moduleIndex, "index"),
FF_ARG(moduleArgs->keyIcon, "icon"),
}));
ffStrbufWriteTo(&key, stdout);
}
+2
View File
@@ -128,6 +128,8 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
{
close(pipes[0]);
close(pipes[1]);
if (ret == ENOENT)
return "command not found";
return "posix_spawnp() failed";
}
+74 -50
View File
@@ -1,4 +1,5 @@
#include "fastfetch.h"
#include "common/mallocHelper.h"
#include "common/processing.h"
#include "common/io.h"
#include "common/windows/unicode.h"
@@ -85,7 +86,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
PROCESS_INFORMATION piProcInfo = {};
STARTUPINFOA siStartInfo = {
STARTUPINFOW siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
@@ -100,12 +101,19 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
siStartInfo.hStdError = ffGetNullFD();
}
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
FF_AUTO_FREE wchar_t* cmdline = NULL;
{
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
argvToCmdline(argv, &buf);
uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t);
cmdline = malloc(cmdlineBytes);
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, NULL, buf.chars, buf.length + 1)))
return "RtlUTF8ToUnicodeN() failed";
}
BOOL success = CreateProcessA(
BOOL success = CreateProcessW(
NULL, // application name
cmdline.chars, // command line
cmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
@@ -116,15 +124,15 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
&piProcInfo // receives PROCESS_INFORMATION
);
CloseHandle(hChildPipeWrite);
NtClose(hChildPipeWrite);
if(!success)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
return "command not found";
return "CreateProcessA() failed";
return "CreateProcessW() failed";
}
CloseHandle(piProcInfo.hThread); // we don't need the thread handle
NtClose(piProcInfo.hThread); // we don't need the thread handle
outHandle->pid = piProcInfo.hProcess;
outHandle->pipeRead = hChildPipeRead;
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
@@ -132,6 +140,17 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
return NULL;
}
static void terminateChildProcess(HANDLE hProcess, HANDLE hChildPipeRead, HANDLE hReadEvent, IO_STATUS_BLOCK* piosb)
{
IO_STATUS_BLOCK cancelIosb = {};
if (NT_SUCCESS(NtCancelIoFileEx(hChildPipeRead, piosb, &cancelIosb)))
{
if (hReadEvent)
NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = -100000 }); // wait for cancellation to complete
}
NtTerminateProcess(hProcess, 1);
}
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
{
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
@@ -140,56 +159,59 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
FF_AUTO_CLOSE_FD HANDLE hReadEvent = NULL;
handle->pid = INVALID_HANDLE_VALUE;
handle->pipeRead = INVALID_HANDLE_VALUE;
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
return "NtCreateEvent() failed";
char str[FF_PIPE_BUFSIZ];
DWORD nRead = 0;
OVERLAPPED overlapped = {};
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
uint32_t nRead = 0;
IO_STATUS_BLOCK iosb = {};
do
{
if (!ReadFile(hChildPipeRead, str, sizeof(str), &nRead, &overlapped))
NTSTATUS status = NtReadFile(
hChildPipeRead,
hReadEvent,
NULL,
NULL,
&iosb,
str,
(ULONG) sizeof(str),
NULL,
NULL
);
if (status == STATUS_PENDING)
{
switch (GetLastError())
switch (NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }))
{
case ERROR_IO_PENDING:
#if !FF_WIN7_COMPAT
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
#else
// To support Windows 7
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
{
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "WaitForSingleObject(hChildPipeRead) failed or timeout (try increasing --processing-timeout)";
}
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
#endif
{
if (GetLastError() == ERROR_BROKEN_PIPE)
return NULL;
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "GetOverlappedResult"
#if !FF_WIN7_COMPAT
"Ex"
#endif
"(hChildPipeRead) failed";
}
case STATUS_WAIT_0:
status = iosb.Status;
break;
case ERROR_BROKEN_PIPE:
goto exit;
case STATUS_TIMEOUT:
{
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
return "NtReadFile(hChildPipeRead) timed out";
}
default:
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "ReadFile(hChildPipeRead) failed";
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
return "NtWaitForSingleObject(hReadEvent) failed";
}
}
if (status == STATUS_PIPE_BROKEN || status == STATUS_END_OF_FILE)
goto exit;
if (!NT_SUCCESS(status))
{
terminateChildProcess(hProcess, hChildPipeRead, NULL, &iosb);
return "NtReadFile(hChildPipeRead) failed";
}
nRead = (uint32_t) iosb.Information;
ffStrbufAppendNS(buffer, nRead, str);
} while (nRead > 0);
@@ -212,12 +234,14 @@ exit:
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
{
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
? NtCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess == NULL)
return false;
FF_AUTO_CLOSE_FD HANDLE hProcess = NtCurrentProcess();
if(pid != 0)
{
if (!NT_SUCCESS(NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, &(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
}, &(CLIENT_ID) { .UniqueProcess = (HANDLE)(uintptr_t) pid })))
return false;
}
if(ppid)
{
+173 -54
View File
@@ -18,6 +18,7 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
!ffStrbufIgnCaseEqualS(value, "None") &&
!ffStrbufIgnCaseEqualS(value, "System Name") &&
!ffStrbufIgnCaseEqualS(value, "System Version") &&
!ffStrbufIgnCaseEqualS(value, "System SKU#") &&
!ffStrbufIgnCaseEqualS(value, "Default string") &&
!ffStrbufIgnCaseEqualS(value, "Undefined") &&
!ffStrbufIgnCaseEqualS(value, "Not Specified") &&
@@ -32,11 +33,29 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
!ffStrbufIgnCaseEqualS(value, "All Series") &&
!ffStrbufIgnCaseEqualS(value, "N/A") &&
!ffStrbufIgnCaseEqualS(value, "Unknown") &&
!ffStrbufIgnCaseEqualS(value, "Standard") &&
!ffStrbufIgnCaseEqualS(value, "0x0000")
!ffStrbufIgnCaseEqualS(value, "Standard") && ({
// Some SMBIOS implementations use "0x0000" to indicate an unset value, even for strings.
bool zero = ffStrbufStartsWithS(value, "0x0");
if (zero)
{
for (size_t i = 2; i < value->length; i++)
{
char c = value->chars[i];
if (c != '0')
{
zero = false;
break;
}
}
}
!zero;
})
;
}
static bool smbiosTableInitialized = false;
static FFSmbiosHeaderTable smbiosTable;
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
{
const char* p = ((const char*) header) + header->Length;
@@ -52,6 +71,74 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
return (const FFSmbiosHeader*) (p + 1);
}
static bool parseSmbiosTable(const uint8_t* data, uint32_t length)
{
const FFSmbiosHeader* endOfTable = NULL;
FF_DEBUG("Parsing SMBIOS table structures with length %u bytes", length);
FF_MAYBE_UNUSED int structureCount = 0, totalCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) data;
(const uint8_t*) header + sizeof(FFSmbiosHeader) < (const uint8_t*) data + length;
header = ffSmbiosNextEntry(header)
)
{
++totalCount;
endOfTable = header;
// This doesn't verify the entire structure (e.g. string section can still be truncated),
// but at least ensures the formatted section is valid and prevents infinite loops
// when the table is severely malformed.
if (__builtin_expect((const uint8_t*) header + header->Length > (const uint8_t*) data + length, false))
{
FF_DEBUG("Truncated SMBIOS structure at offset 0x%lx: length %u is too small",
(unsigned long)((const uint8_t*) header - data), header->Length);
break;
}
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
{
if (!smbiosTable[header->Type])
{
smbiosTable[header->Type] = header;
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
structureCount++;
}
else
{
FF_DEBUG("Duplicate SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
}
}
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE)
{
FF_DEBUG("Reached SMBIOS end of type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
break;
}
else
{
FF_DEBUG("Found custom SMBIOS structure type %u, handle 0x%04X, length %u; ignoring",
header->Type, header->Handle, header->Length);
}
}
if (!endOfTable)
{
FF_DEBUG("No SMBIOS structures found in table");
return false;
}
FF_DEBUG("Parsed %d/%d SMBIOS structures, end-of-table (Type 127) %s",
structureCount,
totalCount,
endOfTable->Type == FF_SMBIOS_TYPE_END_OF_TABLE ? "found." : "not found! SMBIOS data may be malformed.");
smbiosTable[FF_SMBIOS_TYPE_END_OF_TABLE] = endOfTable;
return true;
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__OpenBSD__) || defined(__GNU__)
#include <fcntl.h>
#include <sys/stat.h>
@@ -71,17 +158,30 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
#define loff_t off_t
#endif
#ifdef __linux__
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
if (ffReadFileBuffer(devicesPath, buffer))
// /sys/class/dmi/id/* are all pseudo-files with very small content
// so reading the whole file at once is efficient
ffStrbufEnsureFixedLengthFree(buffer, 127);
ssize_t len = ffReadFileData(devicesPath, buffer->allocated - 1, buffer->chars);
if (len > 0)
{
assert(len < buffer->allocated);
buffer->chars[len] = '\0';
buffer->length = (uint32_t) len;
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return true;
}
if (ffReadFileBuffer(classPath, buffer))
len = ffReadFileData(classPath, buffer->allocated - 1, buffer->chars);
if (len > 0)
{
assert(len < buffer->allocated);
buffer->chars[len] = '\0';
buffer->length = (uint32_t) len;
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return true;
@@ -90,6 +190,7 @@ bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf*
ffStrbufClear(buffer);
return false;
}
#endif
typedef struct FFSmbios20EntryPoint
{
@@ -137,10 +238,10 @@ typedef union FFSmbiosEntryPoint
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
{
static FFstrbuf buffer;
static FFSmbiosHeaderTable table;
if (buffer.chars == NULL)
if (!smbiosTableInitialized)
{
smbiosTableInitialized = true;
FF_DEBUG("Initializing SMBIOS buffer");
ffStrbufInit(&buffer);
#if !__HAIKU__ && !__OpenBSD__ && !__DragonFly__ && !__GNU__
@@ -401,29 +502,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
}
#endif
FF_DEBUG("Parsing SMBIOS table structures");
FF_MAYBE_UNUSED int structureCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars;
(const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length;
header = ffSmbiosNextEntry(header)
)
{
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
{
if (!table[header->Type]) {
table[header->Type] = header;
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
structureCount++;
}
}
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
FF_DEBUG("Reached end-of-table marker");
break;
}
}
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
if (!parseSmbiosTable((const uint8_t*) buffer.chars, buffer.length))
ffStrbufClear(&buffer);
}
if (buffer.length == 0) {
@@ -431,7 +511,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
return NULL;
}
return &table;
return &smbiosTable;
}
#elif defined(_WIN32)
#include "common/windows/nt.h"
@@ -451,10 +531,10 @@ typedef struct FFRawSmbiosData
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
{
static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;
static FFSmbiosHeaderTable table;
if (!buffer)
if (!smbiosTableInitialized)
{
smbiosTableInitialized = true;
FF_DEBUG("Initializing Windows SMBIOS buffer");
FF_DEBUG("Querying system firmware table size with signature 'RSMB'");
@@ -491,31 +571,70 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length);
FF_DEBUG("Parsing SMBIOS table structures");
FF_MAYBE_UNUSED int structureCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) rawData->SMBIOSTableData;
(const uint8_t*) header < rawData->SMBIOSTableData + rawData->Length;
header = ffSmbiosNextEntry(header)
)
if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length))
{
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
{
if (!table[header->Type]) {
table[header->Type] = header;
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
structureCount++;
}
}
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
FF_DEBUG("Reached end-of-table marker");
break;
}
free(buffer);
buffer = NULL;
return NULL;
}
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
}
return &table;
if (!buffer) {
FF_DEBUG("No valid SMBIOS data available");
return NULL;
}
return &smbiosTable;
}
#elif defined(__APPLE__)
#include "common/apple/cf_helpers.h"
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
{
static CFDataRef smbiosDataBuffer;
if (!smbiosTableInitialized)
{
smbiosTableInitialized = true;
FF_DEBUG("Initializing SMBIOS buffer on Apple platform");
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMBIOS"));
if (!registryEntry)
{
FF_DEBUG("IOServiceGetMatchingService() failed to find AppleSMBIOS");
return NULL;
}
FF_DEBUG("AppleSMBIOS service found, retrieving SMBIOS data");
smbiosDataBuffer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("SMBIOS"), kCFAllocatorDefault, kNilOptions);
if (!smbiosDataBuffer)
{
FF_DEBUG("IORegistryEntryCreateCFProperty() failed to get SMBIOS data");
return NULL;
}
if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID())
{
FF_DEBUG("Unexpected SMBIOS data type: expected CFData");
CFRelease(smbiosDataBuffer);
smbiosDataBuffer = NULL;
return NULL;
}
FF_DEBUG("Successfully retrieved SMBIOS data: %lu bytes", CFDataGetLength(smbiosDataBuffer));
if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer)))
{
CFRelease(smbiosDataBuffer);
smbiosDataBuffer = NULL;
return NULL;
}
}
if (!smbiosDataBuffer)
{
FF_DEBUG("No valid SMBIOS data available");
return NULL;
}
return &smbiosTable;
}
#endif
+1 -1
View File
@@ -89,7 +89,7 @@ FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
static void ffTimeInitQpcMultiplier(void)
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
RtlQueryPerformanceFrequency(&frequency);
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
}
#endif
+102 -42
View File
@@ -7,6 +7,7 @@
#include <fileapi.h>
#include <handleapi.h>
#include <io.h>
#include "common/windows/nt.h"
typedef HANDLE FFNativeFD;
#define FF_INVALID_FD INVALID_HANDLE_VALUE
#else
@@ -15,6 +16,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
typedef int FFNativeFD;
#define FF_INVALID_FD (-1)
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
@@ -22,6 +24,51 @@
#define PROC_FILE_BUFFSIZ (32 * 1024)
#endif
#ifdef _WIN32
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#ifndef O_DIRECTORY
#define O_DIRECTORY 0200000
#endif
// Only O_RDONLY is supported
HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
#endif
static inline bool ffIsValidNativeFD(FFNativeFD fd)
{
#ifndef _WIN32
return fd >= 0;
#else
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
return fd != INVALID_HANDLE_VALUE && fd != NULL;
#endif
}
FF_C_NONNULL(1)
static inline bool wrapClose(FFNativeFD* pfd)
{
assert(pfd);
if (!ffIsValidNativeFD(*pfd))
return false;
#ifndef _WIN32
close(*pfd);
#else
NtClose(*pfd);
#endif
return true;
}
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
{
#ifndef _WIN32
@@ -71,17 +118,60 @@ static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
#endif
}
FF_C_NONNULL(1, 3)
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
FF_C_NONNULL(2, 4)
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
FF_C_NONNULL(2)
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
FF_C_NONNULL(1, 3)
static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
{
FFNativeFD FF_AUTO_CLOSE_FD fd =
#ifndef _WIN32
open(fileName, O_RDONLY | O_CLOEXEC);
#else
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
if (!ffIsValidNativeFD(fd))
return -1;
return ffReadFDData(fd, dataSize, data);
}
FF_C_NONNULL(2, 4)
static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data)
{
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if (!ffIsValidNativeFD(fd))
return -1;
return ffReadFDData(fd, dataSize, data);
}
FF_C_NONNULL(1, 2)
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
{
FFNativeFD FF_AUTO_CLOSE_FD fd =
#ifndef _WIN32
open(fileName, O_RDONLY | O_CLOEXEC);
#else
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
if (!ffIsValidNativeFD(fd))
return false;
return ffAppendFDBuffer(fd, buffer);
}
FF_C_NONNULL(2, 3)
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
{
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if (!ffIsValidNativeFD(fd))
return false;
return ffAppendFDBuffer(fd, buffer);
}
FF_C_NONNULL(2)
static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer)
@@ -117,7 +207,11 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
{
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path);
wchar_t wPath[MAX_PATH];
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG)strlen(path) + 1)))
return false;
DWORD attr = GetFileAttributesW(wPath);
if(attr == INVALID_FILE_ATTRIBUTES)
return false;
@@ -178,34 +272,6 @@ static inline void ffUnsuppressIO(bool* suppressed)
void ffListFilesRecursively(const char* path, bool pretty);
static inline bool ffIsValidNativeFD(FFNativeFD fd)
{
#ifndef _WIN32
return fd >= 0;
#else
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
return fd != INVALID_HANDLE_VALUE && fd != NULL;
#endif
}
FF_C_NONNULL(1)
static inline bool wrapClose(FFNativeFD* pfd)
{
assert(pfd);
if (!ffIsValidNativeFD(*pfd))
return false;
#ifndef _WIN32
close(*pfd);
#else
CloseHandle(*pfd);
#endif
return true;
}
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
FF_C_NONNULL(1)
static inline bool wrapFclose(FILE** pfile)
{
@@ -257,9 +323,3 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
FFNativeFD ffGetNullFD(void);
bool ffRemoveFile(const char* fileName);
#ifdef _WIN32
// Only O_RDONLY is supported
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
#endif
+17 -15
View File
@@ -6,11 +6,10 @@
#ifndef FF_DISABLE_DLOPEN
#if defined(_WIN32)
#include <libloaderapi.h>
#define FF_DLOPEN_FLAGS 0
FF_C_NODISCARD static inline void* dlopen(const char* path, int mode) { FF_UNUSED(mode); return LoadLibraryA(path); }
FF_C_NODISCARD static inline void* dlsym(void* handle, const char* symbol) { return (void*) GetProcAddress((HMODULE)handle, symbol); }
static inline int dlclose(void* handle) { return !FreeLibrary((HMODULE)handle); }
FF_C_NODISCARD void* dlopen(const char* path, int mode);
FF_C_NODISCARD void* dlsym(void* handle, const char* symbol);
int dlclose(void* handle);
#else
#include <dlfcn.h>
#endif
@@ -30,6 +29,10 @@ static inline void ffLibraryUnload(void** handle)
dlclose(*handle);
}
#if __cplusplus
#define __auto_type auto
#endif
#define FF_LIBRARY_SYMBOL(symbolName) \
__typeof__(&symbolName) ff ## symbolName;
@@ -38,13 +41,8 @@ static inline void ffLibraryUnload(void** handle)
if(libraryObjectName == NULL) \
return returnValue;
#if _WIN32
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
FF_LIBRARY_LOAD(libraryObjectName, "LoadLibraryA(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
#else
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
FF_LIBRARY_LOAD(libraryObjectName, "dlopen(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
#endif
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
symbolMapping = (__typeof__(&symbolName)) dlsym(library, #symbolName); \
@@ -52,13 +50,13 @@ static inline void ffLibraryUnload(void** handle)
return returnValue;
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
__typeof__(&symbolName) ff ## symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
__auto_type ff ## symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
@@ -88,13 +86,13 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
symbolMapping = (__typeof__(&symbolName)) &symbolName;
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
FF_MAYBE_UNUSED __typeof__(&symbolName) ff ## symbolName = (__typeof__(&symbolName)) &symbolName;
FF_MAYBE_UNUSED __auto_type ff ## symbolName = (__typeof__(&symbolName)) &symbolName;
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
@@ -106,3 +104,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff ## symbolName, symbolName, returnValue);
#endif
#if _WIN32
void* ffLibraryGetModule(const wchar_t* libraryFileName);
#endif
+7
View File
@@ -13,3 +13,10 @@ static inline bool ffIsAbsolutePath(const char* path)
return path[0] == '/';
#endif
}
#if _WIN32
char* frealpath(void* __restrict hFile, char* __restrict resolved_name /*MAX_PATH*/);
char* realpath(const char* __restrict file_name, char* __restrict resolved_name /*MAX_PATH*/);
ssize_t freadlink(void* hFile, char* buf, size_t bufsiz);
ssize_t readlink(const char* path, char* buf, size_t bufsiz);
#endif
+9 -1
View File
@@ -63,14 +63,22 @@ typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t
FF_SMBIOS_TYPE_STRING_PROPERTY = 46,
FF_SMBIOS_TYPE_INACTIVE = 126,
FF_SMBIOS_TYPE_END_OF_TABLE = 127,
FF_SMBIOS_TYPE__MAX,
// system- and OEM-specific information 128~256
} FFSmbiosType;
static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte");
typedef struct FFSmbiosHeader
{
// Type of SMBIOS structure. Do NOT test `Type == FF_SMBIOS_END_OF_TABLE` to determine the end of the table,
// as malformed tables may be missing the end-of-table marker.
// **Use FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE] pointer instead.**
FFSmbiosType Type;
// Length of formatted section, excluding unformatted string section
// Must be at least 4 (sizeof(FFSmbiosHeader)) to be valid
uint8_t Length;
// Unique handle, used to reference this structure from other structures.
// Not guaranteed to be consistent across reboots or even multiple reads of the same table.
uint16_t Handle;
} __attribute__((__packed__)) FFSmbiosHeader;
static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes");
@@ -84,7 +92,7 @@ static inline const char* ffSmbiosLocateString(const char* start, uint8_t index
return start;
}
typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE];
typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE__MAX];
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header);
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable();
+17
View File
@@ -80,6 +80,23 @@ static inline bool ffCharIsDigit(char c)
return '0' <= c && c <= '9';
}
static inline bool ffCharIsHexDigit(char c)
{
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}
static inline int8_t ffHexCharToInt(char c)
{
if (ffCharIsDigit(c))
return (int8_t) (c - '0');
else if ('a' <= c && c <= 'f')
return (int8_t) (c - 'a' + 10);
else if ('A' <= c && c <= 'F')
return (int8_t) (c - 'A' + 10);
else
return -1;
}
// Copies at most (dstBufSiz - 1) bytes from src to dst; dst is always null-terminated
static inline char* ffStrCopy(char* __restrict__ dst, const char* __restrict__ src, size_t dstBufSiz)
{
+5 -5
View File
@@ -4,7 +4,7 @@
#ifdef FF_HAVE_THREADS
#if defined(_WIN32)
#include <handleapi.h>
#include <winternl.h>
#include <synchapi.h>
#include <process.h>
#include <processthreadsapi.h>
@@ -18,16 +18,16 @@
}
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static __stdcall unsigned fn ## ThreadMain (void* data) { fn((paramType)data); return 0; }
#define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static __stdcall unsigned fn ## ThreadMain () { fn(); return 0; }
static inline void ffThreadDetach(FFThreadType thread) { CloseHandle(thread); }
static inline void ffThreadDetach(FFThreadType thread) { NtClose(thread); }
static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout)
{
if (WaitForSingleObject(thread, timeout == 0 ? (DWORD) -1 : timeout) != 0 /*WAIT_OBJECT_0*/)
if (NtWaitForSingleObject(thread, FALSE, timeout == 0 ? NULL : &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }) != STATUS_WAIT_0)
{
TerminateThread(thread, (DWORD) -1);
CloseHandle(thread);
NtClose(thread);
return false;
}
CloseHandle(thread);
NtClose(thread);
return true;
}
#else
+11 -2
View File
@@ -18,7 +18,7 @@ static inline double ffTimeGetTick(void) //In msec
#ifdef _WIN32
extern double ffQpcMultiplier;
LARGE_INTEGER start;
QueryPerformanceCounter(&start);
RtlQueryPerformanceCounter(&start);
return (double) start.QuadPart * ffQpcMultiplier;
#elif defined(__HAIKU__)
return (double) system_time() / 1000.;
@@ -29,11 +29,20 @@ static inline double ffTimeGetTick(void) //In msec
#endif
}
#if _WIN32
static inline uint64_t ffFileTimeToUnixMs(uint64_t value)
{
if (__builtin_expect(__builtin_usubll_overflow(value, 116444736000000000ull, &value), false))
return 0;
return value / 10000ull;
}
#endif
static inline uint64_t ffTimeGetNow(void)
{
#ifdef _WIN32
uint64_t timeNow = ffKSystemTimeToUInt64(&SharedUserData->SystemTime);
return (timeNow - 116444736000000000ull) / 10000ull;
return ffFileTimeToUnixMs((uint64_t) timeNow);
#elif defined(__HAIKU__)
return (uint64_t) real_time_clock_usecs() / 1000u;
#else
+5 -2
View File
@@ -17,7 +17,8 @@ static const char* doInitCom()
return "CoInitializeEx() failed";
// Set general COM security levels
if (FAILED(CoInitializeSecurity(
HRESULT hRes = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
@@ -27,7 +28,9 @@ static const char* doInitCom()
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
)))
);
if (FAILED(hRes) && hRes != RPC_E_TOO_LATE /* Has been set by a random dll */)
{
CoUninitialize();
return "CoInitializeSecurity() failed";
+2 -8
View File
@@ -2,14 +2,8 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--This Id value indicates the application supports Windows 7 functionality-->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--This Id value indicates the application supports Windows 8 functionality-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!--This Id value indicates the application supports Windows 8.1 functionality-->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!--This Id value indicates the application supports Windows 10, 11 functionality-->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10/11 -->
</application>
</compatibility>
<assemblyIdentity type="win32" name="com.github.fastfetch" version="0.0.0.0"/>
+933 -219
View File
File diff suppressed because it is too large Load Diff
+362 -111
View File
@@ -1,17 +1,22 @@
#include "registry.h"
#include "unicode.h"
#include "common/mallocHelper.h"
#include "common/debug.h"
#include "common/windows/nt.h"
static const char* hKey2Str(HKEY hKey)
#include <stdalign.h>
#include <ntstatus.h>
static HANDLE hRootKeys[8 /*(uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS - (uintptr_t) HKEY_CLASSES_ROOT + 1*/];
static const char* hKey2Str(HANDLE hRootKey)
{
#define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey;
#define HKEY_CASE(compareKey) if(hRootKey == hRootKeys[(uintptr_t)compareKey - (uintptr_t)HKEY_CLASSES_ROOT]) return #compareKey;
HKEY_CASE(HKEY_CLASSES_ROOT)
HKEY_CASE(HKEY_CURRENT_USER)
HKEY_CASE(HKEY_LOCAL_MACHINE)
HKEY_CASE(HKEY_USERS)
HKEY_CASE(HKEY_PERFORMANCE_DATA)
HKEY_CASE(HKEY_PERFORMANCE_TEXT)
HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT)
HKEY_CASE(HKEY_CURRENT_CONFIG)
HKEY_CASE(HKEY_DYN_DATA)
HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS)
@@ -20,152 +25,398 @@ static const char* hKey2Str(HKEY hKey)
return "UNKNOWN";
}
bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error)
HANDLE ffRegGetRootKeyHandle(HKEY hKey)
{
if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS)
assert(hKey);
assert((uintptr_t) hKey >= (uintptr_t) HKEY_CLASSES_ROOT && (uintptr_t) hKey <= (uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS);
FF_DEBUG("Getting root key handle for HKEY %08llx", (uint64_t)(uintptr_t) hKey);
HANDLE result = hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT];
if (result)
{
if(error)
FF_DEBUG("Found cached root key handle for %s -> %p", hKey2Str(result), result);
return result;
}
switch ((uintptr_t) hKey)
{
case (uintptr_t) HKEY_CURRENT_USER: {
NTSTATUS status = RtlOpenCurrentUser(KEY_READ, &result);
if (!NT_SUCCESS(status))
{
FF_DEBUG("RtlOpenCurrentUser() failed: %s", ffDebugNtStatus(status));
return NULL;
}
break;
}
case (uintptr_t) HKEY_LOCAL_MACHINE: {
UNICODE_STRING path = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
NTSTATUS status = NtOpenKey(&result, KEY_READ, &(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
.RootDirectory = NULL,
.ObjectName = &path,
.Attributes = OBJ_CASE_INSENSITIVE,
});
if (!NT_SUCCESS(status))
{
FF_DEBUG("NtOpenKey(%ls) failed: %s (0x%08lx)", path.Buffer, ffDebugNtStatus(status), status);
return NULL;
}
break;
}
default:
// Unsupported
FF_DEBUG("Unsupported root key: %p", hKey);
assert(false);
return NULL;
}
hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT] = result;
FF_DEBUG("Opened root key %s -> %p", hKey2Str(result), result);
return result;
}
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error)
{
assert(hKey);
assert(subKeyW);
assert(result);
FF_DEBUG("Opening subkey %s\\%ls for read", hKey2Str(hKey), subKeyW);
USHORT subKeyLen = (USHORT) (wcslen(subKeyW) * sizeof(wchar_t));
if (!NT_SUCCESS(NtOpenKey(result, KEY_READ, &(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
.RootDirectory = hKey,
.ObjectName = &(UNICODE_STRING) {
.Length = subKeyLen,
.MaximumLength = subKeyLen + (USHORT) sizeof(wchar_t),
.Buffer = (wchar_t*) subKeyW,
},
})))
{
FF_DEBUG("NtOpenKey(%s\\<subkey>) failed", hKey2Str(hKey));
if (error)
{
FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW);
ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars);
ffStrbufAppendF(error, "NtOpenKey(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars);
}
return false;
}
FF_DEBUG("Opened subkey under %s -> %p", hKey2Str(hKey), *result);
return true;
}
bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error)
static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const void* regData, ULONG regDataLen, FFstrbuf* error)
{
DWORD bufSize; //with tailing '\0'
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS)
switch (arg->type)
{
if(error)
case FF_ARG_TYPE_STRBUF:
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars);
if (regType != REG_SZ && regType != REG_EXPAND_SZ)
goto type_mismatch;
FFstrbuf* strbuf = (FFstrbuf*) arg->value;
uint32_t strLen = regDataLen / sizeof(wchar_t);
if (strLen == 0)
ffStrbufClear(strbuf);
else
{
const wchar_t* ws = (const wchar_t*) regData;
if (ws[strLen - 1] == L'\0')
--strLen;
ffStrbufSetNWS(strbuf, strLen, ws);
}
break;
}
return false;
}
assert(bufSize >= sizeof(wchar_t));
wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize);
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS)
{
if(error)
case FF_ARG_TYPE_UINT:
case FF_ARG_TYPE_UINT64:
case FF_ARG_TYPE_UINT16:
case FF_ARG_TYPE_UINT8:
case FF_ARG_TYPE_BOOL:
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars);
uint64_t value = 0;
if (regType == REG_DWORD)
{
if (regDataLen < sizeof(uint32_t))
goto type_mismatch;
value = *(uint32_t*) regData;
}
else if (regType == REG_QWORD)
{
if (regDataLen < sizeof(uint64_t))
goto type_mismatch;
value = *(uint64_t*) regData;
}
else
goto type_mismatch;
if (arg->type == FF_ARG_TYPE_UINT) *(uint32_t*) arg->value = (uint32_t) value;
else if (arg->type == FF_ARG_TYPE_UINT64) *(uint64_t*) arg->value = (uint64_t) value;
else if (arg->type == FF_ARG_TYPE_UINT16) *(uint16_t*) arg->value = (uint16_t) value;
else if (arg->type == FF_ARG_TYPE_UINT8) *(uint8_t*) arg->value = (uint8_t) value;
else if (arg->type == FF_ARG_TYPE_BOOL) *(bool*) arg->value = value != 0;
break;
}
return false;
case FF_ARG_TYPE_FLOAT:
{
if (regDataLen < sizeof(float))
goto type_mismatch;
*(float*) arg->value = *(float*) regData;
break;
}
case FF_ARG_TYPE_DOUBLE:
{
if (regDataLen < sizeof(double))
goto type_mismatch;
*(double*) arg->value = *(double*) regData;
break;
}
case FF_ARG_TYPE_LIST:
{
if (regType != REG_MULTI_SZ)
goto type_mismatch;
FFlist* list = (FFlist*) arg->value;
if (list->elementSize != sizeof(FFstrbuf))
{
if (error)
{
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: expected list of strbuf for REG_MULTI_SZ", nameA.chars);
}
return false;
}
ffListClear(list);
for (
const wchar_t* ptr = (const wchar_t*) regData;
(const uint8_t*) ptr < (const uint8_t*) regData + regDataLen && *ptr;
ptr++
)
{
uint32_t strLen = (uint32_t) wcsnlen(ptr, regDataLen / sizeof(wchar_t) - (size_t) (ptr - (const wchar_t*) regData));
ffStrbufInitNWS(FF_LIST_ADD(FFstrbuf, *list), strLen, ptr);
ptr += strLen;
}
break;
}
case FF_ARG_TYPE_BUFFER:
{
if (regType != REG_BINARY)
goto type_mismatch;
FFArgBuffer* buffer = (FFArgBuffer*) arg->value;
if (buffer->length == 0)
{
buffer->data = malloc(regDataLen);
}
else if (buffer->length < regDataLen)
{
if (error)
{
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "ffRegReadValues(%s) buffer too small (%u): expected %u", nameA.chars, (unsigned) buffer->length, (unsigned) regDataLen);
}
return false;
}
buffer->length = regDataLen;
memcpy(buffer->data, regData, regDataLen);
break;
}
case FF_ARG_TYPE_INT: // Use UINT instead
case FF_ARG_TYPE_STRING:
case FF_ARG_TYPE_NULL:
default:
if (error)
{
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "processRegValue(%s) unsupported FFArgType %u", nameA.chars, (unsigned) arg->type);
}
return false;
}
ffStrbufSetNWS(result, (uint32_t) (bufSize / sizeof(*resultW) - 1), resultW);
return true;
type_mismatch:
FF_DEBUG("ffRegReadValues(%ls) type mismatch: regType=%u, argType=%u, dataLen=%u",
arg->name ?: L"(default)", (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
if (error)
{
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: regType=%u, argType=%u, dataLen=%u",
nameA.chars, (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
}
return false;
}
bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error)
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error)
{
assert(result && length);
DWORD bufSize = 0;
LONG err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, NULL, &bufSize);
if(err != ERROR_SUCCESS || bufSize == 0)
{
if(error)
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, NULL, &bufSize) failed", valueNameA.chars);
}
return false;
}
UNICODE_STRING* valueNameU = &(UNICODE_STRING) {
.Length = arg->name ? (USHORT) (wcslen(arg->name) * sizeof(wchar_t)) : 0 /*(default)*/,
.MaximumLength = 0,
.Buffer = (wchar_t*) arg->name,
};
uint8_t* buf = (uint8_t*) malloc(bufSize);
err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, buf, &bufSize);
if(err != ERROR_SUCCESS)
{
if(error)
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, length) failed", valueNameA.chars);
}
free(buf);
return false;
}
*result = buf;
*length = bufSize;
return true;
}
alignas(KEY_VALUE_PARTIAL_INFORMATION) uint8_t staticBuffer[128 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
FF_AUTO_FREE uint8_t* dynamicBuffer = NULL;
bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error)
{
DWORD bufSize = sizeof(*result);
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS)
{
if(error)
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_DWORD) failed", valueNameA.chars);
}
return false;
}
return true;
}
KEY_VALUE_PARTIAL_INFORMATION* buffer = (KEY_VALUE_PARTIAL_INFORMATION*) &staticBuffer;
DWORD bufSize = sizeof(staticBuffer);
if (NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
goto process_value;
bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error)
{
DWORD bufSize = sizeof(*result);
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_QWORD, NULL, result, &bufSize) != ERROR_SUCCESS)
{
if(error)
{
if(!valueNameW)
valueNameW = L"(default)";
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_QWORD) failed", valueNameA.chars);
}
return false;
}
return true;
}
bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error)
{
DWORD bufSize = 0;
if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &bufSize, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
if (bufSize == 0)
{
FF_DEBUG("NtQueryValueKey(%p, %ls) failed (bufSize=0)", hKey, arg->name ?: L"(default)");
if (error)
ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed");
{
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s) failed", hKey, valueNameA.chars);
}
return false;
}
++bufSize;
wchar_t* FF_AUTO_FREE resultW = (wchar_t*) malloc(bufSize * sizeof(*resultW));
if(RegEnumKeyExW(hKey, index, resultW, &bufSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
dynamicBuffer = (uint8_t*) malloc(bufSize);
buffer = (KEY_VALUE_PARTIAL_INFORMATION*) dynamicBuffer;
if (!NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
{
FF_DEBUG("NtQueryValueKey(%p, %ls, buffer=%u) failed", hKey, arg->name ?: L"(default)", (unsigned) bufSize);
if (error)
ffStrbufAppendF(error, "RegEnumKeyExW(hKey, %u) failed", (unsigned) index);
{
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s, buffer) failed", hKey, valueNameA.chars);
}
return false;
}
ffStrbufSetWS(result, resultW);
return true;
process_value:
FF_DEBUG("Read value from %p (%ls), type=%u, len=%u", hKey, arg->name ?: L"(default)", (unsigned) buffer->Type, (unsigned) buffer->DataLength);
return processRegValue(arg, buffer->Type, buffer->Data, buffer->DataLength, error);
}
bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error)
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error)
{
DWORD buffer;
if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &buffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
if (__builtin_expect(argc == 0, false))
return true;
assert(argv);
FF_AUTO_FREE UNICODE_STRING* names = (UNICODE_STRING*) calloc(argc, sizeof(*names));
FF_AUTO_FREE KEY_VALUE_ENTRY* entries = (KEY_VALUE_ENTRY*) calloc(argc, sizeof(*entries));
for (uint32_t i = 0; i < argc; ++i)
{
if (__builtin_expect(!argv[i].value, false))
{
FF_DEBUG("ffRegReadValues(argv[%u].value) is NULL", (unsigned) i);
if (error) ffStrbufAppendF(error, "ffRegReadValues(argv[%u].pVar) is NULL", (unsigned) i);
return false;
}
names[i] = (UNICODE_STRING) {
.Length = argv[i].name ? (USHORT) (wcslen(argv[i].name) * sizeof(wchar_t)) : 0 /*(default)*/,
.MaximumLength = 0,
.Buffer = (wchar_t*) argv[i].name,
};
entries[i].ValueName = &names[i];
}
ULONG bufferSize = argc * 128;
if (bufferSize < 512)
bufferSize = 512;
FF_AUTO_FREE uint8_t* buffer = NULL;
while (true)
{
buffer = (uint8_t*) realloc(buffer, bufferSize);
ULONG writtenSize = bufferSize;
ULONG requiredSize = 0;
NTSTATUS status = NtQueryMultipleValueKey(hKey, entries, argc, buffer, &writtenSize, &requiredSize);
if (!NT_SUCCESS(status))
{
// Buffer too small: docs guarantee requiredSize is returned when provided.
if (requiredSize > bufferSize)
{
FF_DEBUG("NtQueryMultipleValueKey(%p) resize buffer: %u -> %u", hKey, (unsigned) bufferSize, (unsigned) requiredSize);
bufferSize = requiredSize;
continue;
}
FF_DEBUG("NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X", hKey, (unsigned) argc, (unsigned) status);
if (error)
ffStrbufAppendF(error, "NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X",
hKey, (unsigned) argc, (unsigned) status);
return false;
}
break;
}
for (uint32_t i = 0; i < argc; ++i)
{
const FFRegValueArg* arg = &argv[i];
const KEY_VALUE_ENTRY* entry = &entries[i];
FF_DEBUG("Read value[%u] from %p: type=%u, len=%u", (unsigned) i, hKey, (unsigned) entry->Type, (unsigned) entry->DataLength);
if (!processRegValue(arg, entry->Type, buffer + entry->DataOffset, entry->DataLength, error))
return false;
}
return true;
}
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error)
{
assert(hKey);
assert(result);
alignas(KEY_BASIC_INFORMATION) uint8_t buffer[sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(wchar_t)];
ULONG bufSize = (ULONG) sizeof(buffer);
KEY_BASIC_INFORMATION* keyInfo = (KEY_BASIC_INFORMATION*) buffer;
if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize)))
{
FF_DEBUG("NtEnumerateKey(hKey=%p, index=%u) failed", hKey, (unsigned) index);
if (error)
ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed");
ffStrbufAppendF(error, "NtEnumerateKey(hKey=%p, %u, keyInfo) failed", hKey, (unsigned) index);
return false;
}
*result = buffer;
ffStrbufSetNWS(result, keyInfo->NameLength / sizeof(wchar_t), keyInfo->Name);
return true;
}
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error)
{
assert(hKey);
assert(result);
alignas(KEY_FULL_INFORMATION) uint8_t buffer[sizeof(KEY_FULL_INFORMATION) + MAX_PATH * sizeof(wchar_t)];
ULONG bufSize = sizeof(buffer);
KEY_FULL_INFORMATION* keyInfo = (KEY_FULL_INFORMATION*) buffer;
if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize)))
{
FF_DEBUG("NtQueryKey(hKey=%p, KeyFullInformation) failed", hKey);
if (error)
ffStrbufAppendF(error, "NtQueryKey(hKey=%p, KeyFullInformation, keyInfo) failed", hKey);
return false;
}
*result = (uint32_t) keyInfo->SubKeys;
return true;
}
+60 -13
View File
@@ -1,21 +1,68 @@
#pragma once
#include "fastfetch.h"
#include "common/argType.h"
#include "common/io.h"
#include <windows.h>
#ifndef HKEY_CURRENT_USER
#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000))
#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001))
#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002))
#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003))
#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004))
#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005))
#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006))
#define HKEY_CURRENT_USER_LOCAL_SETTINGS ((HKEY) (ULONG_PTR)((LONG)0x80000007))
#endif
static inline void wrapRegCloseKey(HKEY* phKey)
typedef struct FFRegValueArg
{
if(*phKey)
RegCloseKey(*phKey);
FFArgType type;
const void* value;
const wchar_t* name;
} FFRegValueArg;
HANDLE ffRegGetRootKeyHandle(HKEY hKey);
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error);
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error);
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error);
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error);
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error);
static inline bool ffRegOpenKeyForRead(HKEY hRootKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error)
{
return ffRegOpenSubkeyForRead(ffRegGetRootKeyHandle(hRootKey), subKeyW, result, error);
}
#define FF_HKEY_AUTO_DESTROY HKEY __attribute__((__cleanup__(wrapRegCloseKey)))
bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error);
bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error);
bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error);
bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error);
bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error);
bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error);
bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error);
static inline bool ffRegReadStrbuf(HANDLE hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error)
{
return ffRegReadValue(hKey, &(FFRegValueArg) {
.type = FF_ARG_TYPE_STRBUF,
.value = result,
.name = valueNameW,
}, error);
}
static inline bool ffRegReadUint(HANDLE hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error)
{
return ffRegReadValue(hKey, &(FFRegValueArg) {
.type = FF_ARG_TYPE_UINT,
.value = result,
.name = valueNameW,
}, error);
}
static inline bool ffRegReadUint64(HANDLE hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error)
{
return ffRegReadValue(hKey, &(FFRegValueArg) {
.type = FF_ARG_TYPE_UINT64,
.value = result,
.name = valueNameW,
}, error);
}
static inline bool ffRegReadData(HANDLE hKey, const wchar_t* valueNameW, FFArgBuffer* buffer, FFstrbuf* error)
{
return ffRegReadValue(hKey, &(FFRegValueArg) {
.type = FF_ARG_TYPE_BUFFER,
.value = buffer,
.name = valueNameW,
}, error);
}
+23 -13
View File
@@ -1,6 +1,6 @@
#include "unicode.h"
#include <windows.h>
#include "common/windows/nt.h"
void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
{
@@ -10,15 +10,19 @@ void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
return;
}
int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL);
if (size_needed <= 0)
ULONG size_needed = 0;
NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t));
if (size_needed == 0)
{
ffStrbufSetF(result, "WCTMB failed: %u", (unsigned) GetLastError());
ffStrbufSetF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status);
return;
}
ffStrbufEnsureFixedLengthFree(result, (uint32_t)size_needed);
WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars, size_needed, NULL, NULL);
result->length = (uint32_t)size_needed;
ffStrbufEnsureFixedLengthFree(result, size_needed);
RtlUnicodeToUTF8N(result->chars, size_needed, &size_needed, source, length * sizeof(wchar_t));
result->length = size_needed;
result->chars[size_needed] = '\0';
}
@@ -27,12 +31,18 @@ void ffStrbufAppendNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
if(!length)
return;
int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL);
if (size_needed <= 0)
return;
ULONG size_needed = 0;
NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t));
ffStrbufEnsureFree(result, (uint32_t)size_needed);
WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars + result->length, size_needed, NULL, NULL);
result->length += (uint32_t)size_needed;
if (size_needed == 0)
{
ffStrbufAppendF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status);
return;
}
ffStrbufEnsureFree(result, size_needed);
RtlUnicodeToUTF8N(result->chars + result->length, size_needed, &size_needed, source, length * sizeof(wchar_t));
result->length += size_needed;
result->chars[result->length] = '\0';
}
+78 -35
View File
@@ -1,49 +1,92 @@
#include "common/windows/version.h"
#include "common/debug.h"
#include "common/mallocHelper.h"
#include "common/windows/version.h"
#include "common/windows/unicode.h"
#include <windows.h>
#define FF_VERSION_LANG_EN_US L"040904b0"
bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrbuf* version)
{
FF_DEBUG("ffGetFileVersion: enter filePath=%ls stringName=%ls", filePath, stringName);
DWORD handle;
DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
if (size > 0)
if (size == 0)
{
FF_AUTO_FREE void *versionData = malloc(size);
if (GetFileVersionInfoW(filePath, handle, size, versionData))
{
if (!stringName)
{
VS_FIXEDFILEINFO* verInfo;
UINT len;
if (VerQueryValueW(versionData, L"\\", (void **)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD)
{
ffStrbufSetF(version, "%u.%u.%u.%u",
(unsigned)((verInfo->dwProductVersionMS >> 16) & 0xffff),
(unsigned)((verInfo->dwProductVersionMS >> 0) & 0xffff),
(unsigned)((verInfo->dwProductVersionLS >> 16) & 0xffff),
(unsigned)((verInfo->dwProductVersionLS >> 0) & 0xffff));
return true;
}
}
else
{
wchar_t* value;
UINT valueLen;
wchar_t subBlock[128] = L"\\StringFileInfo\\" FF_VERSION_LANG_EN_US L"\\";
wcscat_s(subBlock, ARRAY_SIZE(subBlock), stringName);
if (VerQueryValueW(versionData, subBlock, (void **)&value, &valueLen) && valueLen > 0)
{
ffStrbufSetWS(version, value);
return true;
}
}
}
DWORD err = GetLastError();
FF_DEBUG("GetFileVersionInfoSizeW failed: err=%lu (%s)",
(unsigned long) err, ffDebugWin32Error(err));
return false;
}
FF_DEBUG("GetFileVersionInfoSizeW ok: size=%lu handle=%lu",
(unsigned long) size, (unsigned long) handle);
FF_AUTO_FREE void* versionData = malloc(size);
if (!versionData)
{
FF_DEBUG("malloc failed: size=%lu", (unsigned long) size);
return false;
}
if (!GetFileVersionInfoW(filePath, handle, size, versionData))
{
DWORD err = GetLastError();
FF_DEBUG("GetFileVersionInfoW failed: err=%lu (%s)",
(unsigned long) err, ffDebugWin32Error(err));
return false;
}
FF_DEBUG("GetFileVersionInfoW ok");
if (!stringName)
{
VS_FIXEDFILEINFO* verInfo;
UINT len;
if (VerQueryValueW(versionData, L"\\", (void**) &verInfo, &len) &&
len &&
verInfo->dwSignature == 0xFEEF04BD)
{
ffStrbufSetF(version, "%u.%u.%u.%u",
(unsigned) ((verInfo->dwProductVersionMS >> 16) & 0xffff),
(unsigned) ((verInfo->dwProductVersionMS >> 0) & 0xffff),
(unsigned) ((verInfo->dwProductVersionLS >> 16) & 0xffff),
(unsigned) ((verInfo->dwProductVersionLS >> 0) & 0xffff));
FF_DEBUG("fixed version resolved: %s", version->chars);
return true;
}
FF_DEBUG("fixed version query failed or invalid signature");
return false;
}
struct { WORD language; WORD codePage; }* translations;
UINT translationsLen;
if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation", (void**) &translations, &translationsLen) &&
translationsLen >= sizeof(*translations))
{
wchar_t subBlock[128];
snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls",
translations[0].language, translations[0].codePage, stringName);
FF_DEBUG("query version string with translation: %ls", subBlock);
wchar_t* value;
UINT valueLen; // Number of characters, including null terminator
if (VerQueryValueW(versionData, subBlock, (void**) &value, &valueLen) && valueLen > 0)
{
ffStrbufSetNWS(version, valueLen - 1, value);
FF_DEBUG("version string resolved (translation fallback): %s", version->chars);
return true;
}
FF_DEBUG("translation fallback query failed");
}
else
{
FF_DEBUG("no translation table found in version resource");
}
FF_DEBUG("ffGetFileVersion failed");
return false;
}
+7 -9
View File
@@ -29,20 +29,18 @@ const char* ffDetectBios(FFBiosResult* bios)
if (!device)
return "IODeviceTree:/ not found";
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceProps = NULL;
if(IORegistryEntryCreateCFProperties(device, &deviceProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
return "IORegistryEntryCreateCFProperties(device) failed";
ffCfDictGetString(deviceProps, CFSTR("manufacturer"), &bios->vendor);
ffCfDictGetString(deviceProps, CFSTR("time-stamp"), &bios->date);
FF_CFTYPE_AUTO_RELEASE CFDataRef manufacturer = IORegistryEntryCreateCFProperty(device, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
ffCfStrGetString(manufacturer, &bios->vendor);
FF_CFTYPE_AUTO_RELEASE CFDataRef timeStamp = IORegistryEntryCreateCFProperty(device, CFSTR("time-stamp"), kCFAllocatorDefault, kNilOptions);
ffCfStrGetString(timeStamp, &bios->date);
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
if (deviceChosen)
{
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmWareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
if (systemFirmWareVersion)
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmwareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
if (systemFirmwareVersion)
{
ffCfStrGetString(systemFirmWareVersion, &bios->version);
ffCfStrGetString(systemFirmwareVersion, &bios->version);
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
if (index != bios->version.length)
{
+12 -6
View File
@@ -2,14 +2,20 @@
#include "common/io.h"
#include "common/smbiosHelper.h"
#include <stdlib.h>
const char* ffDetectBios(FFBiosResult* bios)
{
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date))
{
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
}
else if (ffReadFileBuffer("/proc/device-tree/chosen/u-boot,version", &bios->version))
{
ffStrbufTrimRight(&bios->version, '\0');
ffStrbufSetStatic(&bios->vendor, "U-Boot");
}
if (ffPathExists("/sys/firmware/efi/", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE))
ffStrbufSetStatic(&bios->type, "UEFI");
else
+8 -2
View File
@@ -11,10 +11,12 @@
#include <fcntl.h>
#include <unistd.h>
#elif __sun
#include <libdevinfo.h>
#include <sys/sunddi.h>
#elif __APPLE__
#include "common/apple/cf_helpers.h"
#include <IOKit/IOKitLib.h>
#endif
typedef struct FFSmbiosBios
@@ -90,8 +92,12 @@ const char* ffDetectBios(FFBiosResult* bios)
}
di_fini(rootNode);
#elif __HAIKU__ || __OpenBSD__
// Currently SMBIOS detection is supported in legancy BIOS only
// Currently SMBIOS detection is supported in legacy BIOS only
ffStrbufSetStatic(&bios->type, "BIOS");
#elif __APPLE__
// Intel Macs use UEFI from day one
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceEfi = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/efi");
ffStrbufSetStatic(&bios->type, deviceEfi ? "UEFI" : "BIOS");
#endif
return NULL;
+1 -8
View File
@@ -9,14 +9,7 @@
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
{
// Actually bluetoothapis.dll, but it's missing on Windows 7
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis,
#if FF_WIN7_COMPAT
"bthprops.cpl"
#else
"bluetoothapis.dll"
#endif
, 1)
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextDevice)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindDeviceClose)
@@ -54,13 +54,7 @@ static_assert(sizeof(BTH_LOCAL_RADIO_INFO) == 292, "BTH_LOCAL_RADIO_INFO should
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
{
// Actually bluetoothapis.dll, but it's missing on Windows 7
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis,
#if FF_WIN7_COMPAT
"bthprops.cpl"
#else
"bluetoothapis.dll"
#endif
, 1)
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstRadio)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextRadio)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindRadioClose)
@@ -104,7 +98,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
device->connectable = ffBluetoothIsConnectable(hRadio);
device->discoverable = ffBluetoothIsDiscoverable(hRadio);
CloseHandle(hRadio);
NtClose(hRadio);
} while (ffBluetoothFindNextRadio(hFind, &hRadio));
ffBluetoothFindRadioClose(hFind);
+11 -8
View File
@@ -3,13 +3,14 @@
#include "common/io.h"
#include "common/windows/nt.h"
#include <ntstatus.h>
#include <windows.h>
const char* enablePrivilege(const wchar_t* privilege)
{
FF_AUTO_CLOSE_FD HANDLE token = NULL;
if (!OpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
return "OpenProcessToken() failed";
if (!NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)))
return "NtOpenProcessToken() failed";
TOKEN_PRIVILEGES tp = {
.PrivilegeCount = 1,
@@ -20,19 +21,21 @@ const char* enablePrivilege(const wchar_t* privilege)
if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid))
return "LookupPrivilegeValue() failed";
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL))
return "AdjustTokenPrivileges() failed";
NTSTATUS status = NtAdjustPrivilegesToken(token, false, &tp, sizeof(tp), NULL, NULL);
if (!NT_SUCCESS(status))
return "NtAdjustPrivilegesToken() failed";
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return "The token does not have the specified privilege";
if (status == STATUS_NOT_ALL_ASSIGNED)
return "The token does not have the specified privilege; try sudo please";
return NULL;
}
const char* ffDetectBootmgr(FFBootmgrResult* result)
{
if (enablePrivilege(L"SeSystemEnvironmentPrivilege") != NULL)
return "Failed to enable SeSystemEnvironmentPrivilege";
const char* err = enablePrivilege(L"SeSystemEnvironmentPrivilege");
if (err != NULL)
return err;
GUID efiGlobalGuid;
if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid)))
+9 -6
View File
@@ -110,26 +110,29 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options,
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_close_display)
#ifndef FF_DISABLE_DLOPEN
__typeof__(&ddca_init) ffddca_init = dlsym(libddcutil, "ddca_init");
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_init)
if (ffddca_init)
#else
__typeof__(&ddca_init) ffddca_init = ddca_init;
#endif
{
FF_SUPPRESS_IO();
// Ref: https://github.com/rockowitz/ddcutil/issues/344
if (ffddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
return "ddca_init() failed";
}
#ifndef FF_DISABLE_DLOPEN
else
{
__typeof__(&ddca_set_default_sleep_multiplier) ffddca_set_default_sleep_multiplier = dlsym(libddcutil, "ddca_set_default_sleep_multiplier");
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_set_default_sleep_multiplier);
if (ffddca_set_default_sleep_multiplier)
ffddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
libddcutil = NULL; // Don't dlclose libddcutil. See https://github.com/rockowitz/ddcutil/issues/330
}
#else
#if DDCUTIL_VMAJOR >= 2
if (ddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
return "ddca_init() failed";
#else
ddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
#endif
#endif
FF_AUTO_FREE DDCA_Display_Info_List* infoList = NULL;
+67 -16
View File
@@ -7,8 +7,37 @@ extern "C"
#include "common/windows/wmi.hpp"
#include "common/windows/unicode.hpp"
#include <highlevelmonitorconfigurationapi.h>
#include <physicalmonitorenumerationapi.h>
#include <winternl.h>
NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
_In_ UNICODE_STRING *pstrDeviceName,
_In_ DWORD dwPhysicalMonitorArraySize,
_Out_ DWORD *pdwNumPhysicalMonitorHandlesInArray,
_Out_ HANDLE *phPhysicalMonitorArray
);
typedef enum _MC_VCP_CODE_TYPE {
MC_MOMENTARY,
MC_SET_PARAMETER
} MC_VCP_CODE_TYPE, *LPMC_VCP_CODE_TYPE;
NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
_In_ HANDLE hMonitor,
_In_ DWORD dwVCPCode,
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
_Out_ DWORD *pdwCurrentValue,
_Out_opt_ DWORD *pdwMaximumValue
);
NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
_In_ HANDLE hMonitor
);
NTSTATUS WINAPI GetPhysicalMonitorDescription(
_In_ HANDLE hMonitor,
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
_Out_ LPWSTR szPhysicalMonitorDescription
);
static const char* detectWithWmi(FFlist* result)
{
@@ -40,33 +69,55 @@ static const char* detectWithWmi(FFlist* result)
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result)
{
FF_LIBRARY_LOAD_MESSAGE(dxva2, "dxva2" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, GetPhysicalMonitorsFromHMONITOR)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, GetMonitorBrightness)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, DestroyPhysicalMonitor)
void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
if (!gdi32) return "ffLibraryGetModule(gdi32.dll) failed";
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
{
PHYSICAL_MONITOR physicalMonitor;
if (ffGetPhysicalMonitorsFromHMONITOR((HMONITOR)(uintptr_t) display->id, 1, &physicalMonitor))
if (display->type == FF_DISPLAY_TYPE_BUILTIN) continue;
MONITORINFOEXW mi;
mi.cbSize = sizeof(mi);
if (!GetMonitorInfoW((HMONITOR)(uintptr_t) display->id, (LPMONITORINFO) &mi))
continue;
UNICODE_STRING deviceName = {
.Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
.MaximumLength = 0,
.Buffer = mi.szDevice,
};
HANDLE physicalMonitor;
DWORD monitorCount = 0;
if (NT_SUCCESS(ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor)) && monitorCount >= 1)
{
DWORD min = 0, curr = 0, max = 0;
if (ffGetMonitorBrightness(physicalMonitor.hPhysicalMonitor, &min, &curr, &max))
DWORD curr = 0, max = 0;
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max)))
{
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
if (display->name.length)
if (display->name.length > 0)
ffStrbufInitCopy(&brightness->name, &display->name);
else
ffStrbufInitWS(&brightness->name, physicalMonitor.szPhysicalMonitorDescription);
{
FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
if (ffGetPhysicalMonitorDescription)
{
wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description)))
ffStrbufInitWS(&brightness->name, description);
}
if (brightness->name.length == 0)
ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
}
brightness->max = max;
brightness->min = min;
brightness->min = 0;
brightness->current = curr;
brightness->builtin = false;
}
ffDestroyPhysicalMonitor(physicalMonitor.hPhysicalMonitor);
ffDestroyPhysicalMonitorInternal(physicalMonitor);
}
}
return NULL;
+9 -21
View File
@@ -38,10 +38,8 @@ const char* detectThermalTemp(const FFCPUOptions* options, double* result)
if (options->tempSensor.length > 0)
{
int written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, options->tempSensor.chars, (int) options->tempSensor.length, querySpec.Name, (int)(ARRAY_SIZE(querySpec.Name) - 1));
if (written == 0)
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(querySpec.Name, (ULONG) sizeof(querySpec.Name), NULL, options->tempSensor.chars, (ULONG)options->tempSensor.length + 1)))
return "Invalid temp sensor string";
querySpec.Name[written] = L'\0';
}
DWORD dataSize = 0;
@@ -252,28 +250,18 @@ static const char* detectNCores(FFCPUResult* cpu)
static const char* detectByRegistry(FFCPUResult* cpu)
{
FF_HKEY_AUTO_DESTROY hKey = NULL;
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL))
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL);
if (ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL))
if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) {
FF_ARG(cpu->name, L"ProcessorNameString"),
FF_ARG(cpu->vendor, L"VendorIdentifier"),
FF_ARG(cpu->frequencyBase, L"~MHz"),
}, NULL))
ffStrbufTrimRightSpace(&cpu->vendor);
if (cpu->coresLogical == 0)
{
FF_HKEY_AUTO_DESTROY hProcsKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &hProcsKey, NULL))
{
uint32_t cores;
if (ffRegGetNSubKeys(hProcsKey, &cores, NULL))
cpu->coresOnline = cpu->coresPhysical = cpu->coresLogical = (uint16_t) cores;
}
}
uint32_t mhz;
if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL))
cpu->frequencyBase = mhz;
else
return "ffRegReadValues() failed for CPU registry key";
return NULL;
}
+6 -3
View File
@@ -44,12 +44,15 @@ static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result,
ffStrbufSubstrBefore(path, baseLen);
ffStrbufAppendS(path, "/shared_cpu_list");
if (!ffReadFileBuffer(path->chars, buffer))
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
ffStrbufClear(buffer);
ffStrbufAppendC(buffer, '[');
if (!ffAppendFileBuffer(path->chars, buffer))
return "ffAppendFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
ffStrbufTrimRightSpace(buffer);
// deduplicate shared caches
ffStrbufAppendF(buffer, "_%u_%u_%u_%u\n", level, sizeKb, lineSize, cacheType);
ffStrbufAppendF(buffer, "_%u_%u_%u_%u]", level, sizeKb, lineSize, cacheType);
if (ffStrbufContain(added, buffer)) return NULL;
ffStrbufAppend(added, buffer);
ffCPUCacheAddItem(result, level, sizeKb * 1024, lineSize, cacheType);
+5 -2
View File
@@ -37,9 +37,12 @@ const char* ffDetectCPUCache(FFCPUCacheResult* result)
if (!data)
return "Cache information is not found in SMBIOS data";
for (; data->Header.Type == FF_SMBIOS_TYPE_CACHE_INFO;
data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header))
const FFSmbiosCacheInfo* endOfTable = (const FFSmbiosCacheInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
for (; data != endOfTable; data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header))
{
if (data->Header.Type != FF_SMBIOS_TYPE_CACHE_INFO)
continue;
bool enabled = !!(data->CacheConfiguration & (1 << 7));
if (!enabled)
continue;
+7 -6
View File
@@ -1,17 +1,18 @@
#include "cursor.h"
#include "common/io.h"
#include "common/windows/registry.h"
void ffDetectCursor(FFCursorResult* result)
{
FF_HKEY_AUTO_DESTROY hKey;
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Control Panel\\Cursors", &hKey, &result->error))
{
if (!ffRegReadStrbuf(hKey, NULL, &result->theme, &result->error))
return;
uint32_t cursorBaseSize;
if (ffRegReadUint(hKey, L"CursorBaseSize", &cursorBaseSize, NULL))
ffStrbufAppendF(&result->size, "%u", (unsigned) cursorBaseSize);
if (ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
FF_ARG(result->theme, NULL),
FF_ARG(cursorBaseSize, L"CursorBaseSize"),
}, &result->error))
ffStrbufAppendUInt(&result->size, cursorBaseSize);
}
}
+1 -15
View File
@@ -140,21 +140,7 @@ static void detectName(FFDisk* disk)
if (disk->name.length == 0) return;
// Basic\x20data\x20partition
for (uint32_t i = ffStrbufFirstIndexS(&disk->name, "\\x");
i != disk->name.length;
i = ffStrbufNextIndexS(&disk->name, i + 1, "\\x"))
{
uint32_t len = (uint32_t) strlen("\\x20");
if (disk->name.length >= len)
{
char bak = disk->name.chars[i + len];
disk->name.chars[i + len] = '\0';
disk->name.chars[i] = (char) strtoul(&disk->name.chars[i + 2], NULL, 16);
ffStrbufRemoveSubstr(&disk->name, i + 1, i + len);
disk->name.chars[i + 1] = bak;
}
}
ffStrbufDecodeHexEscapeSequences(&disk->name);
}
#ifdef __ANDROID__
+2 -1
View File
@@ -1,5 +1,6 @@
#include "disk.h"
#include "common/io.h"
#include "common/time.h"
#include "common/windows/unicode.h"
#include "common/windows/nt.h"
@@ -101,7 +102,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (fsVolume->VolumeLabelLength > 0)
ffStrbufSetNWS(&disk->name, fsVolume->VolumeLabelLength / sizeof(WCHAR), fsVolume->VolumeLabel);
if (fsVolume->VolumeCreationTime.QuadPart)
disk->createTime = ((uint64_t) fsVolume->VolumeCreationTime.QuadPart - 116444736000000000ull) / 10000ull;
disk->createTime = ffFileTimeToUnixMs((uint64_t) fsVolume->VolumeCreationTime.QuadPart);
}
if (fsAttr)
+2 -4
View File
@@ -5,8 +5,7 @@ FFDisplayResult* ffdsAppendDisplay(
uint32_t width,
uint32_t height,
double refreshRate,
uint32_t scaledWidth,
uint32_t scaledHeight,
uint32_t dpi,
uint32_t preferredWidth,
uint32_t preferredHeight,
double preferredRefreshRate,
@@ -26,8 +25,7 @@ FFDisplayResult* ffdsAppendDisplay(
display->width = width;
display->height = height;
display->refreshRate = refreshRate;
display->scaledWidth = scaledWidth;
display->scaledHeight = scaledHeight;
display->dpi = dpi ?: 96; // 0 means unknown
display->preferredWidth = preferredWidth;
display->preferredHeight = preferredHeight;
display->preferredRefreshRate = preferredRefreshRate;
+2 -4
View File
@@ -72,8 +72,7 @@ typedef struct FFDisplayResult
uint32_t width; // in px
uint32_t height; // in px
double refreshRate; // in Hz
uint32_t scaledWidth; // in px
uint32_t scaledHeight; // in px
uint32_t dpi; // Base 96
uint32_t preferredWidth; // in px
uint32_t preferredHeight; // in px
double preferredRefreshRate; // in Hz
@@ -110,8 +109,7 @@ FFDisplayResult* ffdsAppendDisplay(
uint32_t width,
uint32_t height,
double refreshRate,
uint32_t scaledWidth,
uint32_t scaledHeight,
uint32_t dpi,
uint32_t preferredWidth,
uint32_t preferredHeight,
double preferredRefreshRate,
@@ -85,7 +85,7 @@ static void detectWithDumpsys(FFDisplayServerResult* ds)
FFDisplayResult* display = ffdsAppendDisplay(ds,
(uint32_t)width, (uint32_t)height,
refreshRate,
0, 0,
0,
0, 0,
0,
0,
@@ -117,11 +117,11 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
ffStrbufSubstrAfterFirstC(&buffer, ',');
uint32_t height = (uint32_t) ffStrbufToUInt(&buffer, 0);
ffStrbufSubstrAfterFirstC(&buffer, ',');
double scaleFactor = (double) ffStrbufToUInt(&buffer, 0) / 160.;
uint32_t dpi = (uint32_t) ffStrbufToUInt(&buffer, 0) * 96 / 160;
FFDisplayResult* display = ffdsAppendDisplay(ds,
width, height,
0,
(uint32_t) (width / scaleFactor + .5), (uint32_t) (height / scaleFactor + .5),
dpi,
0, 0,
0,
0,
@@ -116,12 +116,14 @@ static void detectDisplays(FFDisplayServerResult* ds)
physicalHeight = (uint32_t) (size.height + 0.5);
}
uint32_t pixelWidth = (uint32_t) CGDisplayModeGetPixelWidth(mode);
uint32_t pixelHeight = (uint32_t) CGDisplayModeGetPixelHeight(mode);
FFDisplayResult* display = ffdsAppendDisplay(ds,
(uint32_t)CGDisplayModeGetPixelWidth(mode),
(uint32_t)CGDisplayModeGetPixelHeight(mode),
pixelWidth,
pixelHeight,
refreshRate,
(uint32_t)CGDisplayModeGetWidth(mode),
(uint32_t)CGDisplayModeGetHeight(mode),
pixelHeight * 96 / (uint32_t)CGDisplayModeGetHeight(mode),
preferredWidth,
preferredHeight,
preferredRefreshRate,
@@ -37,13 +37,11 @@ static void detectDisplays(FFDisplayServerResult* ds)
uint32_t width = (uint32_t) s.Frame().Width() + 1;
uint32_t height = (uint32_t) (uint32_t)s.Frame().Height() + 1;
double scaleFactor = (double) 1.0;
FFDisplayResult* res = ffdsAppendDisplay(ds,
width,
height,
(double)mode.timing.pixel_clock * 1000 / (mode.timing.v_total * mode.timing.h_total),
(uint32_t) (width / scaleFactor + .5),
(uint32_t) (height / scaleFactor + .5),
0,
0,
0,
0,
@@ -1,33 +1,26 @@
#include "displayserver.h"
#include "common/windows/unicode.h"
#include "common/edidHelper.h"
#include "common/windows/registry.h"
#include "common/windows/unicode.h"
#include <windows.h>
#include <shellscalingapi.h>
static inline void freeArgBuffer(FFArgBuffer* buffer)
{
if (buffer->data)
free(buffer->data);
buffer->data = NULL;
buffer->length = 0;
}
#define FF_AUTO_FREE_ARG_BUFFER __attribute__((__cleanup__(freeArgBuffer)))
// http://undoc.airesoft.co.uk/user32.dll/IsThreadDesktopComposited.php
BOOL WINAPI IsThreadDesktopComposited();
BOOL WINAPI GetDpiForMonitorInternal(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
static void detectDisplays(FFDisplayServerResult* ds)
{
#if FF_WIN7_COMPAT
static __typeof__(GetDpiForMonitorInternal)* ffGetDpiForMonitor;
if (!ffGetDpiForMonitor)
{
HMODULE user32 = GetModuleHandleW(L"user32.dll");
if (user32)
{
// GetDpiForMonitorInternal (returns BOOL) is in user32, while GetDpiForMonitor (returns HRESULT) is in shcore.
// Both are available since Windows 8.1. Not sure why Microsoft decided to put them in different DLLs, but whatever.
// Use GetDpiForMonitorInternal for loading one less dll
ffGetDpiForMonitor = (void*) GetProcAddress(user32, "GetDpiForMonitorInternal");
}
}
#else
#define ffGetDpiForMonitor GetDpiForMonitorInternal
#endif
DISPLAYCONFIG_PATH_INFO paths[128];
uint32_t pathCount = ARRAY_SIZE(paths);
DISPLAYCONFIG_MODE_INFO modes[256];
@@ -46,15 +39,6 @@ static void detectDisplays(FFDisplayServerResult* ds)
const DISPLAYCONFIG_PATH_INFO* path = &paths[i];
const DISPLAYCONFIG_SOURCE_MODE* sourceMode = &modes[path->sourceInfo.modeInfoIdx].sourceMode;
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {
.header = {
.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME,
.size = sizeof(sourceName),
.adapterId = path->sourceInfo.adapterId,
.id = path->sourceInfo.id,
},
};
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
uint32_t physicalWidth = 0, physicalHeight = 0;
@@ -66,9 +50,7 @@ static void detectDisplays(FFDisplayServerResult* ds)
.id = path->targetInfo.id,
},
};
uint8_t edidData[1024];
DWORD edidLength = 0;
FF_AUTO_FREE_ARG_BUFFER FFArgBuffer edid = {};
if(DisplayConfigGetDeviceInfo(&targetName.header) == ERROR_SUCCESS)
{
wchar_t regPath[256] = L"SYSTEM\\CurrentControlSet\\Enum";
@@ -86,16 +68,17 @@ static void detectDisplays(FFDisplayServerResult* ds)
}
wcscpy(pRegPath, L"Device Parameters");
edidLength = ARRAY_SIZE(edidData);
if (RegGetValueW(HKEY_LOCAL_MACHINE, regPath, L"EDID", RRF_RT_REG_BINARY, NULL, edidData, &edidLength) == ERROR_SUCCESS &&
edidLength > 0 && edidLength % 128 == 0)
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regPath, &hKey, NULL) &&
ffRegReadData(hKey, L"EDID", &edid, NULL) &&
ffEdidIsValid(edid.data, edid.length))
{
ffEdidGetName(edidData, &name);
ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight);
ffEdidGetName(edid.data, &name);
ffEdidGetPhysicalSize(edid.data, &physicalWidth, &physicalHeight);
}
else
{
edidLength = 0;
edid.length = 0;
if (targetName.flags.friendlyNameFromEdid)
ffStrbufSetWS(&name, targetName.monitorFriendlyDeviceName);
else
@@ -109,17 +92,6 @@ static void detectDisplays(FFDisplayServerResult* ds)
uint32_t width = sourceMode->width;
uint32_t height = sourceMode->height;
if (path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE90 ||
path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE270)
{
uint32_t temp = width;
width = height;
height = temp;
temp = physicalWidth;
physicalWidth = physicalHeight;
physicalHeight = temp;
}
uint32_t rotation;
switch (path->targetInfo.rotation)
{
@@ -145,15 +117,11 @@ static void detectDisplays(FFDisplayServerResult* ds)
}
uint32_t systemDpi = 0;
if (ffGetDpiForMonitor)
HMONITOR hMonitor = MonitorFromPoint(*(POINT*)&sourceMode->position, MONITOR_DEFAULTTONULL);
if (hMonitor)
{
HMONITOR hMonitor = MonitorFromPoint(*(POINT*)&sourceMode->position, MONITOR_DEFAULTTONULL);
if (hMonitor)
{
UINT ignored;
ffGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &systemDpi, &ignored);
}
UINT ignored;
GetDpiForMonitorInternal(hMonitor, MDT_EFFECTIVE_DPI, &systemDpi, &ignored);
}
if (systemDpi == 0)
@@ -164,12 +132,19 @@ static void detectDisplays(FFDisplayServerResult* ds)
ReleaseDC(NULL, hdc);
}
if (path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE90 ||
path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE270)
{
uint32_t temp = width;
width = height;
height = temp;
}
FFDisplayResult* display = ffdsAppendDisplay(ds,
width,
height,
path->targetInfo.refreshRate.Numerator / (double) path->targetInfo.refreshRate.Denominator,
width * 96 / systemDpi,
height * 96 / systemDpi,
systemDpi,
preferredMode.width,
preferredMode.height,
preferredRefreshRate,
@@ -181,7 +156,7 @@ static void detectDisplays(FFDisplayServerResult* ds)
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED
? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL,
sourceMode->position.x == 0 && sourceMode->position.y == 0,
path->sourceInfo.id,
(uintptr_t) hMonitor,
physicalWidth,
physicalHeight,
"GDI"
@@ -230,8 +205,8 @@ static void detectDisplays(FFDisplayServerResult* ds)
else
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
}
if (edidLength > 0)
ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek);
if (edid.length > 0)
ffEdidGetSerialAndManufactureDate(edid.data, &display->serial, &display->manufactureYear, &display->manufactureWeek);
display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED;
}
}
@@ -79,7 +79,7 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
if (ffSettingsGetFreeBSDKenv("screen.height", &buf))
{
uint32_t height = (uint32_t) ffStrbufToUInt(&buf, 0);
ffdsAppendDisplay(ds, width, height, 0, 0, 0, 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, false, 0, 0, 0, "kenv");
ffdsAppendDisplay(ds, width, height, 0, 0, 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, false, 0, 0, 0, "kenv");
}
}
}
+2 -2
View File
@@ -83,7 +83,7 @@ static const char* drmParseSysfs(FFDisplayServerResult* result)
result,
width, height,
refreshRate,
0, 0,
0,
0, 0,
0,
0,
@@ -398,7 +398,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
FFDisplayResult* item = ffdsAppendDisplay(result,
width, height,
refreshRate,
0, 0,
0,
preferredWidth, preferredHeight,
preferredRefreshRate,
0,
@@ -25,7 +25,7 @@ static void waylandOutputModeListener(void* data, FF_MAYBE_UNUSED struct wl_outp
static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale)
{
WaylandDisplay* display = data;
display->scale = scale;
display->dpi = 96 * (uint32_t) scale;
}
static void waylandOutputGeometryListener(void *data,
@@ -51,7 +51,7 @@ static void handleXdgLogicalSize(void *data, FF_MAYBE_UNUSED struct zxdg_output_
// Seems the values are only useful when ractional scale is enabled
if (width < display->width)
{
display->scale = (double) display->width / width;
display->dpi = (uint32_t) (display->width * 96 / width);
}
}
@@ -86,7 +86,6 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
WaylandDisplay display = {
.parent = wldata,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
@@ -128,8 +127,7 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale + .5),
(uint32_t) (display.height / display.scale + .5),
display.dpi,
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
@@ -14,6 +14,7 @@ extern "C" {
/**
* @page page_kde_output_device_v2 The kde_output_device_v2 protocol
* @section page_ifaces_kde_output_device_v2 Interfaces
* - @subpage page_iface_kde_output_device_registry_v2 - output devices
* - @subpage page_iface_kde_output_device_v2 - output configuration representation
* - @subpage page_iface_kde_output_device_mode_v2 - output mode
* @section page_copyright_kde_output_device_v2 Copyright
@@ -29,8 +30,32 @@ extern "C" {
* </pre>
*/
struct kde_output_device_mode_v2;
struct kde_output_device_registry_v2;
struct kde_output_device_v2;
#ifndef KDE_OUTPUT_DEVICE_REGISTRY_V2_INTERFACE
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_INTERFACE
/**
* @page page_iface_kde_output_device_registry_v2 kde_output_device_registry_v2
* @section page_iface_kde_output_device_registry_v2_desc Description
*
* This interface can be used to list output devices.
*
* If this global is bound with a version less than 21, the unsupported_version
* protocol error will be posted.
* @section page_iface_kde_output_device_registry_v2_api API
* See @ref iface_kde_output_device_registry_v2.
*/
/**
* @defgroup iface_kde_output_device_registry_v2 The kde_output_device_registry_v2 interface
*
* This interface can be used to list output devices.
*
* If this global is bound with a version less than 21, the unsupported_version
* protocol error will be posted.
*/
extern const struct wl_interface kde_output_device_registry_v2_interface;
#endif
#ifndef KDE_OUTPUT_DEVICE_V2_INTERFACE
#define KDE_OUTPUT_DEVICE_V2_INTERFACE
/**
@@ -120,6 +145,119 @@ extern const struct wl_interface kde_output_device_v2_interface;
extern const struct wl_interface kde_output_device_mode_v2_interface;
#endif
#ifndef KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM
/**
* @ingroup iface_kde_output_device_registry_v2
* kde_output_device_registry_v2 error values
*
* These errors can be emitted in response to some requests.
*/
enum kde_output_device_registry_v2_error {
/**
* the registry was bound with an unsupported version
*/
KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_UNSUPPORTED_VERSION = 0,
};
#endif /* KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM */
/**
* @ingroup iface_kde_output_device_registry_v2
* @struct kde_output_device_registry_v2_listener
*/
struct kde_output_device_registry_v2_listener {
/**
* no new output announcements
*
* This event is sent in response to the stop request. The
* compositor will immediately destroy the object after sending
* this event.
* @since 21
*/
void (*finished)(void *data,
struct kde_output_device_registry_v2 *kde_output_device_registry_v2);
/**
* new available output
*
* This event is sent when a new output is connected or after
* binding this global to list all available outputs.
* @since 21
*/
void (*output)(void *data,
struct kde_output_device_registry_v2 *kde_output_device_registry_v2,
struct kde_output_device_v2 *output);
};
/**
* @ingroup iface_kde_output_device_registry_v2
*/
static inline int
kde_output_device_registry_v2_add_listener(struct kde_output_device_registry_v2 *kde_output_device_registry_v2,
const struct kde_output_device_registry_v2_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) kde_output_device_registry_v2,
(void (**)(void)) listener, data);
}
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP 0
/**
* @ingroup iface_kde_output_device_registry_v2
*/
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_FINISHED_SINCE_VERSION 21
/**
* @ingroup iface_kde_output_device_registry_v2
*/
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_OUTPUT_SINCE_VERSION 21
/**
* @ingroup iface_kde_output_device_registry_v2
*/
#define KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP_SINCE_VERSION 21
/** @ingroup iface_kde_output_device_registry_v2 */
static inline void
kde_output_device_registry_v2_set_user_data(struct kde_output_device_registry_v2 *kde_output_device_registry_v2, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) kde_output_device_registry_v2, user_data);
}
/** @ingroup iface_kde_output_device_registry_v2 */
static inline void *
kde_output_device_registry_v2_get_user_data(struct kde_output_device_registry_v2 *kde_output_device_registry_v2)
{
return wl_proxy_get_user_data((struct wl_proxy *) kde_output_device_registry_v2);
}
static inline uint32_t
kde_output_device_registry_v2_get_version(struct kde_output_device_registry_v2 *kde_output_device_registry_v2)
{
return wl_proxy_get_version((struct wl_proxy *) kde_output_device_registry_v2);
}
/** @ingroup iface_kde_output_device_registry_v2 */
static inline void
kde_output_device_registry_v2_destroy(struct kde_output_device_registry_v2 *kde_output_device_registry_v2)
{
wl_proxy_destroy((struct wl_proxy *) kde_output_device_registry_v2);
}
/**
* @ingroup iface_kde_output_device_registry_v2
*
* This request indicates that the client no longer wants to receive new
* output announcements. The compositor will send the
* kde_output_device_registry_v2.finished event in response to this request.
* The compositor may still send new output announcements after calling this
* request until the kde_output_device_registry_v2.finished event is sent.
*/
// static inline void
// kde_output_device_registry_v2_stop(struct kde_output_device_registry_v2 *kde_output_device_registry_v2)
// {
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_device_registry_v2,
// KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_device_registry_v2), 0);
// }
#ifndef KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM
#define KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM
/**
@@ -838,6 +976,16 @@ struct kde_output_device_v2_listener {
void (*auto_brightness)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t enabled);
/**
* the output has been removed
*
* This event is sent when the output device is disconnected and
* no new updates will be sent. The client should call the
* kde_output_device_v2.release request after receiving this event.
* @since 21
*/
void (*removed)(void *data,
struct kde_output_device_v2 *kde_output_device_v2);
};
/**
@@ -851,6 +999,8 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
(void (**)(void)) listener, data);
}
#define KDE_OUTPUT_DEVICE_V2_RELEASE 0
/**
* @ingroup iface_kde_output_device_v2
*/
@@ -995,7 +1145,15 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_AUTO_BRIGHTNESS_SINCE_VERSION 20
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_REMOVED_SINCE_VERSION 21
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_RELEASE_SINCE_VERSION 21
/** @ingroup iface_kde_output_device_v2 */
static inline void
@@ -1024,6 +1182,19 @@ kde_output_device_v2_destroy(struct kde_output_device_v2 *kde_output_device_v2)
wl_proxy_destroy((struct wl_proxy *) kde_output_device_v2);
}
/**
* @ingroup iface_kde_output_device_v2
*
* This notifies the compositor that the client no longer wishes to use
* the kde_output_device_v2 object.
*/
// static inline void
// kde_output_device_v2_release(struct kde_output_device_v2 *kde_output_device_v2)
// {
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_device_v2,
// KDE_OUTPUT_DEVICE_V2_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_device_v2), WL_MARSHAL_FLAG_DESTROY);
// }
#ifndef KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM
#define KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM
/**
@@ -18,6 +18,7 @@
#include <wayland-util.h>
extern const struct wl_interface kde_output_device_mode_v2_interface;
extern const struct wl_interface kde_output_device_v2_interface;
static const struct wl_interface *kde_output_device_v2_types[] = {
NULL,
@@ -28,14 +29,34 @@ static const struct wl_interface *kde_output_device_v2_types[] = {
NULL,
NULL,
NULL,
&kde_output_device_v2_interface,
&kde_output_device_mode_v2_interface,
&kde_output_device_mode_v2_interface,
};
static const struct wl_message kde_output_device_registry_v2_requests[] = {
{ "stop", "21", kde_output_device_v2_types + 0 },
};
static const struct wl_message kde_output_device_registry_v2_events[] = {
{ "finished", "21", kde_output_device_v2_types + 0 },
{ "output", "21n", kde_output_device_v2_types + 8 },
};
WL_EXPORT const struct wl_interface kde_output_device_registry_v2_interface = {
"kde_output_device_registry_v2", 21,
1, kde_output_device_registry_v2_requests,
2, kde_output_device_registry_v2_events,
};
static const struct wl_message kde_output_device_v2_requests[] = {
{ "release", "21", kde_output_device_v2_types + 0 },
};
static const struct wl_message kde_output_device_v2_events[] = {
{ "geometry", "iiiiissi", kde_output_device_v2_types + 0 },
{ "current_mode", "o", kde_output_device_v2_types + 8 },
{ "mode", "n", kde_output_device_v2_types + 9 },
{ "current_mode", "o", kde_output_device_v2_types + 9 },
{ "mode", "n", kde_output_device_v2_types + 10 },
{ "done", "", kde_output_device_v2_types + 0 },
{ "scale", "f", kde_output_device_v2_types + 0 },
{ "edid", "s", kde_output_device_v2_types + 0 },
@@ -69,12 +90,13 @@ static const struct wl_message kde_output_device_v2_events[] = {
{ "sharpness", "17u", kde_output_device_v2_types + 0 },
{ "priority", "18u", kde_output_device_v2_types + 0 },
{ "auto_brightness", "20u", kde_output_device_v2_types + 0 },
{ "removed", "21", kde_output_device_v2_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
"kde_output_device_v2", 20,
0, NULL,
36, kde_output_device_v2_events,
"kde_output_device_v2", 21,
1, kde_output_device_v2_requests,
37, kde_output_device_v2_events,
};
static const struct wl_message kde_output_device_mode_v2_events[] = {
@@ -86,7 +108,7 @@ static const struct wl_message kde_output_device_mode_v2_events[] = {
};
WL_EXPORT const struct wl_interface kde_output_device_mode_v2_interface = {
"kde_output_device_mode_v2", 20,
"kde_output_device_mode_v2", 21,
0, NULL,
5, kde_output_device_mode_v2_events,
};
@@ -83,7 +83,7 @@ static void waylandKdeCurrentModeListener(void* data, FF_MAYBE_UNUSED struct kde
static void waylandKdeScaleListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, wl_fixed_t scale)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->scale = wl_fixed_to_double(scale);
wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96;
}
static void waylandKdeEdidListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, const char* raw)
@@ -181,6 +181,7 @@ static struct kde_output_device_v2_listener outputListener = {
.sharpness = (void*) stubListener,
.priority = (void*) stubListener,
.auto_brightness = (void*) stubListener,
.removed = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
@@ -192,7 +193,6 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandKdeMode));
WaylandDisplay display = {
.parent = wldata,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
@@ -223,8 +223,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale + .5),
(uint32_t) (display.height / display.scale + .5),
display.dpi,
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
@@ -43,7 +43,7 @@ typedef struct WaylandDisplay
int32_t preferredRefreshRate;
int32_t physicalWidth;
int32_t physicalHeight;
double scale;
uint32_t dpi;
enum wl_output_transform transform;
FFDisplayType type;
FFstrbuf name;
@@ -12,7 +12,7 @@ static void waylandZwlrTransformListener(void* data, FF_MAYBE_UNUSED struct zwlr
static void waylandZwlrScaleListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, wl_fixed_t scale)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->scale = wl_fixed_to_double(scale);
wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96;
}
typedef struct WaylandZwlrMode
@@ -125,7 +125,6 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandZwlrMode));
WaylandDisplay display = {
.parent = wldata,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
@@ -146,8 +145,7 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale + 0.5),
(uint32_t) (display.height / display.scale + 0.5),
(uint32_t) display.dpi,
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
+1 -1
View File
@@ -302,7 +302,7 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
#elif __OpenBSD__
kvm_t* kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
int count = 0;
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_UID, userId, sizeof(*proc), &count);
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_UID, (int) userId, sizeof(*proc), &count);
if (proc)
{
for (int i = 0; i < count; ++i)
+27 -20
View File
@@ -93,7 +93,7 @@ static xcb_randr_get_output_property_reply_t* xcbRandrGetProperty(XcbRandrData*
static void xcbDetectWMfromEWMH(XcbRandrData* data, xcb_window_t rootWindow, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0)
if(result->wmProcessName.length > 0 || ffStrbufEqualS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND))
return;
FF_AUTO_FREE xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, rootWindow, "_NET_SUPPORTING_WM_CHECK");
@@ -127,7 +127,7 @@ static void xcbFetchServerVendor(XcbRandrData* data, FFDisplayServerResult* resu
}
}
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, uint32_t dpi)
{
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
@@ -153,13 +153,13 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
ffEdidGetName(edidData, name);
}
uint8_t randrEmulation = 0;
bool randrEmulation = false;
FF_AUTO_FREE xcb_randr_get_output_property_reply_t* randrEmulationReply = xcbRandrGetProperty(data, output, "RANDR Emulation");
if(randrEmulationReply)
{
int len = data->ffxcb_randr_get_output_property_data_length(randrEmulationReply);
if(len >= 1)
randrEmulation = data->ffxcb_randr_get_output_property_data(randrEmulationReply)[0];
randrEmulation = !!data->ffxcb_randr_get_output_property_data(randrEmulationReply)[0];
}
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, outputInfoReply->crtc, XCB_CURRENT_TIME);
@@ -211,8 +211,7 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
(uint32_t) (currentMode ? currentMode->width : crtcInfoReply->width),
(uint32_t) (currentMode ? currentMode->height : crtcInfoReply->height),
currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0,
(uint32_t) (crtcInfoReply->width / scaleFactor + .5),
(uint32_t) (crtcInfoReply->height / scaleFactor + .5),
dpi,
preferredMode ? (uint32_t) preferredMode->width : 0,
preferredMode ? (uint32_t) preferredMode->height : 0,
preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0,
@@ -228,17 +227,27 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
: (currentMode ? "xcb-randr-mode" : "xcb-randr-crtc")
);
if (item && edidData && edidLength >= 128)
if (item)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
if (edidData && edidLength >= 128)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
}
item->bitDepth = bitDepth;
if ((rotation == 90 || rotation == 180) && !randrEmulation)
{
// In XWayland mode, width / height has been swapped out of box
uint32_t tmp = item->width;
item->width = item->height;
item->height = tmp;
}
}
return !!item;
}
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, uint32_t dpi)
{
//for some reasons, we have to construct this our self
xcb_randr_output_iterator_t outputIterator = {
@@ -262,7 +271,7 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
while(outputIterator.rem > 0)
{
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType, screenResources, bitDepth, scaleFactor))
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType, screenResources, bitDepth, dpi))
foundOutput = true;
data->ffxcb_randr_output_next(&outputIterator);
}
@@ -274,8 +283,7 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
(uint32_t) monitor->width,
(uint32_t) monitor->height,
0,
(uint32_t) (monitor->width / scaleFactor + .5),
(uint32_t) (monitor->height / scaleFactor + .5),
dpi,
0, 0, 0,
0,
&name,
@@ -301,13 +309,13 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root);
FF_AUTO_FREE struct xcb_randr_get_screen_resources_current_reply_t* screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL);
double scaleFactor = 1;
uint32_t dpi = 0;
FF_AUTO_FREE const char* resourceManager = xcbGetProperty(data, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi))
scaleFactor = ffStrbufToDouble(&dpi, 96) / 96;
FF_STRBUF_AUTO_DESTROY dpiStr = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpiStr))
dpi = (uint32_t) ffStrbufToUInt(&dpiStr, 96);
}
uint8_t bitDepth = (uint8_t) (screen->root_depth / 3);
@@ -317,7 +325,7 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
while(monitorInfoIterator.rem > 0)
{
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data, screenResources, bitDepth, scaleFactor))
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data, screenResources, bitDepth, dpi))
foundMonitor = true;
data->ffxcb_randr_monitor_info_next(&monitorInfoIterator);
}
@@ -337,8 +345,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
(uint32_t) screen->width_in_pixels,
(uint32_t) screen->height_in_pixels,
0,
(uint32_t) screen->width_in_pixels,
(uint32_t) screen->height_in_pixels,
0,
0, 0, 0,
0,
NULL,
+21 -17
View File
@@ -76,7 +76,7 @@ static uint8_t* xrandrGetProperty(XrandrData* data, RROutput output, const char*
static void x11DetectWMFromEWMH(XrandrData* data, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0)
if(result->wmProcessName.length > 0 || ffStrbufEqualS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND))
return;
Window* wmWindow = (Window*) x11GetProperty(data, data->display, DefaultRootWindow(data->display), "_NET_SUPPORTING_WM_CHECK");
@@ -101,7 +101,7 @@ static void x11FetchServerVendor(XrandrData* data, FFDisplayServerResult* result
ffStrbufSetS(&result->wmProtocolName, serverVendor);
}
static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor, bool randrEmulation)
static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, uint32_t dpi, bool randrEmulation)
{
//We do the check here, because we want the best fallback display if this call failed
if(screenResources == NULL)
@@ -145,8 +145,7 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
(uint32_t) (currentMode ? currentMode->width : crtcInfo->width),
(uint32_t) (currentMode ? currentMode->height : crtcInfo->height),
currentMode ? (double) currentMode->dotClock / (double) ((uint32_t) currentMode->hTotal * currentMode->vTotal) : 0,
(uint32_t) (crtcInfo->width / scaleFactor + .5),
(uint32_t) (crtcInfo->height / scaleFactor + .5),
dpi,
preferredMode ? (uint32_t) preferredMode->width : 0,
preferredMode ? (uint32_t) preferredMode->height : 0,
preferredMode ? (double) preferredMode->dotClock / (double) ((uint32_t) preferredMode->hTotal * preferredMode->vTotal) : 0,
@@ -170,13 +169,20 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
}
item->bitDepth = bitDepth;
if ((rotation == 90 || rotation == 180) && !randrEmulation)
{
// In XWayland mode, width / height has been swapped out of box
uint32_t tmp = item->width;
item->width = item->height;
item->height = tmp;
}
}
data->ffXRRFreeCrtcInfo(crtcInfo);
return !!item;
}
static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType, XRRScreenResources* screenResources, uint8_t bitDepth, uint32_t dpi)
{
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, screenResources, output);
if(outputInfo == NULL)
@@ -195,7 +201,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name
uint8_t* randrEmulation = xrandrGetProperty(data, output, "RANDR Emulation", NULL);
bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, edidLength, screenResources, bitDepth, scaleFactor, randrEmulation ? !!randrEmulation[0] : false);
bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, edidLength, screenResources, bitDepth, dpi, randrEmulation ? !!randrEmulation[0] : false);
if (edidData)
data->ffXFree(edidData);
@@ -206,7 +212,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name
return res;
}
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, XRRScreenResources* screenResources, uint8_t bitDepth, uint32_t dpi)
{
bool foundOutput = false;
char* xname = data->ffXGetAtomName(data->display, monitorInfo->name);
@@ -215,7 +221,7 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, X
FFDisplayType displayType = ffdsGetDisplayType(name.chars);
for(int i = 0; i < monitorInfo->noutput; i++)
{
if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType, screenResources, bitDepth, scaleFactor))
if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType, screenResources, bitDepth, dpi))
foundOutput = true;
}
@@ -226,8 +232,7 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, X
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
0,
(uint32_t) (monitorInfo->width / scaleFactor + .5),
(uint32_t) (monitorInfo->height / scaleFactor + .5),
dpi,
0, 0, 0,
0,
&name,
@@ -251,13 +256,13 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
XRRScreenResources* screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen));
double scaleFactor = 1;
uint32_t dpi = 1;
char* resourceManager = (char*) x11GetProperty(data, data->display, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi))
scaleFactor = ffStrbufToDouble(&dpi, 96) / 96;
FF_STRBUF_AUTO_DESTROY dpiStr = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpiStr))
dpi = (uint32_t) ffStrbufToUInt(&dpiStr, 96);
data->ffXFree(resourceManager);
}
uint8_t bitDepth = (uint8_t) (screen->root_depth / 3);
@@ -266,7 +271,7 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
for(int i = 0; i < numberOfMonitors; i++)
{
if(xrandrHandleMonitor(data, &monitorInfos[i], screenResources, bitDepth, scaleFactor))
if(xrandrHandleMonitor(data, &monitorInfos[i], screenResources, bitDepth, dpi))
foundAMonitor = true;
}
@@ -287,8 +292,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
(uint32_t) WidthOfScreen(screen),
(uint32_t) HeightOfScreen(screen),
0,
(uint32_t) WidthOfScreen(screen),
(uint32_t) HeightOfScreen(screen),
0,
0, 0, 0,
0,
NULL,
+1 -1
View File
@@ -15,7 +15,7 @@ static const char* detectDnsFromConf(const char* path, FFDNSOptions* options, FF
FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r");
if (!file)
{
FF_DEBUG("Failed to open %s: %m", path);
FF_DEBUG("Failed to open %s: %s", path, strerror(errno));
return "fopen(path, r) failed";
}
+1 -1
View File
@@ -18,7 +18,7 @@ static const char* detectDnsFromConf(const char* path, FFDNSOptions* options, FF
FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r");
if (!file)
{
FF_DEBUG("Failed to open %s: %m", path);
FF_DEBUG("Failed to open %s: %s", path, strerror(errno));
return "fopen(path, r) failed";
}
+2 -3
View File
@@ -51,15 +51,14 @@ const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
{
SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr;
ffStrbufInitA(item, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &ipv4->sin_addr, item->chars, item->allocated);
item->length = (uint32_t) (RtlIpv4AddressToStringA(&ipv4->sin_addr, item->chars) - item->chars);
}
else if (ifa->Address.lpSockaddr->sa_family == AF_INET6)
{
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
ffStrbufInitA(item, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &ipv6->sin6_addr, item->chars, item->allocated);
item->length = (uint32_t) (RtlIpv6AddressToStringA(&ipv6->sin6_addr, item->chars) - item->chars);
}
ffStrbufRecalculateLength(item);
}
break;
}
-8
View File
@@ -7,14 +7,6 @@
#include <stdlib.h>
#ifdef _WIN32
static inline char* realpath(const char* restrict file_name, char* restrict resolved_name)
{
assert(resolved_name != NULL);
return _fullpath(resolved_name, file_name, _MAX_PATH);
}
#endif
static bool extractNvimVersionFromBinary(const char* str, FF_MAYBE_UNUSED uint32_t len, void* userdata)
{
if (!ffStrStartsWith(str, "NVIM v")) return true;
+28 -8
View File
@@ -1,5 +1,6 @@
#include "font.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include <windows.h>
@@ -25,17 +26,36 @@ static void generateString(FFFontResult* font)
const char* ffDetectFontImpl(FFFontResult* result)
{
NONCLIENTMETRICSW info = { .cbSize = sizeof(info) };
if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0))
return "SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed";
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if (!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics", &hKey, NULL))
return "ffRegOpenKeyForRead(HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics) failed";
LOGFONTW* fonts[4] = { &info.lfCaptionFont, &info.lfMenuFont, &info.lfMessageFont, &info.lfStatusFont };
LOGFONTW fonts[4];
FFArgBuffer fontBuffers[4] = {
{ .data = &fonts[0], .length = sizeof(fonts[0]) },
{ .data = &fonts[1], .length = sizeof(fonts[1]) },
{ .data = &fonts[2], .length = sizeof(fonts[2]) },
{ .data = &fonts[3], .length = sizeof(fonts[3]) },
};
for(uint32_t i = 0; i < ARRAY_SIZE(fonts); ++i)
if (!ffRegReadValues(hKey, 4, (FFRegValueArg[]) {
FF_ARG(fontBuffers[0], L"CaptionFont"),
FF_ARG(fontBuffers[1], L"MenuFont"),
FF_ARG(fontBuffers[2], L"MessageFont"),
FF_ARG(fontBuffers[3], L"StatusFont"),
}, NULL))
return "ffRegReadValues(HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics) failed";
for (uint32_t i = 0; i < ARRAY_SIZE(fonts); ++i)
{
ffStrbufSetWS(&result->fonts[i], fonts[i]->lfFaceName);
if(fonts[i]->lfHeight < 0)
ffStrbufAppendF(&result->fonts[i], " (%dpt)", (int)-fonts[i]->lfHeight);
if (fontBuffers[i].length != sizeof(LOGFONTW))
continue; // Invalid data, skip
LOGFONTW* logFont = &fonts[i];
ffStrbufSetWS(&result->fonts[i], logFont->lfFaceName);
if (logFont->lfHeight < 0)
ffStrbufAppendF(&result->fonts[i], " (%dpt)", (int)-logFont->lfHeight);
}
generateString(result);
+1 -2
View File
@@ -3,7 +3,6 @@
#include "common/mallocHelper.h"
#include "common/windows/unicode.h"
#include <winternl.h>
#include <windows.h>
#include <hidsdi.h>
@@ -159,7 +158,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
OVERLAPPED overlapped = { };
DWORD nBytes;
if (ReadFile(hHidFile, reportBuffer, caps.InputReportByteLength, &nBytes, &overlapped) ||
(WaitForSingleObject(hHidFile, FF_IO_TERM_RESP_WAIT_MS) == WAIT_OBJECT_0 && GetOverlappedResult(hHidFile, &overlapped, &nBytes, FALSE)))
GetOverlappedResultEx(hHidFile, &overlapped, &nBytes, FF_IO_TERM_RESP_WAIT_MS, TRUE))
{
if (rdi.hid.dwVendorId == 0x054C)
{
+439
View File
@@ -0,0 +1,439 @@
#pragma once
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#if _WIN32
#include <ntdef.h>
#include <windef.h>
#else
#include <sys/ioctl.h>
#include <uchar.h>
typedef struct _LUID {
uint32_t LowPart;
uint32_t HighPart;
} LUID;
typedef uint32_t UINT;
typedef uint64_t ULONGLONG;
typedef uint64_t UINT64;
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint32_t ULONG;
typedef uint16_t USHORT;
typedef uint8_t UCHAR;
typedef void VOID;
typedef char16_t WCHAR;
typedef void* HANDLE;
typedef uint8_t BYTE;
typedef int32_t BOOL;
typedef uint8_t BOOLEAN;
typedef union {
struct {
uint32_t LowPart;
int32_t HighPart;
} u;
int64_t QuadPart;
} LARGE_INTEGER;
typedef int32_t NTSTATUS; // 0 for success, -1 for failure
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
#define D3DKMT_ALIGN64 __attribute__((aligned(8)))
#define MAX_ENUM_ADAPTERS 16
typedef struct D3DKMT_HANDLE
{
union {
struct {
uint32_t Instance : 6;
uint32_t Index : 24;
uint32_t Unique : 2;
};
uint32_t Value;
};
} D3DKMT_HANDLE;
typedef struct _D3DKMT_OPENADAPTERFROMLUID
{
LUID AdapterLuid;
D3DKMT_HANDLE hAdapter;
} D3DKMT_OPENADAPTERFROMLUID;
typedef struct _D3DKMT_ADAPTERINFO
{
D3DKMT_HANDLE hAdapter;
LUID AdapterLuid;
ULONG NumOfSources;
BOOL bPrecisePresentRegionsPreferred;
} D3DKMT_ADAPTERINFO;
typedef struct _D3DKMT_ENUMADAPTERS2
{
ULONG NumAdapters; // in/out: On input, the count of the pAdapters array buffer. On output, the number of adapters enumerated.
D3DKMT_ADAPTERINFO* pAdapters; // out: Array of enumerated adapters containing NumAdapters elements
} D3DKMT_ENUMADAPTERS2;
static_assert(sizeof(D3DKMT_ENUMADAPTERS2) ==
#if SIZE_MAX == UINT64_MAX
0x10
#else
0x08
#endif
, "D3DKMT_ENUMADAPTERS2 structure size mismatch");
typedef struct _D3DKMT_ADAPTERREGISTRYINFO
{
WCHAR AdapterString[260];
WCHAR BiosString[260];
WCHAR DacType[260];
WCHAR ChipType[260];
} D3DKMT_ADAPTERREGISTRYINFO;
typedef struct _D3DKMT_CLOSEADAPTER
{
D3DKMT_HANDLE hAdapter; // in: adapter handle
} D3DKMT_CLOSEADAPTER;
typedef struct _D3DKMT_SEGMENTSIZEINFO
{
D3DKMT_ALIGN64 ULONGLONG DedicatedVideoMemorySize;
D3DKMT_ALIGN64 ULONGLONG DedicatedSystemMemorySize;
D3DKMT_ALIGN64 ULONGLONG SharedSystemMemorySize;
} D3DKMT_SEGMENTSIZEINFO;
typedef struct _D3DKMT_ADAPTERTYPE
{
union
{
struct
{
UINT RenderSupported : 1; // WDDM 1.2, Windows 8
UINT DisplaySupported : 1;
UINT SoftwareDevice : 1;
UINT PostDevice : 1;
UINT HybridDiscrete : 1; // WDDM 1.3, Windows 8.1
UINT HybridIntegrated : 1;
UINT IndirectDisplayDevice : 1;
UINT Paravirtualized : 1; // WDDM 2.3, Windows 10 Fall Creators Update (version 1709)
UINT ACGSupported : 1;
UINT SupportSetTimingsFromVidPn : 1;
UINT Detachable : 1;
UINT ComputeOnly : 1; // WDDM 2.6, Windows 10 May 2019 Update (Version 1903)
UINT Prototype : 1;
UINT RuntimePowerManagement : 1; // WDDM 2.9, Windows 10 Insider Preview "Iron"
UINT Reserved : 18;
};
UINT Value;
};
} D3DKMT_ADAPTERTYPE;
typedef struct _D3DKMT_ADAPTERADDRESS
{
UINT BusNumber; // Bus number on which the physical device is located.
UINT DeviceNumber; // Index of the physical device on the bus.
UINT FunctionNumber; // Function number of the adapter on the physical device.
} D3DKMT_ADAPTERADDRESS;
typedef struct _D3DKMT_DEVICE_IDS
{
UINT VendorID;
UINT DeviceID;
UINT SubVendorID;
UINT SubSystemID;
UINT RevisionID;
UINT BusType;
} D3DKMT_DEVICE_IDS;
typedef struct _D3DKMT_UMD_DRIVER_VERSION
{
D3DKMT_ALIGN64 LARGE_INTEGER DriverVersion;
} D3DKMT_UMD_DRIVER_VERSION;
typedef struct _D3DKMT_QUERY_DEVICE_IDS
{
UINT PhysicalAdapterIndex; // in:
D3DKMT_DEVICE_IDS DeviceIds; // out:
} D3DKMT_QUERY_DEVICE_IDS;
typedef enum _QAI_DRIVERVERSION
{
KMT_DRIVERVERSION_WDDM_1_0 = 1000, // Windows Vista
KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE = 1102, // Windows Vista with prereleased Win7 features
KMT_DRIVERVERSION_WDDM_1_1 = 1105, // Windows 7
KMT_DRIVERVERSION_WDDM_1_2 = 1200, // Windows 8
KMT_DRIVERVERSION_WDDM_1_3 = 1300, // Windows 8.1
KMT_DRIVERVERSION_WDDM_2_0 = 2000, // Windows 10
KMT_DRIVERVERSION_WDDM_2_1 = 2100, // Windows 10 (1607)
KMT_DRIVERVERSION_WDDM_2_2 = 2200, // Windows 10 (1703)
KMT_DRIVERVERSION_WDDM_2_3 = 2300, // Windows 10 (1709)
KMT_DRIVERVERSION_WDDM_2_4 = 2400, // Windows 10 (1803)
KMT_DRIVERVERSION_WDDM_2_5 = 2500, // Windows 10 (1809)
KMT_DRIVERVERSION_WDDM_2_6 = 2600, // Windows 10 (1903)
KMT_DRIVERVERSION_WDDM_2_7 = 2700, // Windows 10 (2004)
KMT_DRIVERVERSION_WDDM_2_8 = 2800, // Windows 11 Insider Preview Manganese
KMT_DRIVERVERSION_WDDM_2_9 = 2900, // Windows 11 Insider Preview Iron
KMT_DRIVERVERSION_WDDM_3_0 = 3000, // Windows 11 (21H2)
KMT_DRIVERVERSION_WDDM_3_1 = 3100, // Windows 11 (22H2)
KMT_DRIVERVERSION_WDDM_3_2 = 3200, // Windows 11 (24H2)
} D3DKMT_DRIVERVERSION;
typedef struct _D3DKMT_QUERY_ADAPTER_UNIQUE_GUID
{
WCHAR AdapterUniqueGUID[40];
} D3DKMT_QUERY_ADAPTER_UNIQUE_GUID;
typedef enum _KMTQUERYADAPTERINFOTYPE
{
KMTQAITYPE_GETSEGMENTSIZE = 3,
KMTQAITYPE_ADAPTERGUID = 4,
KMTQAITYPE_ADAPTERADDRESS = 6,
KMTQAITYPE_ADAPTERREGISTRYINFO = 8,
KMTQAITYPE_DRIVERVERSION = 13,
KMTQAITYPE_ADAPTERTYPE = 15, // WDDM 1.2, Windows 8
KMTQAITYPE_UMD_DRIVER_VERSION = 18,
KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10
KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31,
KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // WDDM 2.4, Windows 10 (1803)
// This reports the GUID string used by the adapter's registry key (DirectX and Video)
} KMTQUERYADAPTERINFOTYPE;
typedef struct _D3DKMT_QUERYADAPTERINFO
{
D3DKMT_HANDLE hAdapter;
KMTQUERYADAPTERINFOTYPE Type;
VOID* pPrivateDriverData;
UINT PrivateDriverDataSize;
} D3DKMT_QUERYADAPTERINFO;
#define D3DKMT_MAX_SEGMENT_COUNT 32
typedef enum _D3DKMT_MEMORY_SEGMENT_GROUP
{
D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL = 0,
D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL = 1
} D3DKMT_MEMORY_SEGMENT_GROUP;
typedef enum _D3DKMT_QUERYSTATISTICS_TYPE
{
D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER = 10, // WDDM 2.4, Windows 10 April 2018 Update (version 1803)
D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE = 17, // WDDM 3.1, Windows 11 2022 Update (version 22H2)
D3DKMT_QUERYSTATISTICS_NODE2 = 18,
} D3DKMT_QUERYSTATISTICS_TYPE;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER
{
ULONG PhysicalAdapterIndex;
} D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE2
{
UINT16 PhysicalAdapterIndex;
UINT16 NodeOrdinal;
} D3DKMT_QUERYSTATISTICS_QUERY_NODE2;
typedef struct _D3DKMT_ADAPTER_PERFDATA
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG MemoryFrequency; // out: Clock frequency of the memory in hertz
D3DKMT_ALIGN64 ULONGLONG MaxMemoryFrequency; // out: Max memory clock frequency
D3DKMT_ALIGN64 ULONGLONG MaxMemoryFrequencyOC; // out: Clock frequency of the memory while overclocked in hertz.
D3DKMT_ALIGN64 ULONGLONG MemoryBandwidth; // out: Amount of memory transferred in bytes
D3DKMT_ALIGN64 ULONGLONG PCIEBandwidth; // out: Amount of memory transferred over PCI-E in bytes
ULONG FanRPM; // out: Fan rpm
ULONG Power; // out: Power draw of the adapter in tenths of a percentage
ULONG Temperature; // out: Temperature in deci-Celsius 1 = 0.1C
UCHAR PowerStateOverride; // out: Overrides dxgkrnls power view of linked adapters.
} D3DKMT_ADAPTER_PERFDATA;
typedef struct _D3DKMT_ADAPTER_PERFDATACAPS
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG MaxMemoryBandwidth; // out: Max memory bandwidth in bytes for 1 second
D3DKMT_ALIGN64 ULONGLONG MaxPCIEBandwidth; // out: Max pcie bandwidth in bytes for 1 second
ULONG MaxFanRPM; // out: Max fan rpm
ULONG TemperatureMax; // out: Max temperature before damage levels
ULONG TemperatureWarning; // out: The temperature level where throttling begins.
} D3DKMT_ADAPTER_PERFDATACAPS;
#define DXGK_MAX_GPUVERSION_NAME_LENGTH 32
typedef struct _D3DKMT_GPUVERSION
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
WCHAR BiosVersion[DXGK_MAX_GPUVERSION_NAME_LENGTH]; //out: The gpu bios version
WCHAR GpuArchitecture[DXGK_MAX_GPUVERSION_NAME_LENGTH]; //out: The gpu architectures name.
} D3DKMT_GPUVERSION;
typedef struct _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION
{
D3DKMT_ADAPTER_PERFDATA AdapterPerfData;
D3DKMT_ADAPTER_PERFDATACAPS AdapterPerfDataCaps;
D3DKMT_GPUVERSION GpuVersion;
} D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION {
D3DKMT_ALIGN64 UINT64 Reserved[34];
} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION;
typedef struct _D3DKMT_NODE_PERFDATA
{
UINT32 NodeOrdinal; // in: Node ordinal of the requested engine.
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG Frequency; // out: Clock frequency of the engine in hertz
D3DKMT_ALIGN64 ULONGLONG MaxFrequency; // out: Max engine clock frequency
D3DKMT_ALIGN64 ULONGLONG MaxFrequencyOC;// out: Max engine over clock frequency
ULONG Voltage; // out: Voltage of the engine in milli volts mV
ULONG VoltageMax; // out: Max voltage levels in milli volts.
ULONG VoltageMaxOC; // out: Max voltage level while overclocked in milli volts.
// WDDM 2.5
D3DKMT_ALIGN64 ULONGLONG MaxTransitionLatency; // out: Max transition latency to change the frequency in 100 nanoseconds
} D3DKMT_NODE_PERFDATA;
typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION {
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; //Global statistics
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; //Statistics for system thread
D3DKMT_NODE_PERFDATA NodePerfData;
UINT32 Reserved[3];
} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY_USAGE
{
D3DKMT_ALIGN64 UINT64 AllocatedBytes;
D3DKMT_ALIGN64 UINT64 FreeBytes;
D3DKMT_ALIGN64 UINT64 ZeroBytes;
D3DKMT_ALIGN64 UINT64 ModifiedBytes;
D3DKMT_ALIGN64 UINT64 StandbyBytes;
} D3DKMT_QUERYSTATISTICS_MEMORY_USAGE;
typedef union _D3DKMT_QUERYSTATISTICS_RESULT
{
D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation;
D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation;
D3DKMT_QUERYSTATISTICS_MEMORY_USAGE SegmentGroupUsageInformation;
uint8_t Padding[776];
} D3DKMT_QUERYSTATISTICS_RESULT;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT_GROUP_USAGE
{
UINT16 PhysicalAdapterIndex;
UINT16 SegmentGroup; // D3DKMT_MEMORY_SEGMENT_GROUP
} D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT_GROUP_USAGE;
typedef struct _D3DKMT_QUERYSTATISTICS
{
D3DKMT_QUERYSTATISTICS_TYPE Type; // in: type of data requested
LUID AdapterLuid; // in: adapter to get export / statistics from
HANDLE* hProcess; // in: process to get statistics for, if required for this query type
D3DKMT_QUERYSTATISTICS_RESULT QueryResult; // out: requested data
union
{
D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER QueryPhysAdapter; // in: id of physical adapter to get statistics for
D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT_GROUP_USAGE QuerySegmentGroupUsage;
D3DKMT_QUERYSTATISTICS_QUERY_NODE2 QueryNode2; // in: id of node to get statistics for
};
} D3DKMT_QUERYSTATISTICS;
static_assert(sizeof(D3DKMT_QUERYSTATISTICS) ==
#if SIZE_MAX == UINT64_MAX
0x328
#else
0x320
#endif
, "D3DKMT_QUERYSTATISTICS structure size mismatch");
#define DXGK_MAX_METADATA_NAME_LENGTH 32
typedef enum
{
DXGK_ENGINE_TYPE_OTHER,
DXGK_ENGINE_TYPE_3D,
DXGK_ENGINE_TYPE_VIDEO_DECODE,
DXGK_ENGINE_TYPE_VIDEO_ENCODE,
DXGK_ENGINE_TYPE_VIDEO_PROCESSING,
DXGK_ENGINE_TYPE_SCENE_ASSEMBLY,
DXGK_ENGINE_TYPE_COPY,
DXGK_ENGINE_TYPE_OVERLAY,
DXGK_ENGINE_TYPE_CRYPTO,
DXGK_ENGINE_TYPE_VIDEO_CODEC,
DXGK_ENGINE_TYPE_MAX
} DXGK_ENGINE_TYPE;
typedef struct _DXGK_NODEMETADATA_FLAGS
{
union
{
struct
{
UINT ContextSchedulingSupported : 1; // WDDM 2.2
UINT RingBufferFenceRelease : 1; // WDDM 2.5
UINT SupportTrackedWorkload : 1;
UINT UserModeSubmission : 1;
UINT SupportBuildTestCommandBuffer : 1; // WDDM 3.2
UINT Reserved : 11;
UINT MaxInFlightHwQueueBuffers : 16;
};
UINT32 Value;
};
} DXGK_NODEMETADATA_FLAGS;
typedef struct _DXGK_NODEMETADATA
{
DXGK_ENGINE_TYPE EngineType;
WCHAR FriendlyName[DXGK_MAX_METADATA_NAME_LENGTH];
DXGK_NODEMETADATA_FLAGS Flags; // WDDM 2.2
BOOLEAN GpuMmuSupported; // WDDM 2.0 ???
BOOLEAN IoMmuSupported;
} __attribute__((packed)) DXGK_NODEMETADATA;
typedef struct _D3DKMT_NODEMETADATA
{
UINT NodeOrdinalAndAdapterIndex; // WDDMv2: High word is physical adapter index, low word is node ordinal
DXGK_NODEMETADATA NodeData;
} __attribute__((packed)) D3DKMT_NODEMETADATA;
static_assert(sizeof(D3DKMT_NODEMETADATA) == 0x4E, "D3DKMT_NODEMETADATA structure size mismatch");
// Functions
#if _WIN32
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTOpenAdapterFromLuid(_Inout_ CONST D3DKMT_OPENADAPTERFROMLUID*);
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryAdapterInfo(_Inout_ CONST D3DKMT_QUERYADAPTERINFO*);
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTCloseAdapter(_In_ CONST D3DKMT_CLOSEADAPTER*);
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTEnumAdapters2(_Inout_ D3DKMT_ENUMADAPTERS2*);
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryStatistics(_In_ CONST D3DKMT_QUERYSTATISTICS*);
#else
// Ref: https://github.com/microsoft/WSL2-Linux-Kernel/blob/linux-msft-wsl-6.6.y/include/uapi/misc/d3dkmthk.h
#define LX_DXOPENADAPTERFROMLUID _IOWR(0x47, 0x01, D3DKMT_OPENADAPTERFROMLUID)
#define LX_DXQUERYADAPTERINFO _IOWR(0x47, 0x09, D3DKMT_QUERYADAPTERINFO)
#define LX_DXENUMADAPTERS2 _IOWR(0x47, 0x14, D3DKMT_ENUMADAPTERS2)
#define LX_DXCLOSEADAPTER _IOWR(0x47, 0x15, D3DKMT_CLOSEADAPTER)
#define LX_DXQUERYSTATISTICS _IOWR(0x47, 0x43, D3DKMT_QUERYSTATISTICS)
static inline NTSTATUS D3DKMTOpenAdapterFromLuid(int dxgfd, const D3DKMT_OPENADAPTERFROMLUID* params)
{
return ioctl(dxgfd, LX_DXOPENADAPTERFROMLUID, params);
}
static inline NTSTATUS D3DKMTQueryAdapterInfo(int dxgfd, const D3DKMT_QUERYADAPTERINFO* params)
{
return ioctl(dxgfd, LX_DXQUERYADAPTERINFO, params);
}
static inline NTSTATUS D3DKMTCloseAdapter(int dxgfd, const D3DKMT_CLOSEADAPTER* params)
{
return ioctl(dxgfd, LX_DXCLOSEADAPTER, params);
}
static inline NTSTATUS D3DKMTEnumAdapters2(int dxgfd, D3DKMT_ENUMADAPTERS2* params)
{
return ioctl(dxgfd, LX_DXENUMADAPTERS2, params);
}
static inline NTSTATUS D3DKMTQueryStatistics(int dxgfd, const D3DKMT_QUERYSTATISTICS* params)
{
return ioctl(dxgfd, LX_DXQUERYSTATISTICS, params);
}
#endif
+4 -4
View File
@@ -656,10 +656,10 @@ static const char* pciDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
#ifdef FF_HAVE_DIRECTX_HEADERS
const char* ffGPUDetectByDirectX(const FFGPUOptions* options, FFlist* gpus);
if (ffGPUDetectByDirectX(options, gpus) == NULL)
return NULL;
#if __x86_64__ || __aarch64__
const char* ffGPUDetectWsl2(const FFGPUOptions* options, FFlist* gpus);
if (ffGPUDetectWsl2(options, gpus) == NULL)
return NULL;
#endif
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
+8 -8
View File
@@ -8,7 +8,7 @@
#include <dev/pci/pcidevs.h>
#include <sys/pciio.h>
static inline int pciReadConf(int fd, uint32_t bus, uint32_t device, uint32_t func, uint32_t reg, uint32_t* result)
static inline int pciReadConf(int fd, uint8_t bus, uint8_t device, uint8_t func, uint8_t reg, uint32_t* result)
{
struct pci_io bdfr = {
.pi_sel = {
@@ -34,21 +34,21 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (pcifd < 0)
return "open(\"/dev/pci0\", O_RDONLY | O_CLOEXEC) failed";
for (uint32_t bus = 0; bus <= 255; bus++)
for (uint16_t bus = 0; bus <= 255; bus++)
{
for (uint32_t dev = 0; dev < 32; dev++)
for (uint8_t dev = 0; dev < 32; dev++)
{
uint32_t maxfuncs = 0;
for (uint32_t func = 0; func <= maxfuncs; func++)
uint8_t maxfuncs = 0;
for (uint8_t func = 0; func <= maxfuncs; func++)
{
uint32_t pciid, pciclass;
if (pciReadConf(pcifd, bus, dev, func, PCI_ID_REG, &pciid) != 0)
if (pciReadConf(pcifd, (uint8_t) bus, dev, func, PCI_ID_REG, &pciid) != 0)
continue;
if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID || PCI_VENDOR(pciid) == 0)
continue;
if (pciReadConf(pcifd, bus, dev, func, PCI_CLASS_REG, &pciclass) != 0)
if (pciReadConf(pcifd, (uint8_t) bus, dev, func, PCI_CLASS_REG, &pciclass) != 0)
continue;
if (func == 0)
@@ -56,7 +56,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
// For some reason, pciReadConf returns success even for non-existing devices.
// So we need to check for `PCI_VENDOR(pciid) == PCI_VENDOR_INVALID` above to filter them out.
uint32_t bhlcr;
if (pciReadConf(pcifd, bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0)
if (pciReadConf(pcifd, (uint8_t) bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0)
continue;
if (PCI_HDRTYPE_MULTIFN(bhlcr)) maxfuncs = 7;
+165 -123
View File
@@ -1,13 +1,14 @@
#include "gpu.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "common/library.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/mallocHelper.h"
#include "common/debug.h"
#include "common/windows/nt.h"
#include <windows.h>
#include <cfgmgr32.h>
#include "d3dkmthk.h"
#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}"
enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 };
@@ -19,6 +20,13 @@ const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\C
#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
static inline void wrapRegCloseKey(HKEY* phKey)
{
if(*phKey)
RegCloseKey(*phKey);
}
#define FF_HKEY_AUTO_DESTROY __attribute__((__cleanup__(wrapRegCloseKey)))
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
FF_DEBUG("Starting GPU detection");
@@ -115,7 +123,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
uint64_t adapterLuid = 0;
FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL;
FF_HKEY_AUTO_DESTROY HKEY hVideoIdKey = NULL;
wchar_t buffer[256];
ULONG bufferLen = 0;
@@ -147,7 +155,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
{
FF_DEBUG("Found VideoID: %ls", buffer);
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
FF_AUTO_CLOSE_FD HANDLE hDirectxKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
{
FF_DEBUG("Opened DirectX registry key");
@@ -237,7 +245,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
{
FF_DEBUG("Found driver GUID: %ls", buffer);
wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000"));
FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL;
FF_AUTO_CLOSE_FD HANDLE hRegDriverKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL))
{
FF_DEBUG("Opened driver registry key");
@@ -290,7 +298,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName))
{
FF_DEBUG("Calling driver-specific detection function for vendor: %s, DLL: %s", gpu->vendor.chars, dllName);
detectFn(
FF_MAYBE_UNUSED const char* error = detectFn(
&(FFGpuDriverCondition) {
.type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0)
| (adapterLuid > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0)
@@ -323,7 +331,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
},
dllName
);
FF_DEBUG("Driver-specific detection completed");
FF_DEBUG("Driver-specific detection completed: %s", error ?: "Success");
}
else if (options->driverSpecific)
{
@@ -333,145 +341,179 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0)
{
FF_DEBUG("Trying to determine GPU type using D3DKMT APIs");
#if !FF_WIN7_COMPAT
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
if (NT_SUCCESS(D3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
#else
HMODULE hgdi32 = GetModuleHandleW(L"gdi32.dll");
if (hgdi32)
{
FF_LIBRARY_LOAD_SYMBOL_LAZY(hgdi32, D3DKMTOpenAdapterFromLuid);
if (ffD3DKMTOpenAdapterFromLuid) // Windows 8 and later
FF_DEBUG("Successfully opened adapter from LUID");
D3DKMT_ADAPTERTYPE adapterType = {};
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_ADAPTERTYPE, // Windows 8 and later
.pPrivateDriverData = &adapterType,
.PrivateDriverDataSize = sizeof(adapterType),
};
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo)))
{
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
if (NT_SUCCESS(ffD3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
#endif
{
FF_DEBUG("Successfully opened adapter from LUID");
D3DKMT_ADAPTERTYPE adapterType = {};
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_ADAPTERTYPE, // Windows 8 and later
.pPrivateDriverData = &adapterType,
.PrivateDriverDataSize = sizeof(adapterType),
};
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo)))
{
FF_DEBUG("Queried adapter type - HybridDiscrete: %d, HybridIntegrated: %d", adapterType.HybridDiscrete, adapterType.HybridIntegrated);
if (adapterType.HybridDiscrete)
gpu->type = FF_GPU_TYPE_DISCRETE;
else if (adapterType.HybridIntegrated)
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
else
{
FF_DEBUG("Failed to query adapter type");
}
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET && ffIsWindows11OrGreater())
{
FF_DEBUG("Trying to get GPU frequency information");
for (ULONG nodeIdx = 0; ; nodeIdx++)
{
D3DKMT_NODEMETADATA nodeMetadata = {
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
};
queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_NODEMETADATA, // Windows 10 and later
.pPrivateDriverData = &nodeMetadata,
.PrivateDriverDataSize = sizeof(nodeMetadata),
};
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo)))
{
FF_DEBUG("No more nodes to query (index %lu)", nodeIdx);
break;
}
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D)
{
FF_DEBUG("Skipping node %lu (not 3D engine)", nodeIdx);
continue;
}
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_NODE2, // Windows 11 (22H2) and later
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)))
{
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
FF_DEBUG("Found GPU frequency: %u MHz", gpu->frequency);
break;
}
else
{
FF_DEBUG("Failed to query node statistics for node %lu", nodeIdx);
}
}
}
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
(void) D3DKMTCloseAdapter(&closeAdapter);
openAdapterFromLuid.hAdapter = 0;
FF_DEBUG("Closed adapter handle");
}
else
{
FF_DEBUG("Failed to open adapter from LUID");
}
if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET && ffIsWindows10OrGreater())
{
FF_DEBUG("Trying to get GPU temperature");
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER, // Windows 10 (1803) and later
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
{
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
FF_DEBUG("Found GPU temperature: %.1f°C", gpu->temperature);
}
else
{
FF_DEBUG("Failed to get GPU temperature or temperature is 0");
}
}
#if FF_WIN7_COMPAT
FF_DEBUG("Queried adapter type - HybridDiscrete: %d, HybridIntegrated: %d", adapterType.HybridDiscrete, adapterType.HybridIntegrated);
if (adapterType.HybridDiscrete)
gpu->type = FF_GPU_TYPE_DISCRETE;
else if (adapterType.HybridIntegrated)
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
else
{
FF_DEBUG("D3DKMTOpenAdapterFromLuid not available");
FF_DEBUG("Failed to query adapter type");
}
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET && ffIsWindows11OrGreater())
{
FF_DEBUG("Trying to get GPU frequency information");
for (ULONG nodeIdx = 0; ; nodeIdx++)
{
D3DKMT_NODEMETADATA nodeMetadata = {
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
};
queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_NODEMETADATA, // Windows 10 and later
.pPrivateDriverData = &nodeMetadata,
.PrivateDriverDataSize = sizeof(nodeMetadata),
};
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo)))
{
FF_DEBUG("No more nodes to query (index %lu)", nodeIdx);
break;
}
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D)
{
FF_DEBUG("Skipping node %lu (not 3D engine)", nodeIdx);
continue;
}
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_NODE2, // Windows 11 (22H2) and later
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)))
{
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
FF_DEBUG("Found GPU frequency: %u MHz", gpu->frequency);
break;
}
else
{
FF_DEBUG("Failed to query node statistics for node %lu", nodeIdx);
}
}
}
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
(void) D3DKMTCloseAdapter(&closeAdapter);
openAdapterFromLuid.hAdapter = (D3DKMT_HANDLE) {};
FF_DEBUG("Closed adapter handle");
}
else
{
FF_DEBUG("Failed to get gdi32.dll module handle");
FF_DEBUG("Failed to open adapter from LUID");
}
if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET && ffIsWindows10OrGreater())
{
FF_DEBUG("Trying to get GPU temperature");
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER, // Windows 10 (1803) and later
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
{
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
FF_DEBUG("Found GPU temperature: %.1f°C", gpu->temperature);
}
else
{
FF_DEBUG("Failed to get GPU temperature or temperature is 0");
}
}
if (options->driverSpecific && gpu->dedicated.used == FF_GPU_VMEM_SIZE_UNSET && ffIsWindows11OrGreater())
{
FF_DEBUG("Trying to get used video memory from D3DKMT method");
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE,
.AdapterLuid = *(LUID*)&adapterLuid,
.QuerySegmentGroupUsage = {
.PhysicalAdapterIndex = 0,
.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL,
},
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)))
{
D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation;
uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes;
uint64_t total = used + info->FreeBytes + info->ZeroBytes;
gpu->dedicated.used = used;
gpu->dedicated.total = total;
FF_DEBUG("Found local memory size %llu / %llu", used, total);
}
else
{
FF_DEBUG("Failed to query segment group usage for local memory");
}
queryStatistics.QuerySegmentGroupUsage.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL;
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)))
{
D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation;
uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes;
uint64_t total = used + info->FreeBytes + info->ZeroBytes;
gpu->shared.used = used;
gpu->shared.total = total;
FF_DEBUG("Found non-local memory size %llu / %llu", used, total);
}
else
{
FF_DEBUG("Failed to query segment group usage for non-local memory");
}
}
#endif
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
FF_DEBUG("Using fallback GPU type detection");
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
FF_DEBUG("Intel GPU type determined: %s", gpu->type == FF_GPU_TYPE_INTEGRATED ? "Integrated" : "Discrete");
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
gpu->type = gpu->dedicated.total >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
FF_DEBUG("GPU type determined by memory size (%llu bytes): %s", gpu->dedicated.total, gpu->type == FF_GPU_TYPE_DISCRETE ? "Discrete" : "Integrated");
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
if (gpu->type != FF_GPU_TYPE_UNKNOWN)
FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type);
else if (ffIsWindows10OrGreater())
{
const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult* gpu);
FF_MAYBE_UNUSED const char* error = ffGPUDetectTypeWithDXCore(*(LUID*)&adapterLuid, gpu);
FF_DEBUG("DXCore GPU type detection result: %s", error ?: "Success");
}
else
{
FF_DEBUG("Unable to determine GPU type");
}
FF_DEBUG("Unable to determine GPU type by any method for this adapter");
}
FF_DEBUG("Completed processing GPU #%d - Vendor: %s, Name: %s, Type: %d", deviceCount, gpu->vendor.chars, gpu->name.chars, gpu->type);
+88
View File
@@ -0,0 +1,88 @@
extern "C"
{
#include "gpu.h"
#include "common/library.h"
#include "common/debug.h"
}
#if __has_include(<directx/dxcore.h>) && __has_include(<dxguids/dxguids.h>)
#include <directx/dxcore.h>
#include <dxguids/dxguids.h>
#include "common/windows/util.hpp"
static IDXCoreAdapterFactory* loadDxCoreFactory()
{
static bool initialized = false;
static IDXCoreAdapterFactory* factory = nullptr;
if (initialized)
return factory; // Already loaded
initialized = true;
FF_LIBRARY_LOAD(dxcore, NULL, "dxcore" FF_LIBRARY_EXTENSION, 1)
// DXCoreCreateAdapterFactory is a reloaded function, so we can't use FF_LIBRARY_LOAD_SYMBOL_MESSAGE here
typedef HRESULT (*DXCoreCreateAdapterFactory_t)(REFIID riid, void** ppvFactory);
#ifndef FF_DISABLE_DLOPEN
auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) dlsym(dxcore, "DXCoreCreateAdapterFactory");
if (ffDXCoreCreateAdapterFactory == nullptr) return NULL;
#else
auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) DXCoreCreateAdapterFactory;
#endif
HRESULT hr = ffDXCoreCreateAdapterFactory(IID_PPV_ARGS(&factory));
if (FAILED(hr))
{
FF_DEBUG("DXCoreCreateAdapterFactory failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
return NULL;
}
dxcore = NULL; // Don't unload
return factory;
}
extern "C"
const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult* gpu)
{
auto* factory = loadDxCoreFactory();
if (!factory)
return "Failed to load DXCore library or create adapter factory";
IDXCoreAdapter *adapter = nullptr;
HRESULT hr = factory->GetAdapterByLuid(adapterLuid, IID_PPV_ARGS(&adapter));
if (FAILED(hr))
{
FF_DEBUG("GetAdapterByLuid failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
return "Failed to get adapter by LUID";
}
on_scope_exit releaseAdapter {[adapter] { adapter->Release(); }};
bool isIntegrated = false;
hr = adapter->GetProperty(DXCoreAdapterProperty::IsIntegrated, sizeof(isIntegrated), &isIntegrated);
if (FAILED(hr))
{
FF_DEBUG("GetProperty(IsIntegrated) failed with HRESULT: 0x%08lX (%s)", hr, ffDebugHResult(hr));
return "Failed to get adapter properties";
}
gpu->type = isIntegrated ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
FF_DEBUG("GPU type determined using DXCore: %s", isIntegrated ? "Integrated" : "Discrete");
return nullptr;
}
#else
#warning "DXCore headers not available, GPU type detection may be less accurate"
extern "C"
const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult* gpu)
{
FF_UNUSED(adapterLuid, gpu);
FF_DEBUG("DXCore not available, skipping GPU type detection with DXCore");
return "DXCore not available";
}
#endif
+377
View File
@@ -0,0 +1,377 @@
#if __x86_64__ || __aarch64__ // WSL2 only supports x86_64 and aarch64
#include "detection/gpu/gpu.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "common/io.h"
#include "common/debug.h"
#include "d3dkmthk.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <uchar.h>
static void ffStrbufAppendUtf16(FFstrbuf* strbuf, const char16_t* str)
{
mbstate_t state = {};
while (*str)
{
char buf[5];
size_t len = c16rtomb(buf, *str, &state);
if (len == (size_t) -1)
ffStrbufAppendS(strbuf, ""); // U+FFFD REPLACEMENT CHARACTER
else if (len > 0)
ffStrbufAppendNS(strbuf, (uint32_t) len, buf);
str++;
}
}
const char* ffGPUDetectWsl2(const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int dxg = open("/dev/dxg", O_RDWR); // Windows DXCore/D3DKMT adapter driver for WSL
if (dxg < 0)
{
if (errno == ENOENT)
{
FF_DEBUG("/dev/dxg is not available, WSL DXCore GPU driver not detected");
return "No DXCore GPU driver detected (no /dev/dxg)";
}
else
{
FF_DEBUG("Failed to open /dev/dxg: %s", strerror(errno));
return "Failed to open /dev/dxg";
}
}
FF_DEBUG("Opened /dev/dxg successfully");
D3DKMT_ADAPTERINFO adapters[64];
D3DKMT_ENUMADAPTERS2 enumAdapters = {
.NumAdapters = ARRAY_SIZE(adapters),
.pAdapters = adapters,
};
if (!NT_SUCCESS(D3DKMTEnumAdapters2(dxg, &enumAdapters)))
{
FF_DEBUG("D3DKMTEnumAdapters2 failed: %s", strerror(errno));
return "Failed to enumerate adapters with D3DKMTEnumAdapters2";
}
FF_DEBUG("D3DKMTEnumAdapters2 succeeded, adapter count: %u", enumAdapters.NumAdapters);
for (uint32_t i = 0; i < enumAdapters.NumAdapters; i++)
{
const D3DKMT_ADAPTERINFO* adapter = &adapters[i];
FF_DEBUG("Processing adapter #%u", i);
D3DKMT_ADAPTERTYPE adapterType;
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_ADAPTERTYPE,
.pPrivateDriverData = &adapterType,
.PrivateDriverDataSize = sizeof(adapterType),
})))
{
FF_DEBUG("KMTQAITYPE_ADAPTERTYPE query failed for adapter #%u: %s", i, strerror(errno));
continue;
}
if (adapterType.SoftwareDevice)
{
FF_DEBUG("Skipping software adapter #%u", i);
continue;
}
FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->type = adapterType.HybridIntegrated
? FF_GPU_TYPE_INTEGRATED
: adapterType.HybridDiscrete
? FF_GPU_TYPE_DISCRETE
: FF_GPU_TYPE_UNKNOWN;
const char* vendorStr = NULL;
D3DKMT_QUERY_DEVICE_IDS deviceIds = { .PhysicalAdapterIndex = 0 };
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_PHYSICALADAPTERDEVICEIDS,
.pPrivateDriverData = &deviceIds,
.PrivateDriverDataSize = sizeof(deviceIds),
})))
{
vendorStr = ffGPUGetVendorString(deviceIds.DeviceIds.VendorID);
ffStrbufSetStatic(&gpu->vendor, vendorStr);
FF_DEBUG("Adapter #%u vendor/device IDs: vendor=0x%04x device=0x%04x", i, deviceIds.DeviceIds.VendorID, deviceIds.DeviceIds.DeviceID);
}
else
FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, strerror(errno));
D3DKMT_ADAPTERADDRESS adapterAddress;
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_ADAPTERADDRESS,
.pPrivateDriverData = &adapterAddress,
.PrivateDriverDataSize = sizeof(adapterAddress),
})))
{
gpu->deviceId = ffGPUPciAddr2Id(0, adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber);
FF_DEBUG("Adapter #%u PCI address: bus=%u device=%u function=%u", i, adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber);
}
else
{
adapterAddress.BusNumber = -1u;
gpu->deviceId = ffGPUGeneral2Id(((uint64_t)adapter->AdapterLuid.HighPart << 32) | (uint64_t)adapter->AdapterLuid.LowPart);
FF_DEBUG("KMTQAITYPE_ADAPTERADDRESS query failed for adapter #%u, fallback to LUID-based deviceId: %s", i, strerror(errno));
}
D3DKMT_UMD_DRIVER_VERSION umdDriverVersion;
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_UMD_DRIVER_VERSION,
.pPrivateDriverData = &umdDriverVersion,
.PrivateDriverDataSize = sizeof(umdDriverVersion),
})))
{
ffStrbufSetF(&gpu->driver, "%lu.%lu.%lu.%lu",
umdDriverVersion.DriverVersion.QuadPart >> 48ul & 0xFFFF,
umdDriverVersion.DriverVersion.QuadPart >> 32ul & 0xFFFF,
umdDriverVersion.DriverVersion.QuadPart >> 16ul & 0xFFFF,
umdDriverVersion.DriverVersion.QuadPart >> 0ul & 0xFFFF);
FF_DEBUG("Adapter #%u UMD driver version: %08lX", i, (unsigned long) umdDriverVersion.DriverVersion.QuadPart);
}
else
{
FF_DEBUG("KMTQAITYPE_UMD_DRIVER_VERSION query failed for adapter #%u: %s", i, strerror(errno));
}
D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_3_0;
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_DRIVERVERSION,
.pPrivateDriverData = &wddmVersion,
.PrivateDriverDataSize = sizeof(wddmVersion),
})))
{
ffStrbufSetF(&gpu->platformApi, "WDDM %u.%u", wddmVersion / 1000, (wddmVersion % 1000) / 100);
FF_DEBUG("Adapter #%u WDDM version: %u", i, wddmVersion);
}
else
{
ffStrbufSetStatic(&gpu->platformApi, "WDDM");
FF_DEBUG("KMTQAITYPE_DRIVERVERSION query failed for adapter #%u", i);
}
if (gpu->name.length == 0)
{
D3DKMT_ADAPTERREGISTRYINFO registryInfo;
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_ADAPTERREGISTRYINFO,
.pPrivateDriverData = &registryInfo,
.PrivateDriverDataSize = sizeof(registryInfo),
})))
{
ffStrbufAppendUtf16(&gpu->name, registryInfo.AdapterString);
FF_DEBUG("Adapter #%u adapter string: %s", i, gpu->name.chars);
}
else
FF_DEBUG("KMTQAITYPE_ADAPTERREGISTRYINFO query failed for adapter #%u: %s", i, strerror(errno));
}
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && options->driverSpecific)
{
FF_DEBUG("Trying NVIDIA driver-specific detection for adapter #%u", i);
FFGpuDriverCondition cond = {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID | (adapterAddress.DeviceNumber != -1u ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0),
.pciDeviceId = {
.deviceId = deviceIds.DeviceIds.DeviceID,
.vendorId = deviceIds.DeviceIds.VendorID,
.subSystemId = deviceIds.DeviceIds.SubSystemID,
.revId = deviceIds.DeviceIds.RevisionID,
},
.pciBusId = {
.domain = 0,
.bus = adapterAddress.BusNumber,
.device = adapterAddress.DeviceNumber,
.func = adapterAddress.FunctionNumber,
},
};
const char* error = ffDetectNvidiaGpuInfo(&cond, (FFGpuDriverResult){
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
}, "/usr/lib/wsl/lib/libnvidia-ml.so");
if (error)
FF_DEBUG("NVIDIA driver-specific detection failed for adapter #%u: %s", i, error);
else
FF_DEBUG("NVIDIA driver-specific detection succeeded for adapter #%u", i);
}
if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET && gpu->shared.total == FF_GPU_VMEM_SIZE_UNSET)
{
if (wddmVersion >= KMT_DRIVERVERSION_WDDM_3_1 && options->driverSpecific)
{
// Supports memory usage query; requires Windows 11 (22H2) or later
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE,
.AdapterLuid = adapter->AdapterLuid,
.QuerySegmentGroupUsage = {
.PhysicalAdapterIndex = 0,
.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL,
},
};
if (NT_SUCCESS(D3DKMTQueryStatistics(dxg, &queryStatistics)))
{
D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation;
uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes;
uint64_t total = used + info->FreeBytes + info->ZeroBytes;
gpu->dedicated.used = used;
gpu->dedicated.total = total;
FF_DEBUG("Adapter #%u local memory usage: used=%lu total=%lu", i, (unsigned long) used, (unsigned long) total);
}
else
FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (LOCAL) failed for adapter #%u: %s", i, strerror(errno));
queryStatistics.QuerySegmentGroupUsage.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL;
if (NT_SUCCESS(D3DKMTQueryStatistics(dxg, &queryStatistics)))
{
D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation;
uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes;
uint64_t total = used + info->FreeBytes + info->ZeroBytes;
gpu->shared.used = used;
gpu->shared.total = total;
FF_DEBUG("Adapter #%u non-local memory usage: used=%lu total=%lu", i, (unsigned long) used, (unsigned long) total);
}
else
FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (NON_LOCAL) failed for adapter #%u: %s", i, strerror(errno));
}
else
{
// Supports basic segment (total) size query
D3DKMT_SEGMENTSIZEINFO segmentSizeInfo = {};
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_GETSEGMENTSIZE,
.pPrivateDriverData = &segmentSizeInfo,
.PrivateDriverDataSize = sizeof(segmentSizeInfo),
};
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &queryAdapterInfo)))
{
FF_DEBUG("Adapter #%u segment size - DedicatedVideoMemorySize: %lu, DedicatedSystemMemorySize: %lu, SharedSystemMemorySize: %lu",
i, segmentSizeInfo.DedicatedVideoMemorySize, segmentSizeInfo.DedicatedSystemMemorySize, segmentSizeInfo.SharedSystemMemorySize);
gpu->dedicated.total = segmentSizeInfo.DedicatedVideoMemorySize;
gpu->shared.total = segmentSizeInfo.DedicatedSystemMemorySize + segmentSizeInfo.SharedSystemMemorySize;
}
else
{
FF_DEBUG("Failed to query segment size information for adapter #%u: %s", i, strerror(errno));
}
}
}
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET && wddmVersion >= KMT_DRIVERVERSION_WDDM_3_1)
{
for (ULONG nodeIdx = 0; ; nodeIdx++)
{
D3DKMT_NODEMETADATA nodeMetadata = {
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
};
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(dxg, &(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
.Type = KMTQAITYPE_NODEMETADATA,
.pPrivateDriverData = &nodeMetadata,
.PrivateDriverDataSize = sizeof(nodeMetadata),
})))
break;
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D)
continue;
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_NODE2,
.AdapterLuid = adapter->AdapterLuid,
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(dxg, &queryStatistics)))
{
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
FF_DEBUG("Adapter #%u max graphics frequency: %u MHz", i, gpu->frequency);
break;
}
else
FF_DEBUG("Failed to query node performance data for adapter #%u node #%u: %s", i, nodeIdx, strerror(errno));
}
}
if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET)
{
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER,
.AdapterLuid = adapter->AdapterLuid,
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(dxg, &queryStatistics)) &&
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
{
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
FF_DEBUG("Adapter #%u temperature: %.1f°C", i, gpu->temperature);
}
else
FF_DEBUG("Failed to query temperature for adapter #%u: %s", i, strerror(errno));
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
FF_DEBUG("Adapter #%u summary: name='%s', vendor='%s', type=%u, deviceId=%lu",
i,
gpu->name.length ? gpu->name.chars : "unknown",
gpu->vendor.length ? gpu->vendor.chars : "unknown",
(unsigned) gpu->type,
(unsigned long) gpu->deviceId);
if (NT_SUCCESS(D3DKMTCloseAdapter(dxg, &(D3DKMT_CLOSEADAPTER) {
.hAdapter = adapter->hAdapter
})))
FF_DEBUG("Closed adapter #%u successfully", i);
else
FF_DEBUG("Failed to close adapter #%u: %s", i, strerror(errno));
}
return NULL;
}
#endif
-138
View File
@@ -1,138 +0,0 @@
#ifdef FF_HAVE_DIRECTX_HEADERS
#define INITGUID
extern "C" {
#include "common/library.h"
#include "detection/gpu/gpu.h"
#include "detection/gpu/gpu_driver_specific.h"
}
#include "common/windows/util.hpp"
#include <wsl/winadapter.h>
#include <directx/dxcore.h>
#include <directx/d3d12.h>
#include <dxguids/dxguids.h>
#include <utility>
#include <cinttypes>
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
extern "C"
const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
FF_LIBRARY_LOAD_MESSAGE(libdxcore, "/usr/lib/wsl/lib/libdxcore" FF_LIBRARY_EXTENSION, 4)
// DXCoreCreateAdapterFactory is a reloaded function, so we can't use FF_LIBRARY_LOAD_SYMBOL_MESSAGE here
typedef HRESULT (*DXCoreCreateAdapterFactory_t)(REFIID riid, void** ppvFactory);
#ifndef FF_DISABLE_DLOPEN
auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) dlsym(libdxcore, "DXCoreCreateAdapterFactory");
if(ffDXCoreCreateAdapterFactory == nullptr) return "dlsym DXCoreCreateAdapterFactory failed";
#else
auto ffDXCoreCreateAdapterFactory = (DXCoreCreateAdapterFactory_t) DXCoreCreateAdapterFactory;
#endif
IDXCoreAdapterFactory *factory = nullptr;
if (FAILED(ffDXCoreCreateAdapterFactory(IID_PPV_ARGS(&factory))))
return "DXCoreCreateAdapterFactory(IID_PPV_ARGS(&factory)) failed";
on_scope_exit destroyFactory([&] { factory->Release(); });
IDXCoreAdapterList *list = NULL;
if (FAILED(factory->CreateAdapterList(1, &DXCORE_ADAPTER_ATTRIBUTE_D3D11_GRAPHICS, &list)))
return "factory->CreateAdapterList(1, &DXCORE_ADAPTER_ATTRIBUTE_D3D11_GRAPHICS, &list) failed";
on_scope_exit destroyList([&] { list->Release(); });
for (uint32_t i = 0, count = list->GetAdapterCount(); i < count; i++)
{
IDXCoreAdapter *adapter = nullptr;
if (FAILED(list->GetAdapter(i, &adapter)))
continue;
on_scope_exit destroyAdapter([&] { adapter->Release(); });
// https://learn.microsoft.com/en-us/windows/win32/api/dxcore_interface/ne-dxcore_interface-dxcoreadapterproperty
{
bool value = 0;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::IsHardware, sizeof(value), &value)) && !value)
continue;
}
char desc[256];
if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::DriverDescription, sizeof(desc), desc)))
continue;
FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus);
ffStrbufInitS(&gpu->name, desc);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->deviceId = 0;
ffStrbufInitStatic(&gpu->platformApi, "DXCore");
LUID luid;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::InstanceLuid, sizeof(luid), &luid)))
{
static_assert(sizeof(luid) == sizeof(uint64_t), "LUID size mismatch");
gpu->deviceId = ffGPUGeneral2Id((uint64_t) luid.HighPart << 32 | (uint64_t) luid.LowPart);
}
ffStrbufInit(&gpu->driver);
uint64_t value = 0;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::DriverVersion, sizeof(value), &value)))
{
ffStrbufSetF(&gpu->driver, "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".%" PRIu64,
(value >> 48) & 0xFFFF,
(value >> 32) & 0xFFFF,
(value >> 16) & 0xFFFF,
(value >> 0) & 0xFFFF);
}
gpu->dedicated.used = gpu->shared.used = gpu->dedicated.total = gpu->shared.total = FF_GPU_VMEM_SIZE_UNSET;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::DedicatedAdapterMemory, sizeof(value), &value)))
gpu->dedicated.total = value;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::SharedSystemMemory, sizeof(value), &value)))
gpu->shared.total = value;
gpu->type = FF_GPU_TYPE_UNKNOWN;
bool integrated;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::IsIntegrated, sizeof(integrated), &integrated)))
gpu->type = integrated ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
ffStrbufInit(&gpu->vendor);
DXCoreHardwareID hardwareId;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::HardwareID, sizeof(hardwareId), &hardwareId)))
{
const char* vendorStr = ffGPUGetVendorString((unsigned) hardwareId.vendorID);
ffStrbufSetStatic(&gpu->vendor, vendorStr);
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp))
{
FFGpuDriverCondition cond = {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID,
.pciDeviceId = {
.deviceId = hardwareId.deviceID,
.vendorId = hardwareId.vendorID,
.subSystemId = hardwareId.subSysID,
.revId = hardwareId.revision,
},
};
ffDetectNvidiaGpuInfo(&cond, (FFGpuDriverResult){
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = options->driverSpecific ? &gpu->name : NULL,
}, "/usr/lib/wsl/lib/libnvidia-ml.so");
}
}
}
return NULL;
}
#endif
+46 -28
View File
@@ -5,18 +5,13 @@
#include <stdlib.h>
static void getHostProductName(FFstrbuf* name)
static bool getHostProductName(FFstrbuf* name)
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/model", name))
if (ffReadFileBuffer("/sys/firmware/devicetree/base/model", name) ||
ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name))
{
ffStrbufTrimRight(name, '\0');
return;
}
if (ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name))
{
ffStrbufTrimRight(name, '\0');
return;
return true;
}
if (ffReadFileBuffer("/tmp/sysinfo/model", name))
@@ -24,38 +19,61 @@ static void getHostProductName(FFstrbuf* name)
ffStrbufTrimRightSpace(name);
ffStrbufTrimRight(name, '\0');
if(ffIsSmbiosValueSet(name))
return;
return true;
}
ffStrbufClear(name);
return false;
}
static void getHostSerialNumber(FFstrbuf* serial)
static bool getHostSerialNumber(FFstrbuf* serial)
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/serial", serial))
ffStrbufTrimRight(serial, '\0');
else if (ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial))
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/serial", serial) ||
ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial))
{
ffStrbufTrimRight(serial, '\0');
return true;
}
return false;
}
static bool getHostProductFamily(FFstrbuf* family)
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/family", family) ||
ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/product", family))
{
ffStrbufTrimRight(family, '\0');
return true;
}
return false;
}
static bool getHostVendor(FFstrbuf* vendor)
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/manufacturer", vendor))
{
ffStrbufTrimRight(vendor, '\0');
return true;
}
return false;
}
const char* ffDetectHost(FFHostResult* host)
{
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family))
// This is a hack for Asahi Linux, whose product_family is empty
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family))
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/product", &host->family))
ffStrbufTrimRight(&host->family, '\0');
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->sku);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor);
}
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name))
getHostProductName(&host->name);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->sku);
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial))
getHostSerialNumber(&host->serial);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->uuid);
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor))
else
{
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/manufacturer", &host->vendor))
ffStrbufTrimRight(&host->vendor, '\0');
getHostProductFamily(&host->family);
getHostProductName(&host->name);
getHostSerialNumber(&host->serial);
getHostVendor(&host->vendor);
}
#ifdef __x86_64__
+8
View File
@@ -107,6 +107,14 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
else if(ffStrbufStartsWithS(hwModel, "Mac"))
{
const char* version = hwModel->chars + strlen("Mac");
if(ffStrEquals(version, "17,9")) return "MacBook Pro (14-inch, M5 Pro, 2026)";
if(ffStrEquals(version, "17,8")) return "MacBook Pro (16-inch, M5 Pro, 2026)";
if(ffStrEquals(version, "17,7")) return "MacBook Pro (14-inch, M5 Max, 2026)";
if(ffStrEquals(version, "17,6")) return "MacBook Pro (16-inch, M5 Max, 2026)";
if(ffStrEquals(version, "17,5")) return "MacBook Neo (13-inch, A18 Pro, 2026)";
if(ffStrEquals(version, "17,4")) return "MacBook Air (15-inch, M5, 2026)";
if(ffStrEquals(version, "17,3")) return "MacBook Air (13-inch, M5, 2026)";
if(ffStrEquals(version, "17,2")) return "MacBook Pro (14-inch, M5, 2025)";
if(ffStrEquals(version, "16,13")) return "MacBook Air (15-inch, M4, 2025)";
if(ffStrEquals(version, "16,12")) return "MacBook Air (13-inch, M4, 2025)";
if(ffStrEquals(version, "16,11") ||
+1 -1
View File
@@ -72,7 +72,7 @@ const char* ffDetectHost(FFHostResult* host)
ffCleanUpSmbiosValue(&host->family);
}
#if _WIN64 && __x86_64__ // aarch64 also defines _WIN64
#if __x86_64__
ffHostDetectMac(host);
#endif
+6 -2
View File
@@ -3,10 +3,14 @@
const char* ffDetectIcons(FFIconsResult* result)
{
FF_HKEY_AUTO_DESTROY hKey = NULL;
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\NewStartPanel", &hKey, NULL) &&
!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu", &hKey, NULL))
return "ffRegOpenKeyForRead(Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\{NewStartPanel|ClassicStartMenu}) failed";
{
// If the key doesn't exist, it means that the user never changed the default settings.
ffStrbufSetStatic(&result->icons2, "Recycle Bin");
return NULL;
}
// Whether these icons are hidden
uint32_t ThisPC = 1, UsersFiles = 1, RemoteNetwork = 1, RecycleBin = 0 /* Shown by default */, ControlPanel = 1;
+85 -40
View File
@@ -2,55 +2,100 @@
#include "common/io.h"
#include "common/stringUtils.h"
#include <linux/input-event-codes.h>
const char* ffDetectKeyboard(FFlist* devices /* List of FFKeyboardDevice */)
{
// There is no /sys/class/input/kbd* on Linux
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/input/by-path/");
if (dirp == NULL)
return "opendir(\"/dev/input/by-path/\") == NULL";
// Parse /proc/bus/input/devices to find keyboards with a "kbd" handler.
// This detects both wired and Bluetooth keyboards uniformly.
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
if (!ffAppendFileBuffer("/proc/bus/input/devices", &content))
return "ffAppendFileBuffer(\"/proc/bus/input/devices\") == NULL";
uint64_t flags = 0;
FFstrbuf kbd = ffStrbufCreateStatic("kbd");
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
FFKeyboardDevice device = {
.name = ffStrbufCreate(),
.serial = ffStrbufCreate()
};
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &content))
{
if (!ffStrEndsWith(entry->d_name, "-event-kbd"))
continue;
char buffer[32]; // `../eventXX`
ssize_t len = readlinkat(dirfd(dirp), entry->d_name, buffer, ARRAY_SIZE(buffer) - 1);
if (len <= (ssize_t) strlen("../event") || !ffStrStartsWith(buffer, "../event")) continue;
buffer[len] = 0;
const char* eventid = buffer + strlen("../event");
char* pend = NULL;
uint32_t index = (uint32_t) strtoul(eventid, &pend, 10);
if (pend == eventid) continue;
// Ignore duplicate entries (flags supports up to 64 event indices)
if (index >= 64 || (flags & (1UL << index)))
continue;
flags |= (1UL << index);
ffStrbufSetF(&path, "/sys/class/input/event%s/device/name", eventid);
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
if (ffAppendFileBuffer(path.chars, &name))
switch (line[0])
{
ffStrbufTrimRightSpace(&name);
ffStrbufSubstrBefore(&path, path.length - (uint32_t) strlen("name"));
case 'N': {
const uint32_t prefixLen = strlen("N: Name=");
if (__builtin_expect(len <= prefixLen, false)) continue;
const char* name = line + prefixLen;
const uint32_t nameLen = (uint32_t) len - prefixLen;
ffStrbufSetNS(&device.name, nameLen, name);
ffStrbufTrim(&device.name, '"');
continue;
}
case 'H': {
const uint32_t prefixLen = strlen("H: Handlers=");
if (__builtin_expect(len <= prefixLen, false)) continue;
const char* handlers = line + prefixLen;
const uint32_t handlersLen = (uint32_t) len - prefixLen;
if (!ffStrbufMatchSeparatedNS(&kbd, handlersLen, handlers, ' '))
goto skipDevice;
continue;
}
case 'B': {
const char* bits = line + strlen("B: ");
if (ffStrStartsWith(bits, "EV="))
{
// Check EV_REP (auto-repeat, bit 20) to filter pseudo-keyboards (Power Button, PC Speaker).
const char* evBits = bits + strlen("EV=");
uint64_t val = strtoull(evBits, NULL, 16);
if (!(val & (1ULL << EV_REP)))
goto skipDevice;
}
else if (ffStrStartsWith(bits, "KEY="))
{
// Check KEY_A (bit 30) to filter media remotes and headset controls.
// The key capability bitmap is space-separated hex longs, MSB first;
// KEY_A falls in the last (least significant) word on all architectures.
const char* keyBits = bits + strlen("KEY=");
const char* lastWord = memrchr(keyBits, ' ', len - (size_t) (keyBits - line));
lastWord = lastWord ? lastWord + 1 : keyBits;
FFKeyboardDevice* device = (FFKeyboardDevice*) ffListAdd(devices);
ffStrbufInitMove(&device->name, &name);
ffStrbufInit(&device->serial);
ffStrbufAppendS(&path, "uniq");
if (ffAppendFileBuffer(path.chars, &device->serial))
ffStrbufTrimRightSpace(&device->serial);
uint64_t val = strtoull(lastWord, NULL, 16);
if (!(val & (1ULL << KEY_A)))
goto skipDevice;
}
continue;
}
case 'U': {
const uint32_t prefixLen = strlen("U: Uniq=");
if (__builtin_expect(len <= prefixLen, false)) continue;
const char* uniq = line + prefixLen;
const uint32_t uniqLen = (uint32_t) len - prefixLen;
ffStrbufSetNS(&device.serial, uniqLen, uniq);
continue;
}
case '\0':
// End of device entry; add to list if it has a name.
if (device.name.length > 0)
{
FFKeyboardDevice* added = (FFKeyboardDevice*) ffListAdd(devices);
ffStrbufInitMove(&added->name, &device.name);
ffStrbufInitMove(&added->serial, &device.serial);
}
continue;
default:
continue;
}
skipDevice:
// Skip to the end of the current device entry.
while (line[0] != '\0' && ffStrbufGetline(&line, &len, &content))
;
// Despite the fn name, it resets the string buffer to initial state
ffStrbufDestroy(&device.name);
ffStrbufDestroy(&device.serial);
}
return NULL;
+1 -1
View File
@@ -2,4 +2,4 @@
#include "fastfetch.h"
void ffDetectLocale(FFstrbuf* result);
const char* ffDetectLocale(FFstrbuf* result);
+7 -3
View File
@@ -2,15 +2,19 @@
#include <locale.h>
void ffDetectLocale(FFstrbuf* result)
const char* ffDetectLocale(FFstrbuf* result)
{
ffStrbufAppendS(result, getenv("LC_ALL"));
if(result->length > 0)
return;
return NULL;
ffStrbufAppendS(result, getenv("LANG"));
if(result->length > 0)
return;
return NULL;
ffStrbufAppendS(result, setlocale(LC_TIME, NULL));
if(result->length > 0)
return NULL;
return "Failed to detect locale";
}
+7 -4
View File
@@ -2,12 +2,15 @@
#include "common/windows/unicode.h"
#include <windows.h>
#include <locale.h>
void ffDetectLocale(FFstrbuf* result)
const char* ffDetectLocale(FFstrbuf* result)
{
wchar_t name[LOCALE_NAME_MAX_LENGTH];
int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH);
if (size > 1) // including '\0'
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
if (size <= 1) // including '\0'
return "GetUserDefaultLocaleName() failed";
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
return NULL;
}
+6 -6
View File
@@ -4,16 +4,16 @@
#include "modules/localip/option.h"
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
/* Global Unicast: 2000::/3 (001...) */
#define IN6_IS_ADDR_GLOBAL(a) (((a)->s6_addr[0] & 0xE0) == 0x20)
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
/* Unique Local: fc00::/7 (1111 110...) */
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) (((a)->s6_addr[0] & 0xFE) == 0xFC)
#endif
#ifndef IN6_IS_ADDR_LINKLOCAL
#define IN6_IS_ADDR_LINKLOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xffc00000)) == htonl(0xfe800000))
/* Link-Local: fe80::/10 (1111 1110 10...) */
#define IN6_IS_ADDR_LINKLOCAL(a) (((a)->s6_addr[0] == 0xFE) && (((a)->s6_addr[1] & 0xC0) == 0x80))
#endif
typedef struct FFLocalIpResult
+1 -1
View File
@@ -641,7 +641,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
ffStrCopy(ifmr.ifm_name, iface->name.chars, IFNAMSIZ);
if (ioctl(sockfd, SIOCGIFMEDIA, &ifmr) == 0 && (IFM_TYPE(ifmr.ifm_active) & IFM_ETHER))
{
FF_DEBUG("Interface %s media type: 0x%x", iface->name.chars, IFM_SUBTYPE(ifmr.ifm_active));
FF_DEBUG("Interface %s media type: 0x%x", iface->name.chars, (unsigned) IFM_SUBTYPE(ifmr.ifm_active));
switch (IFM_SUBTYPE(ifmr.ifm_active))
{
#ifdef IFM_HPNA_1

Some files were not shown because too many files have changed in this diff Show More