win/fs: check file handle with GetFileInformationByHandle when creating fs::file
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.8, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.8, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.8, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.8, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

On empty mounted drives CreateFileW may return a valid handle even if the drive is not usable.
We have to check the file handle early. Otherwise other functions may fail later as a result.
This commit is contained in:
Megamouse 2026-02-19 23:58:34 +01:00 committed by Elad
parent aaf84a8445
commit ff992a67c8
3 changed files with 32 additions and 22 deletions

View file

@ -398,12 +398,11 @@ namespace fs
class windows_file final : public file_base
{
HANDLE m_handle;
atomic_t<u64> m_pos;
atomic_t<u64> m_pos {0};
public:
windows_file(HANDLE handle)
: m_handle(handle)
, m_pos(0)
{
}
@ -417,10 +416,10 @@ namespace fs
stat_t get_stat() override
{
FILE_BASIC_INFO basic_info;
FILE_BASIC_INFO basic_info {};
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
stat_t info;
stat_t info {};
info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
info.size = this->size();
@ -441,7 +440,7 @@ namespace fs
bool trunc(u64 length) override
{
FILE_END_OF_FILE_INFO _eof;
FILE_END_OF_FILE_INFO _eof {};
_eof.EndOfFile.QuadPart = length;
if (!SetFileInformationByHandle(m_handle, FileEndOfFileInfo, &_eof, sizeof(_eof)))
@ -563,6 +562,7 @@ namespace fs
u64 size() override
{
// NOTE: this can fail if we access a mounted empty drive (e.g. after unmounting an iso).
LARGE_INTEGER size;
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
@ -579,7 +579,7 @@ namespace fs
file_id id{"windows_file"};
id.data.resize(sizeof(FILE_ID_INFO));
FILE_ID_INFO info;
FILE_ID_INFO info {};
if (!GetFileInformationByHandleEx(m_handle, FileIdInfo, &info, sizeof(info)))
{
@ -625,7 +625,7 @@ namespace fs
struct ::stat file_info;
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
stat_t info;
stat_t info {};
info.is_directory = S_ISDIR(file_info.st_mode);
info.is_writable = file_info.st_mode & 0200; // HACK: approximation
info.size = file_info.st_size;
@ -1656,6 +1656,16 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
// Check if the handle is actually valid.
// This can fail on empty mounted drives (e.g. with ERROR_NOT_READY or ERROR_INVALID_FUNCTION).
BY_HANDLE_FILE_INFORMATION info;
if (!GetFileInformationByHandle(handle, &info))
{
CloseHandle(handle);
g_tls_error = to_error(GetLastError());
return;
}
m_file = std::make_unique<windows_file>(handle);
#else
int flags = O_CLOEXEC; // Ensures all files are closed on execl for auto updater

View file

@ -66,13 +66,13 @@ namespace fs
// File attributes (TODO)
struct stat_t
{
bool is_directory;
bool is_symlink;
bool is_writable;
u64 size;
s64 atime;
s64 mtime;
s64 ctime;
bool is_directory = false;
bool is_symlink = false;
bool is_writable = false;
u64 size = 0;
s64 atime = 0;
s64 mtime = 0;
s64 ctime = 0;
using enable_bitcopy = std::true_type;

View file

@ -13,16 +13,16 @@ void unload_iso();
struct iso_extent_info
{
u64 start;
u64 size;
u64 start = 0;
u64 size = 0;
};
struct iso_fs_metadata
{
std::string name;
s64 time;
bool is_directory;
bool has_multiple_extents;
s64 time = 0;
bool is_directory = false;
bool has_multiple_extents = false;
std::vector<iso_extent_info> extents;
u64 size() const;
@ -30,7 +30,7 @@ struct iso_fs_metadata
struct iso_fs_node
{
iso_fs_metadata metadata;
iso_fs_metadata metadata {};
std::vector<std::unique_ptr<iso_fs_node>> children;
};
@ -38,7 +38,7 @@ class iso_file : public fs::file_base
{
private:
fs::file m_file;
iso_fs_metadata m_meta;
iso_fs_metadata m_meta {};
u64 m_pos = 0;
std::pair<u64, iso_extent_info> get_extent_pos(u64 pos) const;
@ -80,7 +80,7 @@ class iso_archive
{
private:
std::string m_path;
iso_fs_node m_root;
iso_fs_node m_root {};
fs::file m_file;
public: