diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index c68fa959df..885b3cb652 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -260,49 +260,37 @@ s32 cellFsGetFreeSize(vm::cptr path, vm::ptr block_size, vm::ptr return CELL_OK; } -s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 entries_size, vm::ptr data_count) +error_code cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 entries_size, vm::ptr data_count) { - cellFs.warning("cellFsGetDirectoryEntries(fd=%d, entries=*0x%x, entries_size=0x%x, data_count=*0x%x)", fd, entries, entries_size, data_count); + cellFs.trace("cellFsGetDirectoryEntries(fd=%d, entries=*0x%x, entries_size=0x%x, data_count=*0x%x)", fd, entries, entries_size, data_count); - const auto directory = idm::get(fd); + if (!data_count || !entries) + { + return CELL_EFAULT; + } - if (!directory) + if (fd - 3 > 252) { return CELL_EBADF; } - u32 count = 0; + vm::var op; - entries_size /= sizeof(CellFsDirectoryEntry); + op->_vtable = vm::cast(0xfae12000); // Intentionally wrong (provide correct vtable if necessary) - for (; count < entries_size; count++) - { - fs::dir_entry info; + op->op = 0xe0000012; + op->arg._code = 0; + op->arg._size = 0; + op->arg.ptr = entries; + op->arg.max = entries_size / sizeof(CellFsDirectoryEntry); - if (directory->dir.read(info)) - { - entries[count].attribute.mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; - entries[count].attribute.uid = 1; // ??? - entries[count].attribute.gid = 1; // ??? - entries[count].attribute.atime = info.atime; - entries[count].attribute.mtime = info.mtime; - entries[count].attribute.ctime = info.ctime; - entries[count].attribute.size = info.size; - entries[count].attribute.blksize = 4096; // ??? + // Call the syscall + const s32 rc = sys_fs_fcntl(fd, 0xe0000012, op.ptr(&lv2_file_op_dir::arg), 0x10); - entries[count].entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; - entries[count].entry_name.d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); - strcpy_trunc(entries[count].entry_name.d_name, info.name); - } - else - { - break; - } - } + *data_count = op->arg._size; - *data_count = count; - - return CELL_OK; + // Select the result + return not_an_error(rc ? rc : +op->arg._code); } error_code cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr nread) diff --git a/rpcs3/Emu/Cell/Modules/cellFs.h b/rpcs3/Emu/Cell/Modules/cellFs.h index 5d22a8417b..a7ac94e4a8 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.h +++ b/rpcs3/Emu/Cell/Modules/cellFs.h @@ -2,12 +2,6 @@ #include "Emu/Cell/lv2/sys_fs.h" -struct CellFsDirectoryEntry -{ - CellFsStat attribute; - CellFsDirent entry_name; -}; - // CellFsRingBuffer.copy enum : s32 { diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 0ebb9322f9..8ad24496cc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -675,6 +675,53 @@ error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr _arg, u32 _size) return CELL_EMFILE; } + case 0xe0000012: // cellFsGetDirectoryEntries + { + const auto arg = vm::static_ptr_cast(_arg); + + if (_size < arg.size()) + { + return CELL_EINVAL; + } + + const auto directory = idm::get(fd); + + if (!directory) + { + return CELL_EBADF; + } + + for (; arg->_size < arg->max; arg->_size++) + { + fs::dir_entry info; + + if (directory->dir.read(info)) + { + auto& entry = arg->ptr[arg->_size]; + + entry.attribute.mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; + entry.attribute.uid = 0; + entry.attribute.gid = 0; + entry.attribute.atime = info.atime; + entry.attribute.mtime = info.mtime; + entry.attribute.ctime = info.ctime; + entry.attribute.size = info.size; + entry.attribute.blksize = 4096; // ??? + + entry.entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; + entry.entry_name.d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); + strcpy_trunc(entry.entry_name.d_name, info.name); + } + else + { + break; + } + } + + arg->_code = CELL_OK; + return CELL_OK; + } + default: { sys_fs.todo("sys_fs_fcntl(): Unknown operation 0x%08x (fd=%d, arg=*0x%x, size=0x%x)", op, fd, _arg, _size); diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 8abb663b06..6897a7b60e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -83,6 +83,12 @@ struct CellFsStat CHECK_SIZE_ALIGN(CellFsStat, 52, 4); +struct CellFsDirectoryEntry +{ + CellFsStat attribute; + CellFsDirent entry_name; +}; + struct CellFsUtimbuf { be_t actime; @@ -238,6 +244,28 @@ struct lv2_file_op_09 : lv2_file_op CHECK_SIZE(lv2_file_op_09, 0x40); +// sys_fs_fnctl: cellFsGetDirectoryEntries +struct lv2_file_op_dir : lv2_file_op +{ + struct dir_info : lv2_file_op + { + be_t _code; // Op result + be_t _size; // Number of entries written + vm::bptrb ptr; + be_t max; + }; + + CHECK_SIZE(dir_info, 0x10); + + vm::bptrb _vtable; + + be_t op; + be_t _x8; + dir_info arg; +}; + +CHECK_SIZE(lv2_file_op_dir, 0x1c); + // Syscalls error_code sys_fs_test(u32 arg1, u32 arg2, vm::ps3::ptr arg3, u32 arg4, vm::ps3::ptr arg5, u32 arg6);