diff --git a/Utilities/File.cpp b/Utilities/File.cpp index eb1a2ba0d0..1528b9681c 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -69,6 +69,15 @@ static time_t to_time(const FILETIME& ft) return to_time(v); } +static FILETIME from_time(s64 _time) +{ + const ullong wtime = (_time + 11644473600ULL) * 10000000ULL; + FILETIME result; + result.dwLowDateTime = static_cast(wtime); + result.dwHighDateTime = static_cast(wtime >> 32); + return result; +} + static fs::error to_error(DWORD e) { switch (e) @@ -94,6 +103,7 @@ static fs::error to_error(DWORD e) #include #include #include +#include #if defined(__APPLE__) || defined(__FreeBSD__) #include @@ -603,6 +613,48 @@ bool fs::truncate_file(const std::string& path, u64 length) #endif } +bool fs::utime(const std::string& path, s64 atime, s64 mtime) +{ + if (auto device = get_virtual_device(path)) + { + return device->utime(path, atime, mtime); + } + +#ifdef _WIN32 + // Open the file + const auto handle = CreateFileW(to_wchar(path).get(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + { + g_tls_error = to_error(GetLastError()); + return false; + } + + FILETIME _atime = from_time(atime); + FILETIME _mtime = from_time(mtime); + if (!SetFileTime(handle, nullptr, &_atime, &_mtime)) + { + g_tls_error = to_error(GetLastError()); + CloseHandle(handle); + return false; + } + + CloseHandle(handle); + return true; +#else + ::utimbuf buf; + buf.actime = atime; + buf.modtime = mtime; + + if (::utime(path.c_str(), &buf) != 0) + { + g_tls_error = to_error(errno); + return false; + } + + return true; +#endif +} + void fs::file::xnull() const { fmt::throw_exception("fs::file is null"); diff --git a/Utilities/File.h b/Utilities/File.h index a4d18108eb..f05405309d 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -93,6 +93,7 @@ namespace fs virtual bool rename(const std::string& from, const std::string& to) = 0; virtual bool remove(const std::string& path) = 0; virtual bool trunc(const std::string& path, u64 length) = 0; + virtual bool utime(const std::string& path, s64 atime, s64 mtime) = 0; virtual std::unique_ptr open(const std::string& path, bs_t mode) = 0; virtual std::unique_ptr open_dir(const std::string& path) = 0; @@ -140,6 +141,9 @@ namespace fs // Change file size (possibly appending zeros) bool truncate_file(const std::string& path, u64 length); + // Set file access/modification time + bool utime(const std::string& path, s64 atime, s64 mtime); + class file final { std::unique_ptr m_file; diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index bf2f453123..6b29870043 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -206,6 +206,16 @@ s32 cellFsChmod(vm::cptr path, s32 mode) return sys_fs_chmod(path, mode); } +s32 cellFsUtime(vm::cptr path, vm::cptr timep) +{ + cellFs.warning("cellFsUtime(path=%s, timep=*0x%x) -> sys_fs_utime()", path, timep); + + // TODO + + // Call the syscall + return sys_fs_utime(path, timep); +} + s32 cellFsGetFreeSize(vm::cptr path, vm::ptr block_size, vm::ptr block_count) { cellFs.warning("cellFsGetFreeSize(path=%s, block_size=*0x%x, block_count=*0x%x)", path, block_size, block_count); @@ -848,11 +858,6 @@ s32 cellFsSetIoBufferFromDefaultContainer(u32 fd, u32 buffer_size, u32 page_type return CELL_OK; } -s32 cellFsUtime() -{ - fmt::throw_exception("Unimplemented" HERE); -} - s32 cellFsArcadeHddSerialNumber() { fmt::throw_exception("Unimplemented" HERE); diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 3b39b21c56..7dcbcabb9b 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -730,7 +730,7 @@ std::array g_ppu_syscall_table BIND_FUNC(sys_fs_rename), //812 (0x32C) BIND_FUNC(sys_fs_rmdir), //813 (0x32D) BIND_FUNC(sys_fs_unlink), //814 (0x32E) - null_func,//BIND_FUNC(sys_fs_utime), //815 (0x32F) + BIND_FUNC(sys_fs_utime), //815 (0x32F) null_func,//BIND_FUNC(sys_fs_access), //816 (0x330) BIND_FUNC(sys_fs_fcntl), //817 (0x331) BIND_FUNC(sys_fs_lseek), //818 (0x332) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 8bc33c2c14..bbae77629f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -592,3 +592,21 @@ error_code sys_fs_chmod(vm::cptr path, s32 mode) return CELL_OK; } + +error_code sys_fs_utime(vm::ps3::cptr path, vm::ps3::cptr timep) +{ + sys_fs.warning("sys_fs_utime(path=%s, timep=*0x%x)", path, timep); + + if (!fs::utime(vfs::get(path.get_ptr()), timep->actime, timep->modtime)) + { + switch (auto error = fs::g_tls_error) + { + case fs::error::noent: return CELL_ENOENT; + default: sys_fs.error("sys_fs_utime(): unknown error %s", error); + } + + return CELL_EIO; // ??? + } + + return CELL_OK; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 09203a6123..96fc1068f3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -205,3 +205,4 @@ error_code sys_fs_get_block_size(vm::ps3::cptr path, vm::ps3::ptr sec error_code sys_fs_truncate(vm::ps3::cptr path, u64 size); error_code sys_fs_ftruncate(u32 fd, u64 size); error_code sys_fs_chmod(vm::ps3::cptr path, s32 mode); +error_code sys_fs_utime(vm::ps3::cptr path, vm::ps3::cptr timep);