diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp index 6ed5bf3bee..72457194ac 100644 --- a/Utilities/rFile.cpp +++ b/Utilities/rFile.cpp @@ -26,13 +26,18 @@ std::unique_ptr ConvertUTF8ToWChar(const std::string& source) return buffer; } +time_t to_time_t(const LARGE_INTEGER& ft) +{ + return ft.QuadPart / 10000000ULL - 11644473600ULL; +} + time_t to_time_t(const FILETIME& ft) { - ULARGE_INTEGER v; + LARGE_INTEGER v; v.LowPart = ft.dwLowDateTime; v.HighPart = ft.dwHighDateTime; - return v.QuadPart / 10000000ULL - 11644473600ULL; + return to_time_t(v); } bool truncate_file(const std::string& file, uint64_t length) @@ -78,17 +83,17 @@ bool truncate_file(const std::string& file, uint64_t length) bool get_file_info(const std::string& path, FileInfo& info) { - // TODO: Expand relative paths? - info.fullName = path; + info.name = path; + + info.exists = false; + info.isDirectory = false; + info.isWritable = false; + info.size = 0; #ifdef _WIN32 WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesExW(ConvertUTF8ToWChar(path).get(), GetFileExInfoStandard, &attrs)) { - info.exists = false; - info.isDirectory = false; - info.isWritable = false; - info.size = 0; return false; } @@ -103,10 +108,6 @@ bool get_file_info(const std::string& path, FileInfo& info) struct stat64 file_info; if (stat64(path.c_str(), &file_info) < 0) { - info.exists = false; - info.isDirectory = false; - info.isWritable = false; - info.size = 0; return false; } @@ -118,6 +119,7 @@ bool get_file_info(const std::string& path, FileInfo& info) info.mtime = file_info.st_mtime; info.ctime = file_info.st_ctime; #endif + return true; } @@ -438,6 +440,7 @@ bool rfile_t::trunc(u64 size) const SetFilePointerEx(fd, pos, NULL, FILE_BEGIN); // set new position SetEndOfFile(fd); // change file size + SetFilePointerEx(fd, old, NULL, FILE_BEGIN); // restore position return true; // TODO @@ -446,6 +449,54 @@ bool rfile_t::trunc(u64 size) const #endif } +bool rfile_t::stat(FileInfo& info) const +{ + info.name.clear(); // possibly, TODO + + info.exists = false; + info.isDirectory = false; + info.isWritable = false; + info.size = 0; + +#ifdef _WIN32 + FILE_BASIC_INFO basic_info; + //FILE_NAME_INFO name_info; + + if (!GetFileInformationByHandleEx(fd, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) + { + return false; + } + + info.exists = true; + info.isDirectory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info.isWritable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0; + info.size = this->size(); + info.atime = to_time_t(basic_info.LastAccessTime); + info.mtime = to_time_t(basic_info.ChangeTime); + info.ctime = to_time_t(basic_info.CreationTime); +#else + struct stat64 file_info; + if (fstat64(fd, &file_info) < 0) + { + info.exists = false; + info.isDirectory = false; + info.isWritable = false; + info.size = 0; + return false; + } + + info.exists = true; + info.isDirectory = S_ISDIR(file_info.st_mode); + info.isWritable = file_info.st_mode & 0200; // HACK: approximation + info.size = file_info.st_size; + info.atime = file_info.st_atime; + info.mtime = file_info.st_mtime; + info.ctime = file_info.st_ctime; +#endif + + return true; +} + bool rfile_t::close() { #ifdef _WIN32 diff --git a/Utilities/rFile.h b/Utilities/rFile.h index 1f2ec21023..70d6d4eb32 100644 --- a/Utilities/rFile.h +++ b/Utilities/rFile.h @@ -3,7 +3,6 @@ struct FileInfo { std::string name; - std::string fullName; bool exists; bool isDirectory; bool isWritable; @@ -68,6 +67,7 @@ public: bool open(const std::string& filename, u32 mode = o_read); bool is_opened() const; bool trunc(u64 size) const; + bool stat(FileInfo& info) const; bool close(); u64 read(void* buffer, u64 count) const; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp b/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp index 94154df1c4..dd40006839 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp @@ -261,14 +261,14 @@ s32 sys_fs_stat(vm::ptr path, vm::ptr sb) sb->mtime = info.mtime; sb->ctime = info.ctime; sb->size = info.size; - sb->blksize = 4096; // ??? + sb->blksize = info.size ? align(info.size, 4096) : 4096; // ??? return CELL_OK; } s32 sys_fs_fstat(u32 fd, vm::ptr sb) { - sys_fs.Error("sys_fs_fstat(fd=0x%x, sb=*0x%x)", fd, sb); + sys_fs.Warning("sys_fs_fstat(fd=0x%x, sb=*0x%x)", fd, sb); const auto file = Emu.GetIdManager().GetIDData(fd); @@ -277,19 +277,47 @@ s32 sys_fs_fstat(u32 fd, vm::ptr sb) return CELL_FS_EBADF; } - sb->mode = - CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR | - CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP | - CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH; + std::lock_guard lock(file->mutex); + + const auto local_file = dynamic_cast(file->file.get()); + + if (!local_file) + { + sys_fs.Error("sys_fs_fstat(fd=0x%x): not a local file"); + return CELL_FS_ENOTSUP; + } + + FileInfo info; + + if (!local_file->GetFile().stat(info)) + { + return CELL_FS_EIO; // ??? + } + + s32 mode = CELL_FS_S_IRUSR | CELL_FS_S_IRGRP | CELL_FS_S_IROTH; + + if (info.isWritable) + { + mode |= CELL_FS_S_IWUSR | CELL_FS_S_IWGRP | CELL_FS_S_IWOTH; + } + + if (info.isDirectory) + { + mode |= CELL_FS_S_IFDIR; + mode |= CELL_FS_S_IXUSR | CELL_FS_S_IXGRP | CELL_FS_S_IXOTH; // ??? + } + else + { + mode |= CELL_FS_S_IFREG; + } - sb->mode |= CELL_FS_S_IFREG; sb->uid = 1; // ??? sb->gid = 1; // ??? - sb->atime = 0; // TODO - sb->mtime = 0; // TODO - sb->ctime = 0; // TODO - sb->size = file->file->GetSize(); - sb->blksize = 4096; + sb->atime = info.atime; + sb->mtime = info.mtime; + sb->ctime = info.ctime; // may be incorrect + sb->size = info.size; + sb->blksize = info.size ? align(info.size, 4096) : 4096; // ??? return CELL_OK; }