mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-09 05:08:43 +00:00
Filesystem: Directory-related fixes (#3416)
* Various GetDents fixes Fixed return and parameter types, and made the function return all the entries that will fit in nbytes during one call. * Fstat dir stub changes Changes the returned statistics to match what my PS4 tests generally show. * Stat dir stub changes To match my fstat changes
This commit is contained in:
@@ -606,9 +606,9 @@ s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
||||
}
|
||||
if (std::filesystem::is_directory(path_name)) {
|
||||
sb->st_mode = 0000777u | 0040000u;
|
||||
sb->st_size = 0;
|
||||
sb->st_blksize = 512;
|
||||
sb->st_blocks = 0;
|
||||
sb->st_size = 65536;
|
||||
sb->st_blksize = 65536;
|
||||
sb->st_blocks = 128;
|
||||
// TODO incomplete
|
||||
} else {
|
||||
sb->st_mode = 0000777u | 0100000u;
|
||||
@@ -678,9 +678,9 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) {
|
||||
}
|
||||
case Core::FileSys::FileType::Directory: {
|
||||
sb->st_mode = 0000777u | 0040000u;
|
||||
sb->st_size = 0;
|
||||
sb->st_blksize = 512;
|
||||
sb->st_blocks = 0;
|
||||
sb->st_size = 65536;
|
||||
sb->st_blksize = 65536;
|
||||
sb->st_blocks = 128;
|
||||
// TODO incomplete
|
||||
break;
|
||||
}
|
||||
@@ -890,7 +890,7 @@ s32 PS4_SYSV_ABI sceKernelFsync(s32 fd) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static s32 GetDents(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
static s64 GetDents(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
||||
if (buf == nullptr) {
|
||||
*__Error() = POSIX_EFAULT;
|
||||
return -1;
|
||||
@@ -901,6 +901,7 @@ static s32 GetDents(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
*__Error() = POSIX_EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file->type == Core::FileSys::FileType::Device) {
|
||||
s32 result = file->device->getdents(buf, nbytes, basep);
|
||||
if (result < 0) {
|
||||
@@ -910,39 +911,49 @@ static s32 GetDents(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (file->dirents_index == file->dirents.size()) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
if (file->type != Core::FileSys::FileType::Directory || nbytes < 512 ||
|
||||
file->dirents_index > file->dirents.size()) {
|
||||
*__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
const auto& entry = file->dirents.at(file->dirents_index++);
|
||||
auto str = entry.name;
|
||||
static int fileno = 1000; // random
|
||||
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf;
|
||||
sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a
|
||||
// hash or something?
|
||||
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
|
||||
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
||||
sce_ent->d_namlen = str.size();
|
||||
strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH);
|
||||
sce_ent->d_name[ORBIS_MAX_PATH] = '\0';
|
||||
|
||||
s64 bytes_to_write = nbytes;
|
||||
char* buf_to_write = buf;
|
||||
u64 bytes_written = 0;
|
||||
while (bytes_to_write >= sizeof(OrbisKernelDirent)) {
|
||||
if (file->dirents_index == file->dirents.size()) {
|
||||
break;
|
||||
}
|
||||
const auto& entry = file->dirents.at(file->dirents_index++);
|
||||
auto str = entry.name;
|
||||
static int fileno = 1000; // random
|
||||
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf_to_write;
|
||||
// TODO this should be unique, maybe switch to a hash or something?
|
||||
sce_ent->d_fileno = fileno++;
|
||||
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
|
||||
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
||||
sce_ent->d_namlen = str.size();
|
||||
strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH);
|
||||
sce_ent->d_name[ORBIS_MAX_PATH] = '\0';
|
||||
|
||||
buf_to_write += sizeof(OrbisKernelDirent);
|
||||
bytes_to_write -= sizeof(OrbisKernelDirent);
|
||||
bytes_written += sizeof(OrbisKernelDirent);
|
||||
}
|
||||
|
||||
if (basep != nullptr) {
|
||||
*basep = file->dirents_index;
|
||||
}
|
||||
|
||||
return sizeof(OrbisKernelDirent);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_getdents(s32 fd, char* buf, s32 nbytes) {
|
||||
s64 PS4_SYSV_ABI posix_getdents(s32 fd, char* buf, u64 nbytes) {
|
||||
return GetDents(fd, buf, nbytes, nullptr);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGetdents(s32 fd, char* buf, s32 nbytes) {
|
||||
s32 result = GetDents(fd, buf, nbytes, nullptr);
|
||||
s64 PS4_SYSV_ABI sceKernelGetdents(s32 fd, char* buf, u64 nbytes) {
|
||||
s64 result = posix_getdents(fd, buf, nbytes);
|
||||
if (result < 0) {
|
||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
@@ -950,16 +961,16 @@ s32 PS4_SYSV_ABI sceKernelGetdents(s32 fd, char* buf, s32 nbytes) {
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI getdirentries(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
s64 PS4_SYSV_ABI getdirentries(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
||||
return GetDents(fd, buf, nbytes, basep);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_getdirentries(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
s64 PS4_SYSV_ABI posix_getdirentries(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
||||
return GetDents(fd, buf, nbytes, basep);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, s32 nbytes, s64* basep) {
|
||||
s32 result = GetDents(fd, buf, nbytes, basep);
|
||||
s64 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, u64 nbytes, s64* basep) {
|
||||
s64 result = GetDents(fd, buf, nbytes, basep);
|
||||
if (result < 0) {
|
||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
|
||||
Reference in New Issue
Block a user