Skip to content

Commit 1a9a7b9

Browse files
committed
libretro: add VFS support
1 parent 17c6a8a commit 1a9a7b9

13 files changed

Lines changed: 1443 additions & 45 deletions

File tree

Source/Core/Common/CommonFuncs.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@
3030
#define fseeko _fseeki64
3131
#define ftello _ftelli64
3232
#define atoll _atoi64
33-
#ifndef stat
33+
#ifndef __MINGW32__
3434
#define stat _stat64
35-
#endif
36-
#ifndef fstat
3735
#define fstat _fstat64
3836
#endif
3937
#define fileno _fileno

Source/Core/Common/DirectIOFile.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
#include "Common/Assert.h"
3434

35+
#ifdef __LIBRETRO__
36+
#include "DolphinLibretro/Common/File.h"
37+
#endif
38+
3539
namespace File
3640
{
3741
DirectIOFile::DirectIOFile() = default;
@@ -79,6 +83,17 @@ bool DirectIOFile::Open(const std::string& path, AccessMode access_mode, OpenMod
7983
if (access_mode == AccessMode::Read && open_mode == OpenMode::Truncate)
8084
return false;
8185

86+
#ifdef __LIBRETRO__
87+
if (Libretro::File::HasVFS())
88+
{
89+
// used in Duplicate() later
90+
m_path = path;
91+
92+
return Libretro::File::Open(path, access_mode, open_mode,
93+
m_vfs_handle, m_mode, m_hints, m_current_offset);
94+
}
95+
#endif
96+
8297
#if defined(_WIN32)
8398
DWORD desired_access = GENERIC_READ | GENERIC_WRITE;
8499
if (access_mode == AccessMode::Read)
@@ -168,6 +183,15 @@ bool DirectIOFile::Close()
168183

169184
m_current_offset = 0;
170185

186+
#ifdef __LIBRETRO__
187+
if (Libretro::File::HasVFS())
188+
{
189+
int result = Libretro::File::Close(m_vfs_handle);
190+
m_vfs_handle = nullptr;
191+
return result == 0;
192+
}
193+
#endif
194+
171195
#if defined(_WIN32)
172196
return CloseHandle(std::exchange(m_handle, INVALID_HANDLE_VALUE)) != 0;
173197
#else
@@ -177,6 +201,11 @@ bool DirectIOFile::Close()
177201

178202
bool DirectIOFile::IsOpen() const
179203
{
204+
#ifdef __LIBRETRO__
205+
if (Libretro::File::HasVFS())
206+
return m_vfs_handle != nullptr;
207+
#endif
208+
180209
#if defined(_WIN32)
181210
return m_handle != INVALID_HANDLE_VALUE;
182211
#else
@@ -216,6 +245,17 @@ static bool OverlappedTransfer(HANDLE handle, u64 offset, auto* data_ptr, u64 si
216245

217246
bool DirectIOFile::OffsetRead(u64 offset, u8* out_ptr, u64 size)
218247
{
248+
#ifdef __LIBRETRO__
249+
if (Libretro::File::HasVFS())
250+
{
251+
if (Libretro::File::Seek(m_vfs_handle, offset, SEEK_SET) < 0)
252+
return false;
253+
254+
int64_t bytes_read = Libretro::File::ReadBytes(m_vfs_handle, out_ptr, size);
255+
return bytes_read == static_cast<int64_t>(size);
256+
}
257+
#endif
258+
219259
#if defined(_WIN32)
220260
return OverlappedTransfer<ReadFile>(m_handle, offset, out_ptr, size);
221261
#else
@@ -225,6 +265,17 @@ bool DirectIOFile::OffsetRead(u64 offset, u8* out_ptr, u64 size)
225265

226266
bool DirectIOFile::OffsetWrite(u64 offset, const u8* in_ptr, u64 size)
227267
{
268+
#ifdef __LIBRETRO__
269+
if (Libretro::File::HasVFS())
270+
{
271+
if (Libretro::File::Seek(m_vfs_handle, offset, SEEK_SET) < 0)
272+
return false;
273+
274+
int64_t bytes_written = Libretro::File::WriteBytes(m_vfs_handle, in_ptr, size);
275+
return bytes_written == static_cast<int64_t>(size);
276+
}
277+
#endif
278+
228279
#if defined(_WIN32)
229280
return OverlappedTransfer<WriteFile>(m_handle, offset, in_ptr, size);
230281
#else
@@ -234,6 +285,11 @@ bool DirectIOFile::OffsetWrite(u64 offset, const u8* in_ptr, u64 size)
234285

235286
u64 DirectIOFile::GetSize() const
236287
{
288+
#ifdef __LIBRETRO__
289+
if (Libretro::File::HasVFS())
290+
return Libretro::File::GetSize(m_vfs_handle);
291+
#endif
292+
237293
#if defined(_WIN32)
238294
LARGE_INTEGER result{};
239295
if (GetFileSizeEx(m_handle, &result) != 0)
@@ -275,6 +331,11 @@ bool DirectIOFile::Seek(s64 offset, SeekOrigin origin)
275331

276332
bool DirectIOFile::Flush()
277333
{
334+
#ifdef __LIBRETRO__
335+
if (Libretro::File::HasVFS())
336+
return Libretro::File::Flush(m_vfs_handle) == 0;
337+
#endif
338+
278339
#if defined(_WIN32)
279340
return FlushFileBuffers(m_handle) != 0;
280341
#else
@@ -284,6 +345,16 @@ bool DirectIOFile::Flush()
284345

285346
void DirectIOFile::Swap(DirectIOFile& other)
286347
{
348+
#ifdef __LIBRETRO__
349+
if (Libretro::File::HasVFS())
350+
{
351+
std::swap(m_vfs_handle, other.m_vfs_handle);
352+
std::swap(m_path, other.m_path);
353+
std::swap(m_mode, other.m_mode);
354+
std::swap(m_hints, other.m_hints);
355+
}
356+
#endif
357+
287358
#if defined(_WIN32)
288359
std::swap(m_handle, other.m_handle);
289360
#else
@@ -299,6 +370,30 @@ DirectIOFile DirectIOFile::Duplicate() const
299370
if (!IsOpen())
300371
return result;
301372

373+
#ifdef __LIBRETRO__
374+
if (Libretro::File::HasVFS())
375+
{
376+
// We need to reopen the file, since VFS handles cannot be duplicated.
377+
result.m_vfs_handle = Libretro::File::Open(
378+
m_path, m_mode, m_hints);
379+
380+
if (result.m_vfs_handle)
381+
{
382+
result.m_path = m_path;
383+
result.m_mode = m_mode;
384+
result.m_hints = m_hints;
385+
386+
// Restore offset if possible
387+
Libretro::File::Seek(
388+
result.m_vfs_handle,
389+
m_current_offset,
390+
SEEK_SET);
391+
result.m_current_offset = m_current_offset;
392+
}
393+
return result;
394+
}
395+
#endif
396+
302397
#if defined(_WIN32)
303398
const auto current_process = GetCurrentProcess();
304399
if (DuplicateHandle(current_process, m_handle, current_process, &result.m_handle, 0, FALSE,
@@ -319,6 +414,11 @@ DirectIOFile DirectIOFile::Duplicate() const
319414

320415
bool Resize(DirectIOFile& file, u64 size)
321416
{
417+
#ifdef __LIBRETRO__
418+
if (Libretro::File::HasVFS())
419+
return Libretro::File::Truncate(file.m_vfs_handle, size) == 0;
420+
#endif
421+
322422
#if defined(_WIN32)
323423
// This operation is not "atomic", but it's the only thing we're using the file pointer for.
324424
// Concurrent `Resize` would need some external synchronization to prevent race regardless.
@@ -333,6 +433,11 @@ bool Resize(DirectIOFile& file, u64 size)
333433
bool Rename(DirectIOFile& file, const std::string& source_path [[maybe_unused]],
334434
const std::string& destination_path)
335435
{
436+
#ifdef __LIBRETRO__
437+
if (Libretro::File::HasVFS())
438+
return file.IsOpen() && Libretro::File::Rename(source_path, destination_path);
439+
#endif
440+
336441
#if defined(_WIN32)
337442
const auto dest_name = UTF8ToWString(destination_path);
338443
const auto dest_name_byte_size = DWORD(dest_name.size() * sizeof(WCHAR));
@@ -354,6 +459,11 @@ bool Rename(DirectIOFile& file, const std::string& source_path [[maybe_unused]],
354459

355460
bool Delete(DirectIOFile& file, const std::string& filename)
356461
{
462+
#ifdef __LIBRETRO__
463+
if (Libretro::File::HasVFS())
464+
return file.IsOpen() && Libretro::File::Delete(filename);
465+
#endif
466+
357467
#if defined(_WIN32)
358468
FILE_DISPOSITION_INFO info{.DeleteFile = TRUE};
359469
return SetFileInformationByHandle(file.GetHandle(), FileDispositionInfo, &info, sizeof(info)) !=

Source/Core/Common/DirectIOFile.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ class DirectIOFile final
111111

112112
auto GetHandle() const
113113
{
114+
#ifdef __LIBRETRO__
115+
if (Libretro::File::HasVFS())
116+
ERROR_LOG_FMT(COMMON, "VFS: Attempt to use std::FILE in DirectIO which should not happen in VFS mode");
117+
#endif
118+
114119
#if defined(_WIN32)
115120
return m_handle;
116121
#else
@@ -133,6 +138,15 @@ class DirectIOFile final
133138
#endif
134139

135140
u64 m_current_offset{};
141+
142+
#ifdef __LIBRETRO__
143+
retro_vfs_file_handle* m_vfs_handle = nullptr;
144+
std::string m_path;
145+
unsigned m_mode{};
146+
unsigned m_hints{};
147+
148+
friend bool Resize(DirectIOFile& file, u64 size);
149+
#endif
136150
};
137151

138152
// These take an open file handle to avoid failures from other processes trying to open our files.

0 commit comments

Comments
 (0)