mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-31 20:41:45 +01:00
Partial commit: sys_fs
This commit is contained in:
parent
59433bfcd5
commit
438e057dc8
@ -80,6 +80,8 @@ static fs::error to_error(DWORD e)
|
||||
case ERROR_ALREADY_EXISTS: return fs::error::exist;
|
||||
case ERROR_FILE_EXISTS: return fs::error::exist;
|
||||
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
|
||||
case ERROR_DIRECTORY: return fs::error::inval;
|
||||
case ERROR_INVALID_NAME: return fs::error::inval;
|
||||
default: throw fmt::exception("Unknown Win32 error: %u.", e);
|
||||
}
|
||||
}
|
||||
|
@ -103,3 +103,46 @@ public:
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//! Simple lock-free map. Based on lf_array<>. All elements are accessible, implicitly initialized.
|
||||
template<typename K, typename T, typename Hash = value_hash<K>, std::size_t Size = 256>
|
||||
class lf_hashmap
|
||||
{
|
||||
struct pair_t
|
||||
{
|
||||
// Default-constructed key means "no key"
|
||||
atomic_t<K> key{};
|
||||
T value{};
|
||||
};
|
||||
|
||||
//
|
||||
lf_array<pair_t, Size> m_data{};
|
||||
|
||||
// Value for default-constructed key
|
||||
T m_default_key_data{};
|
||||
|
||||
public:
|
||||
constexpr lf_hashmap() = default;
|
||||
|
||||
// Access element (added implicitly)
|
||||
T& operator [](const K& key)
|
||||
{
|
||||
if (UNLIKELY(key == K{}))
|
||||
{
|
||||
return m_default_key_data;
|
||||
}
|
||||
|
||||
// Calculate hash and array position
|
||||
for (std::size_t pos = Hash{}(key) % Size;; pos += Size)
|
||||
{
|
||||
// Access the array
|
||||
auto& pair = m_data[pos];
|
||||
|
||||
// Check the key value (optimistic)
|
||||
if (LIKELY(pair.key == key) || pair.key.compare_and_swap_test(K{}, key))
|
||||
{
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -423,6 +423,15 @@ struct pointer_hash
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, std::size_t Shift = 0>
|
||||
struct value_hash
|
||||
{
|
||||
std::size_t operator()(T value) const
|
||||
{
|
||||
return static_cast<std::size_t>(value) >> Shift;
|
||||
}
|
||||
};
|
||||
|
||||
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied.
|
||||
// For example, `simple_t` may be used to remove endianness.
|
||||
template<template<typename> class TT, std::size_t S, std::size_t A = S>
|
||||
|
@ -58,8 +58,13 @@ s32 cellFsReaddir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||
{
|
||||
cellFs.trace("cellFsReaddir(fd=0x%x, dir=*0x%x, nread=*0x%x)", fd, dir, nread);
|
||||
|
||||
if (!dir || !nread)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return dir && nread ? sys_fs_readdir(fd, dir, nread) : CELL_FS_EFAULT;
|
||||
return sys_fs_readdir(fd, dir, nread);
|
||||
}
|
||||
|
||||
s32 cellFsClosedir(u32 fd)
|
||||
@ -132,8 +137,13 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr<u64> pos)
|
||||
{
|
||||
cellFs.trace("cellFsLseek(fd=0x%x, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return pos ? sys_fs_lseek(fd, offset, whence, pos) : CELL_FS_EFAULT;
|
||||
return sys_fs_lseek(fd, offset, whence, pos);
|
||||
}
|
||||
|
||||
s32 cellFsFsync(u32 fd)
|
||||
@ -147,8 +157,13 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_siz
|
||||
{
|
||||
cellFs.trace("cellFsFGetBlockSize(fd=0x%x, sector_size=*0x%x, block_size=*0x%x)", fd, sector_size, block_size);
|
||||
|
||||
if (!sector_size || !block_size)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return sector_size && block_size ? sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>{}, vm::var<u64>{}) : CELL_FS_EFAULT;
|
||||
return sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>{}, vm::var<u64>{});
|
||||
}
|
||||
|
||||
s32 cellFsGetBlockSize(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
|
||||
@ -205,11 +220,11 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
|
||||
{
|
||||
cellFs.warning("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<lv2_dir_t>(fd);
|
||||
const auto directory = idm::get<lv2_dir>(fd);
|
||||
|
||||
if (!directory)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
u32 count = 0;
|
||||
@ -246,474 +261,278 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr<void> buf, u64 buffer_size, vm::ptr<u64> nread)
|
||||
ppu_error_code cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr<void> buf, u64 buffer_size, vm::ptr<u64> nread)
|
||||
{
|
||||
cellFs.trace("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, buffer_size=0x%llx, nread=*0x%x)", fd, offset, buf, buffer_size, nread);
|
||||
|
||||
// TODO: use single sys_fs_fcntl syscall
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
|
||||
if (!file || file->flags & CELL_FS_O_WRONLY)
|
||||
if (fd - 3 > 252)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
if (nread) *nread = 0;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
vm::var<lv2_file_op_rw> arg;
|
||||
|
||||
const auto old_pos = file->file.pos(); file->file.seek(offset);
|
||||
arg->_vtable = vm::cast(0xfa8a0000); // Intentionally wrong (provide correct vtable if necessary)
|
||||
|
||||
arg->op = 0x8000000a;
|
||||
arg->fd = fd;
|
||||
arg->buf = buf;
|
||||
arg->offset = offset;
|
||||
arg->size = buffer_size;
|
||||
|
||||
const auto read = file->file.read(buf.get_ptr(), buffer_size);
|
||||
// Call the syscall
|
||||
const s32 rc = sys_fs_fcntl(fd, 0x8000000a, arg, arg.size());
|
||||
|
||||
file->file.seek(old_pos);
|
||||
// Write size read
|
||||
if (nread) *nread = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value();
|
||||
|
||||
if (nread)
|
||||
{
|
||||
*nread = read;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return NOT_AN_ERROR(rc ? rc : arg->out_code.value());
|
||||
}
|
||||
|
||||
s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr<void> buf, u64 data_size, vm::ptr<u64> nwrite)
|
||||
ppu_error_code cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr<void> buf, u64 data_size, vm::ptr<u64> nwrite)
|
||||
{
|
||||
cellFs.trace("cellFsWriteWithOffset(fd=%d, offset=0x%llx, buf=*0x%x, data_size=0x%llx, nwrite=*0x%x)", fd, offset, buf, data_size, nwrite);
|
||||
|
||||
// TODO: use single sys_fs_fcntl syscall
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
|
||||
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
|
||||
if (!buf)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
if (nwrite) *nwrite = 0;
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
const auto old_pos = file->file.pos(); file->file.seek(offset);
|
||||
|
||||
const auto written = file->file.write(buf.get_ptr(), data_size);
|
||||
|
||||
file->file.seek(old_pos);
|
||||
|
||||
if (nwrite)
|
||||
if (fd - 3 > 252)
|
||||
{
|
||||
*nwrite = written;
|
||||
if (nwrite) *nwrite = 0;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
vm::var<lv2_file_op_rw> arg;
|
||||
|
||||
arg->_vtable = vm::cast(0xfa8b0000); // Intentionally wrong (provide correct vtable if necessary)
|
||||
|
||||
arg->op = 0x8000000b;
|
||||
arg->fd = fd;
|
||||
arg->buf = vm::const_ptr_cast<void>(buf);
|
||||
arg->offset = offset;
|
||||
arg->size = data_size;
|
||||
|
||||
// Call the syscall
|
||||
const s32 rc = sys_fs_fcntl(fd, 0x8000000b, arg, arg.size());
|
||||
|
||||
// Write size written
|
||||
if (nwrite) *nwrite = rc && rc != CELL_EFSSPECIFIC ? 0 : arg->out_size.value();
|
||||
|
||||
return NOT_AN_ERROR(rc ? rc : arg->out_code.value());
|
||||
}
|
||||
|
||||
s32 cellFsStReadInit(u32 fd, vm::cptr<CellFsRingBuffer> ringbuf)
|
||||
{
|
||||
cellFs.warning("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
|
||||
cellFs.todo("cellFsStReadInit(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
|
||||
|
||||
if (ringbuf->copy & ~CELL_FS_ST_COPYLESS)
|
||||
{
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (ringbuf->block_size & 0xfff) // check if a multiple of sector size
|
||||
{
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (ringbuf->ringbuf_size % ringbuf->block_size) // check if a multiple of block_size
|
||||
{
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->flags & CELL_FS_O_WRONLY)
|
||||
{
|
||||
return CELL_FS_EPERM;
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
if (!file->st_status.compare_and_swap_test(SSS_NOT_INITIALIZED, SSS_INITIALIZED))
|
||||
{
|
||||
return CELL_FS_EBUSY;
|
||||
}
|
||||
|
||||
file->st_ringbuf_size = ringbuf->ringbuf_size;
|
||||
file->st_block_size = ringbuf->ringbuf_size;
|
||||
file->st_trans_rate = ringbuf->transfer_rate;
|
||||
file->st_copyless = ringbuf->copy == CELL_FS_ST_COPYLESS;
|
||||
|
||||
const u64 alloc_size = align(file->st_ringbuf_size, file->st_ringbuf_size < 1024 * 1024 ? 64 * 1024 : 1024 * 1024);
|
||||
|
||||
file->st_buffer = vm::alloc(static_cast<u32>(alloc_size), vm::main);
|
||||
file->st_read_size = 0;
|
||||
file->st_total_read = 0;
|
||||
file->st_copied = 0;
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadFinish(u32 fd)
|
||||
{
|
||||
cellFs.warning("cellFsStReadFinish(fd=%d)", fd);
|
||||
cellFs.todo("cellFsStReadFinish(fd=%d)", fd);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF; // ???
|
||||
return CELL_EBADF; // ???
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
|
||||
if (!file->st_status.compare_and_swap_test(SSS_INITIALIZED, SSS_NOT_INITIALIZED))
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
vm::dealloc(file->st_buffer, vm::main);
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
|
||||
{
|
||||
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
|
||||
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
ringbuf->ringbuf_size = file->st_ringbuf_size;
|
||||
ringbuf->block_size = file->st_block_size;
|
||||
ringbuf->transfer_rate = file->st_trans_rate;
|
||||
ringbuf->copy = file->st_copyless ? CELL_FS_ST_COPYLESS : CELL_FS_ST_COPY;
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadGetStatus(u32 fd, vm::ptr<u64> status)
|
||||
{
|
||||
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status);
|
||||
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
switch (file->st_status.load())
|
||||
{
|
||||
case SSS_INITIALIZED:
|
||||
case SSS_STOPPED:
|
||||
{
|
||||
*status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_STOP;
|
||||
break;
|
||||
}
|
||||
case SSS_STARTED:
|
||||
{
|
||||
*status = CELL_FS_ST_INITIALIZED | CELL_FS_ST_PROGRESS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
*status = CELL_FS_ST_NOT_INITIALIZED | CELL_FS_ST_STOP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadGetRegid(u32 fd, vm::ptr<u64> regid)
|
||||
{
|
||||
cellFs.warning("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid);
|
||||
cellFs.todo("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
*regid = file->st_total_read - file->st_copied;
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
|
||||
{
|
||||
cellFs.warning("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size);
|
||||
cellFs.todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
switch (auto status = file->st_status.compare_and_swap(SSS_INITIALIZED, SSS_STARTED))
|
||||
{
|
||||
case SSS_NOT_INITIALIZED:
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
case SSS_STARTED:
|
||||
{
|
||||
return CELL_FS_EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
offset = std::min<u64>(file->file.size(), offset);
|
||||
size = std::min<u64>(file->file.size() - offset, size);
|
||||
|
||||
file->st_read_size = size;
|
||||
|
||||
file->st_thread = thread_ctrl::spawn("FS ST Thread", [=]()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(file->mutex);
|
||||
|
||||
while (file->st_status == SSS_STARTED && !Emu.IsStopped())
|
||||
{
|
||||
// check free space in buffer and available data in stream
|
||||
if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size)
|
||||
{
|
||||
// get buffer position
|
||||
const u32 position = vm::cast(file->st_buffer + file->st_total_read % file->st_ringbuf_size, HERE);
|
||||
|
||||
// read data
|
||||
auto old = file->file.pos();
|
||||
file->file.seek(offset + file->st_total_read);
|
||||
auto res = file->file.read(vm::base(position), file->st_block_size);
|
||||
file->file.seek(old);
|
||||
|
||||
// notify
|
||||
file->st_total_read += res;
|
||||
file->cv.notify_one();
|
||||
}
|
||||
|
||||
// check callback condition if set
|
||||
if (file->st_callback.load().func)
|
||||
{
|
||||
const u64 available = file->st_total_read - file->st_copied;
|
||||
|
||||
if (available >= file->st_callback.load().size)
|
||||
{
|
||||
const auto func = file->st_callback.exchange({}).func;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, fd, available);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
file->cv.wait_for(lock, 1ms);
|
||||
}
|
||||
|
||||
file->st_status.compare_and_swap(SSS_STOPPED, SSS_INITIALIZED);
|
||||
file->st_read_size = 0;
|
||||
file->st_total_read = 0;
|
||||
file->st_copied = 0;
|
||||
file->st_callback.store({});
|
||||
});
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadStop(u32 fd)
|
||||
{
|
||||
cellFs.warning("cellFsStReadStop(fd=%d)", fd);
|
||||
cellFs.todo("cellFsStReadStop(fd=%d)", fd);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
switch (auto status = file->st_status.compare_and_swap(SSS_STARTED, SSS_STOPPED))
|
||||
{
|
||||
case SSS_NOT_INITIALIZED:
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
case SSS_INITIALIZED:
|
||||
case SSS_STOPPED:
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
file->cv.notify_all();
|
||||
file->st_thread->join();
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStRead(u32 fd, vm::ptr<u8> buf, u64 size, vm::ptr<u64> rsize)
|
||||
{
|
||||
cellFs.warning("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize);
|
||||
cellFs.todo("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED || file->st_copyless)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
// TODO
|
||||
|
||||
const u64 copied = file->st_copied;
|
||||
const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE);
|
||||
const u64 total_read = file->st_total_read;
|
||||
const u64 copy_size = (*rsize = std::min<u64>(size, total_read - copied)); // write rsize
|
||||
|
||||
// copy data
|
||||
const u64 first_size = std::min<u64>(copy_size, file->st_ringbuf_size - (position - file->st_buffer));
|
||||
std::memcpy(buf.get_ptr(), vm::base(position), first_size);
|
||||
std::memcpy((buf + first_size).get_ptr(), vm::base(file->st_buffer), copy_size - first_size);
|
||||
|
||||
// notify
|
||||
file->st_copied += copy_size;
|
||||
file->cv.notify_one();
|
||||
|
||||
// check end of stream
|
||||
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr<u32> addr, vm::ptr<u64> size)
|
||||
{
|
||||
cellFs.warning("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size);
|
||||
cellFs.todo("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
// TODO
|
||||
|
||||
const u64 copied = file->st_copied;
|
||||
const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE);
|
||||
const u64 total_read = file->st_total_read;
|
||||
|
||||
if ((*size = std::min<u64>(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied)))
|
||||
{
|
||||
*addr = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
*addr = 0;
|
||||
}
|
||||
|
||||
// check end of stream
|
||||
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr<u8> addr, u64 size)
|
||||
{
|
||||
cellFs.warning("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size);
|
||||
cellFs.todo("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
// TODO
|
||||
|
||||
const u64 copied = file->st_copied;
|
||||
const u64 total_read = file->st_total_read;
|
||||
|
||||
// notify
|
||||
file->st_copied += size;
|
||||
file->cv.notify_one();
|
||||
|
||||
// check end of stream
|
||||
return total_read < file->st_read_size ? CELL_OK : CELL_FS_ERANGE;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadWait(u32 fd, u64 size)
|
||||
{
|
||||
cellFs.warning("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size);
|
||||
cellFs.todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(file->mutex);
|
||||
|
||||
// wait for size availability or stream end
|
||||
while (file->st_total_read - file->st_copied < size && file->st_total_read < file->st_read_size)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
file->cv.wait_for(lock, 1ms);
|
||||
}
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsStReadWaitCallback(u32 fd, u64 size, fs_st_cb_t func)
|
||||
s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr<void(s32 xfd, u64 xsize)> func)
|
||||
{
|
||||
cellFs.warning("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func);
|
||||
cellFs.todo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (file->st_status == SSS_NOT_INITIALIZED)
|
||||
{
|
||||
return CELL_FS_ENXIO;
|
||||
}
|
||||
|
||||
if (!file->st_callback.compare_and_swap_test({}, { size, func }))
|
||||
{
|
||||
return CELL_FS_EIO;
|
||||
}
|
||||
// TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -831,7 +650,7 @@ s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<vo
|
||||
|
||||
if (flags != CELL_FS_O_RDONLY)
|
||||
{
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({ 0x180, 0x10 }), 8);
|
||||
@ -866,6 +685,12 @@ s32 cellFsSdataOpenByFd(u32 mself_fd, s32 flags, vm::ptr<u32> sdata_fd, u64 offs
|
||||
|
||||
using fs_aio_cb_t = vm::ptr<void(vm::ptr<CellFsAio> xaio, s32 error, s32 xid, u64 size)>;
|
||||
|
||||
// temporarily
|
||||
struct lv2_fs_mount_point
|
||||
{
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
|
||||
{
|
||||
cellFs.notice("FS AIO Request(%d): fd=%d, offset=0x%llx, buf=*0x%x, size=0x%llx, user_data=0x%llx", xid, aio->fd, aio->offset, aio->buf, aio->size, aio->user_data);
|
||||
@ -873,21 +698,21 @@ void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
|
||||
s32 error = CELL_OK;
|
||||
u64 result = 0;
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(aio->fd);
|
||||
const auto file = idm::get<lv2_file>(aio->fd);
|
||||
|
||||
if (!file || (!write && file->flags & CELL_FS_O_WRONLY) || (write && !(file->flags & CELL_FS_O_ACCMODE)))
|
||||
{
|
||||
error = CELL_FS_EBADF;
|
||||
error = CELL_EBADF;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
const auto old_pos = file->file.pos(); file->file.seek(aio->offset);
|
||||
|
||||
result = write
|
||||
? file->file.write(aio->buf.get_ptr(), aio->size)
|
||||
: file->file.read(aio->buf.get_ptr(), aio->size);
|
||||
? file->op_write(aio->buf, aio->size)
|
||||
: file->op_read(aio->buf, aio->size);
|
||||
|
||||
file->file.seek(old_pos);
|
||||
}
|
||||
@ -949,11 +774,11 @@ s32 cellFsAioWrite(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
|
||||
|
||||
s32 cellFsAioCancel(s32 id)
|
||||
{
|
||||
cellFs.warning("cellFsAioCancel(id=%d) -> CELL_FS_EINVAL", id);
|
||||
cellFs.warning("cellFsAioCancel(id=%d) -> CELL_EINVAL", id);
|
||||
|
||||
// TODO: cancelled requests return CELL_FS_ECANCELED through their own callbacks
|
||||
// TODO: cancelled requests return CELL_ECANCELED through their own callbacks
|
||||
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
s32 cellFsSetDefaultContainer(u32 id, u32 total_limit)
|
||||
@ -967,11 +792,11 @@ s32 cellFsSetIoBufferFromDefaultContainer(u32 fd, u32 buffer_size, u32 page_type
|
||||
{
|
||||
cellFs.todo("cellFsSetIoBufferFromDefaultContainer(fd=%d, buffer_size=%d, page_type=%d)", fd, buffer_size, page_type);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -1020,6 +845,7 @@ s32 cellFsChangeFileSizeWithoutAllocation()
|
||||
s32 cellFsAllocateFileAreaWithoutZeroFill(vm::cptr<char> path, u64 size)
|
||||
{
|
||||
cellFs.warning("cellFsAllocateFileAreaWithoutZeroFill(path=*0x%x, size=0x%llx)", path, size);
|
||||
|
||||
return sys_fs_truncate(path, size);
|
||||
}
|
||||
|
||||
@ -1099,7 +925,7 @@ DECLARE(ppu_module_manager::cellFs)("sys_fs", []()
|
||||
REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithInitialData);
|
||||
REG_FUNC(sys_fs, cellFsTruncate2);
|
||||
REG_FUNC(sys_fs, cellFsChangeFileSizeWithoutAllocation);
|
||||
REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill);
|
||||
REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill, MFF_FORCED_HLE);
|
||||
REG_FUNC(sys_fs, cellFsChangeFileSizeByFdWithoutAllocation);
|
||||
REG_FUNC(sys_fs, cellFsSetDiscReadRetrySetting);
|
||||
REG_FUNC(sys_fs, cellFsRegisterConversionCallback);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
#include "Emu/Cell/lv2/sys_fs.h"
|
||||
|
||||
struct CellFsDirectoryEntry
|
||||
{
|
||||
@ -42,7 +42,7 @@ struct CellFsAio
|
||||
{
|
||||
be_t<u32> fd;
|
||||
be_t<u64> offset;
|
||||
vm::bptr<void> buf;
|
||||
vm::bptrb<void> buf;
|
||||
be_t<u64> size;
|
||||
be_t<u64> user_data;
|
||||
};
|
||||
|
@ -61,7 +61,7 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe
|
||||
if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE;
|
||||
|
||||
current_subHandle.fileSize = file_s.size();
|
||||
current_subHandle.fd = idm::make<lv2_file_t>(std::move(file_s), 0, 0);
|
||||
current_subHandle.fd = idm::make<lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf
|
||||
|
||||
case CELL_GIFDEC_FILE:
|
||||
{
|
||||
auto file = idm::get<lv2_file_t>(fd);
|
||||
auto file = idm::get<lv2_file>(fd);
|
||||
file->file.seek(0);
|
||||
file->file.read(buffer, sizeof(buffer));
|
||||
break;
|
||||
@ -181,7 +181,7 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr<u
|
||||
|
||||
case CELL_GIFDEC_FILE:
|
||||
{
|
||||
auto file = idm::get<lv2_file_t>(fd);
|
||||
auto file = idm::get<lv2_file>(fd);
|
||||
file->file.seek(0);
|
||||
file->file.read(gif.get(), fileSize);
|
||||
break;
|
||||
@ -283,7 +283,7 @@ s32 cellGifDecClose(PMainHandle mainHandle, PSubHandle subHandle)
|
||||
{
|
||||
cellGifDec.warning("cellGifDecClose(mainHandle=*0x%x, subHandle=*0x%x)", mainHandle, subHandle);
|
||||
|
||||
idm::remove<lv2_file_t>(subHandle->fd);
|
||||
idm::remove<lv2_file>(subHandle->fd);
|
||||
|
||||
vm::dealloc(subHandle.addr());
|
||||
|
||||
|
@ -51,7 +51,7 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
|
||||
if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE;
|
||||
|
||||
current_subHandle.fileSize = file_s.size();
|
||||
current_subHandle.fd = idm::make<lv2_file_t>(std::move(file_s), 0, 0);
|
||||
current_subHandle.fd = idm::make<lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,7 @@ s32 cellJpgDecClose(u32 mainHandle, u32 subHandle)
|
||||
return CELL_JPGDEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
idm::remove<lv2_file_t>(subHandle_data->fd);
|
||||
idm::remove<lv2_file>(subHandle_data->fd);
|
||||
idm::remove<CellJpgDecSubHandle>(subHandle);
|
||||
|
||||
return CELL_OK;
|
||||
@ -110,7 +110,7 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDecInfo>
|
||||
|
||||
case CELL_JPGDEC_FILE:
|
||||
{
|
||||
auto file = idm::get<lv2_file_t>(fd);
|
||||
auto file = idm::get<lv2_file>(fd);
|
||||
file->file.seek(0);
|
||||
file->file.read(buffer.get(), fileSize);
|
||||
break;
|
||||
@ -189,7 +189,7 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::cp
|
||||
|
||||
case CELL_JPGDEC_FILE:
|
||||
{
|
||||
auto file = idm::get<lv2_file_t>(fd);
|
||||
auto file = idm::get<lv2_file>(fd);
|
||||
file->file.seek(0);
|
||||
file->file.read(jpg.get(), fileSize);
|
||||
break;
|
||||
|
@ -65,7 +65,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length)
|
||||
if (buffer.file)
|
||||
{
|
||||
// Get the file
|
||||
auto file = idm::get<lv2_file_t>(buffer.fd);
|
||||
auto file = idm::get<lv2_file>(buffer.fd);
|
||||
|
||||
// Read the data
|
||||
file->file.read(out, length);
|
||||
@ -364,7 +364,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source,
|
||||
}
|
||||
|
||||
// Get the file descriptor
|
||||
buffer->fd = idm::make<lv2_file_t>(std::move(file_stream), 0, 0);
|
||||
buffer->fd = idm::make<lv2_file>(stream->source.fileName.get_ptr(), std::move(file_stream), 0, 0);
|
||||
|
||||
// Indicate that we need to read from a file stream
|
||||
buffer->file = true;
|
||||
@ -447,7 +447,7 @@ s32 pngDecClose(PPUThread& ppu, PHandle handle, PStream stream)
|
||||
// Remove the file descriptor, if a file descriptor was used for decoding
|
||||
if (stream->buffer->file)
|
||||
{
|
||||
idm::remove<lv2_file_t>(stream->buffer->fd);
|
||||
idm::remove<lv2_file>(stream->buffer->fd);
|
||||
}
|
||||
|
||||
// Deallocate the PNG buffer structure used to decode from memory, if we decoded from memory
|
||||
|
@ -1,24 +1,58 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "sys_fs.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "Emu/VFS.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include <cerrno>
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_fs("sys_fs", logs::level::notice);
|
||||
|
||||
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
|
||||
struct lv2_fs_mount_point
|
||||
{
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
lv2_fs_mount_point g_mp_sys_dev_hdd0;
|
||||
lv2_fs_mount_point g_mp_sys_dev_hdd1;
|
||||
lv2_fs_mount_point g_mp_sys_dev_usb;
|
||||
lv2_fs_mount_point g_mp_sys_dev_bdvd;
|
||||
lv2_fs_mount_point g_mp_sys_app_home;
|
||||
lv2_fs_mount_point g_mp_sys_host_root;
|
||||
|
||||
lv2_fs_mount_point* lv2_fs_object::get_mp(const char* filename)
|
||||
{
|
||||
// TODO
|
||||
return &g_mp_sys_dev_hdd0;
|
||||
}
|
||||
|
||||
u64 lv2_file::op_read(vm::ps3::ptr<void> buf, u64 size)
|
||||
{
|
||||
// Copy data from intermediate buffer (avoid passing vm pointer to a native API)
|
||||
std::unique_ptr<u8[]> local_buf(new u8[size]);
|
||||
const u64 result = file.read(local_buf.get(), size);
|
||||
std::memcpy(buf.get_ptr(), local_buf.get(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 lv2_file::op_write(vm::ps3::cptr<void> buf, u64 size)
|
||||
{
|
||||
// Copy data to intermediate buffer (avoid passing vm pointer to a native API)
|
||||
std::unique_ptr<u8[]> local_buf(new u8[size]);
|
||||
std::memcpy(local_buf.get(), buf.get_ptr(), size);
|
||||
return file.write(local_buf.get(), size);
|
||||
}
|
||||
|
||||
ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
|
||||
{
|
||||
sys_fs.todo("sys_fs_test(arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x, arg5=*0x%x, arg6=0x%x) -> CELL_OK", arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
|
||||
ppu_error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
|
||||
{
|
||||
sys_fs.warning("sys_fs_open(path=*0x%x, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -26,14 +60,15 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
if (!path[0])
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s') failed: path is invalid", path.get_ptr());
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const std::string& local_path = vfs::get(path.get_ptr());
|
||||
|
||||
if (local_path.empty())
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr());
|
||||
return CELL_FS_ENOTMOUNTED;
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
// TODO: other checks for path
|
||||
@ -41,7 +76,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
if (fs::is_dir(local_path))
|
||||
{
|
||||
sys_fs.error("sys_fs_open('%s') failed: path is a directory", path.get_ptr());
|
||||
return CELL_FS_EISDIR;
|
||||
return CELL_EISDIR;
|
||||
}
|
||||
|
||||
bitset_t<fs::open_mode> open_mode{};
|
||||
@ -103,18 +138,18 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
|
||||
if (open_mode & fs::excl)
|
||||
{
|
||||
return CELL_FS_EEXIST; // approximation
|
||||
return CELL_EEXIST; // approximation
|
||||
}
|
||||
|
||||
return CELL_FS_ENOENT;
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
const auto _file = idm::make_ptr<lv2_file_t>(std::move(file), mode, flags);
|
||||
const auto _file = idm::make_ptr<lv2_file>(path.get_ptr(), std::move(file), mode, flags);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
// out of file descriptors
|
||||
return CELL_FS_EMFILE;
|
||||
return CELL_EMFILE;
|
||||
}
|
||||
|
||||
*fd = _file->id;
|
||||
@ -122,7 +157,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
ppu_error_code sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
{
|
||||
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
|
||||
|
||||
@ -131,80 +166,93 @@ s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file || file->flags & CELL_FS_O_WRONLY)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
std::unique_ptr<u8[]> local_buf(new u8[nbytes]);
|
||||
std::memcpy(buf.get_ptr(), local_buf.get(), *nread = file->file.read(local_buf.get(), nbytes));
|
||||
*nread = file->op_read(buf, nbytes);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
ppu_error_code sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
{
|
||||
sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
// TODO: return CELL_FS_EBUSY if locked by stream
|
||||
// TODO: return CELL_EBUSY if locked by stream
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
std::unique_ptr<u8[]> local_buf(new u8[nbytes]);
|
||||
std::memcpy(local_buf.get(), buf.get_ptr(), nbytes);
|
||||
*nwrite = file->file.write(local_buf.get(), nbytes);
|
||||
*nwrite = file->op_write(buf, nbytes);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_close(u32 fd)
|
||||
ppu_error_code sys_fs_close(u32 fd)
|
||||
{
|
||||
sys_fs.trace("sys_fs_close(fd=%d)", fd);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
// TODO: return CELL_FS_EBUSY if locked
|
||||
// TODO: return CELL_EBUSY if locked
|
||||
|
||||
idm::remove<lv2_file_t>(fd);
|
||||
idm::remove<lv2_file>(fd);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
ppu_error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
{
|
||||
sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
|
||||
fs::dir dir(vfs::get(path.get_ptr()));
|
||||
const std::string& local_path = vfs::get(path.get_ptr());
|
||||
|
||||
if (local_path.empty())
|
||||
{
|
||||
sys_fs.error("sys_fs_opendir('%s') failed: device not mounted", path.get_ptr());
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
// TODO: other checks for path
|
||||
|
||||
if (fs::is_file(local_path))
|
||||
{
|
||||
sys_fs.error("sys_fs_opendir('%s') failed: path is a file", path.get_ptr());
|
||||
return CELL_ENOTDIR;
|
||||
}
|
||||
|
||||
fs::dir dir(local_path);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr());
|
||||
return CELL_FS_ENOENT;
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
const auto _dir = idm::make_ptr<lv2_dir_t>(std::move(dir));
|
||||
const auto _dir = idm::make_ptr<lv2_dir>(path.get_ptr(), std::move(dir));
|
||||
|
||||
if (!_dir)
|
||||
{
|
||||
// out of file descriptors
|
||||
return CELL_FS_EMFILE;
|
||||
return CELL_EMFILE;
|
||||
}
|
||||
|
||||
*fd = _dir->id;
|
||||
@ -212,15 +260,15 @@ s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||
ppu_error_code sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||
{
|
||||
sys_fs.warning("sys_fs_readdir(fd=%d, dir=*0x%x, nread=*0x%x)", fd, dir, nread);
|
||||
|
||||
const auto directory = idm::get<lv2_dir_t>(fd);
|
||||
const auto directory = idm::get<lv2_dir>(fd);
|
||||
|
||||
if (!directory)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
fs::dir_entry info;
|
||||
@ -240,23 +288,23 @@ s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_closedir(u32 fd)
|
||||
ppu_error_code sys_fs_closedir(u32 fd)
|
||||
{
|
||||
sys_fs.trace("sys_fs_closedir(fd=%d)", fd);
|
||||
|
||||
const auto directory = idm::get<lv2_dir_t>(fd);
|
||||
const auto directory = idm::get<lv2_dir>(fd);
|
||||
|
||||
if (!directory)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
idm::remove<lv2_dir_t>(fd);
|
||||
idm::remove<lv2_dir>(fd);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
ppu_error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
{
|
||||
sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -266,7 +314,7 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
if (local_path.empty())
|
||||
{
|
||||
sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr());
|
||||
return CELL_FS_ENOTMOUNTED;
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
fs::stat_t info;
|
||||
@ -274,7 +322,7 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
if (!fs::stat(local_path, info))
|
||||
{
|
||||
sys_fs.error("sys_fs_stat('%s') failed: not found", path.get_ptr());
|
||||
return CELL_FS_ENOENT;
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
|
||||
@ -289,18 +337,18 @@ s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
|
||||
ppu_error_code sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
|
||||
{
|
||||
sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
const fs::stat_t& info = file->file.stat();
|
||||
|
||||
@ -316,7 +364,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode)
|
||||
ppu_error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode)
|
||||
{
|
||||
sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -325,19 +373,19 @@ s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode)
|
||||
|
||||
if (fs::is_dir(local_path))
|
||||
{
|
||||
return CELL_FS_EEXIST;
|
||||
return CELL_EEXIST;
|
||||
}
|
||||
|
||||
if (!fs::create_path(local_path))
|
||||
{
|
||||
return CELL_FS_EIO; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_mkdir(): directory '%s' created", path.get_ptr());
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
|
||||
ppu_error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
|
||||
{
|
||||
sys_fs.warning("sys_fs_rename(from=*0x%x, to=*0x%x)", from, to);
|
||||
sys_fs.warning("*** from = '%s'", from.get_ptr());
|
||||
@ -345,14 +393,14 @@ s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
|
||||
|
||||
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
|
||||
{
|
||||
return CELL_FS_ENOENT; // ???
|
||||
return CELL_ENOENT; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_rename(): '%s' renamed to '%s'", from.get_ptr(), to.get_ptr());
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_rmdir(vm::cptr<char> path)
|
||||
ppu_error_code sys_fs_rmdir(vm::cptr<char> path)
|
||||
{
|
||||
sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -361,18 +409,18 @@ s32 sys_fs_rmdir(vm::cptr<char> path)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return CELL_FS_ENOENT;
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error);
|
||||
}
|
||||
|
||||
return CELL_FS_EIO; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_rmdir(): directory '%s' removed", path.get_ptr());
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_unlink(vm::cptr<char> path)
|
||||
ppu_error_code sys_fs_unlink(vm::cptr<char> path)
|
||||
{
|
||||
sys_fs.warning("sys_fs_unlink(path=*0x%x)", path);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -381,57 +429,107 @@ s32 sys_fs_unlink(vm::cptr<char> path)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return CELL_FS_ENOENT;
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_unlink(): unknown error %d", error);
|
||||
}
|
||||
|
||||
return CELL_FS_EIO; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_unlink(): file '%s' deleted", path.get_ptr());
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6)
|
||||
ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
|
||||
{
|
||||
sys_fs.todo("sys_fs_fcntl(fd=0x%x, flags=0x%x, addr=*0x%x, arg4=0x%x, arg5=0x%x, arg6=0x%x) -> CELL_OK", fd, flags, addr, arg4, arg5, arg6);
|
||||
sys_fs.trace("sys_fs_fcntl(fd=%d, op=0x%x, arg=*0x%x, size=0x%x)", fd, op, _arg, _size);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case 0x8000000A: // Read with offset
|
||||
case 0x8000000B: // Write with offset
|
||||
{
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_op_rw>(_arg);
|
||||
|
||||
if (_size < arg.size())
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (op == 0x8000000A && file->flags & CELL_FS_O_WRONLY)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (op == 0x8000000B && !(file->flags & CELL_FS_O_ACCMODE))
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
const u64 old_pos = file->file.pos();
|
||||
const u64 new_pos = file->file.seek(arg->offset);
|
||||
|
||||
arg->out_size = op == 0x8000000A
|
||||
? file->op_read(arg->buf, arg->size)
|
||||
: file->op_write(arg->buf, arg->size);
|
||||
|
||||
VERIFY(old_pos == file->file.seek(old_pos));
|
||||
|
||||
arg->out_code = CELL_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
sys_fs.todo("sys_fs_fcntl(): Unknown operation 0x%08x (fd=%d, arg=*0x%x, size=0x%x)", op, fd, _arg, _size);
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
{
|
||||
sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
|
||||
|
||||
if (whence >= 3)
|
||||
{
|
||||
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
|
||||
return CELL_FS_EINVAL;
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
*pos = file->file.seek(offset, static_cast<fs::seek_mode>(whence));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5)
|
||||
ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5)
|
||||
{
|
||||
sys_fs.todo("sys_fs_fget_block_size(fd=%d, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", fd, sector_size, block_size, arg4, arg5);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
*sector_size = 4096; // ?
|
||||
@ -440,7 +538,7 @@ s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4)
|
||||
ppu_error_code sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4)
|
||||
{
|
||||
sys_fs.todo("sys_fs_get_block_size(path=*0x%x, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", path, sector_size, block_size, arg4);
|
||||
sys_fs.todo("*** path = '%s'", path.get_ptr());
|
||||
@ -451,7 +549,7 @@ s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
|
||||
ppu_error_code sys_fs_truncate(vm::cptr<char> path, u64 size)
|
||||
{
|
||||
sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size);
|
||||
sys_fs.warning("*** path = '%s'", path.get_ptr());
|
||||
@ -460,28 +558,28 @@ s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return CELL_FS_ENOENT;
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_truncate(): unknown error %d", error);
|
||||
}
|
||||
|
||||
return CELL_FS_EIO; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_ftruncate(u32 fd, u64 size)
|
||||
ppu_error_code sys_fs_ftruncate(u32 fd, u64 size)
|
||||
{
|
||||
sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size);
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
const auto file = idm::get<lv2_file>(fd);
|
||||
|
||||
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
|
||||
{
|
||||
return CELL_FS_EBADF;
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(file->mutex);
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
if (!file->file.trunc(size))
|
||||
{
|
||||
@ -491,13 +589,13 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
|
||||
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);
|
||||
}
|
||||
|
||||
return CELL_FS_EIO; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_fs_chmod(vm::cptr<char> path, s32 mode)
|
||||
ppu_error_code sys_fs_chmod(vm::cptr<char> path, s32 mode)
|
||||
{
|
||||
sys_fs.todo("sys_fs_chmod(path=*0x%x, mode=%#o) -> CELL_OK", path, mode);
|
||||
sys_fs.todo("*** path = '%s'", path.get_ptr());
|
||||
|
@ -1,67 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
// Error Codes
|
||||
enum : s32
|
||||
{
|
||||
CELL_FS_EDOM = CELL_EDOM,
|
||||
CELL_FS_EFAULT = CELL_EFAULT,
|
||||
CELL_FS_EFBIG = CELL_EFBIG,
|
||||
CELL_FS_EFPOS = CELL_EFPOS,
|
||||
CELL_FS_EMLINK = CELL_EMLINK,
|
||||
CELL_FS_ENFILE = CELL_ENFILE,
|
||||
CELL_FS_ENOENT = CELL_ENOENT,
|
||||
CELL_FS_ENOSPC = CELL_ENOSPC,
|
||||
CELL_FS_ENOTTY = CELL_ENOTTY,
|
||||
CELL_FS_EPIPE = CELL_EPIPE,
|
||||
CELL_FS_ERANGE = CELL_ERANGE,
|
||||
CELL_FS_EROFS = CELL_EROFS,
|
||||
CELL_FS_ESPIPE = CELL_ESPIPE,
|
||||
CELL_FS_E2BIG = CELL_E2BIG,
|
||||
CELL_FS_EACCES = CELL_EACCES,
|
||||
CELL_FS_EAGAIN = CELL_EAGAIN,
|
||||
CELL_FS_EBADF = CELL_EBADF,
|
||||
CELL_FS_EBUSY = CELL_EBUSY,
|
||||
//CELL_FS_ECHILD = CELL_ECHILD,
|
||||
CELL_FS_EEXIST = CELL_EEXIST,
|
||||
CELL_FS_EINTR = CELL_EINTR,
|
||||
CELL_FS_EINVAL = CELL_EINVAL,
|
||||
CELL_FS_EIO = CELL_EIO,
|
||||
CELL_FS_EISDIR = CELL_EISDIR,
|
||||
CELL_FS_EMFILE = CELL_EMFILE,
|
||||
CELL_FS_ENODEV = CELL_ENODEV,
|
||||
CELL_FS_ENOEXEC = CELL_ENOEXEC,
|
||||
CELL_FS_ENOMEM = CELL_ENOMEM,
|
||||
CELL_FS_ENOTDIR = CELL_ENOTDIR,
|
||||
CELL_FS_ENXIO = CELL_ENXIO,
|
||||
CELL_FS_EPERM = CELL_EPERM,
|
||||
CELL_FS_ESRCH = CELL_ESRCH,
|
||||
CELL_FS_EXDEV = CELL_EXDEV,
|
||||
CELL_FS_EBADMSG = CELL_EBADMSG,
|
||||
CELL_FS_ECANCELED = CELL_ECANCELED,
|
||||
CELL_FS_EDEADLK = CELL_EDEADLK,
|
||||
CELL_FS_EILSEQ = CELL_EILSEQ,
|
||||
CELL_FS_EINPROGRESS = CELL_EINPROGRESS,
|
||||
CELL_FS_EMSGSIZE = CELL_EMSGSIZE,
|
||||
CELL_FS_ENAMETOOLONG = CELL_ENAMETOOLONG,
|
||||
CELL_FS_ENOLCK = CELL_ENOLCK,
|
||||
CELL_FS_ENOSYS = CELL_ENOSYS,
|
||||
CELL_FS_ENOTEMPTY = CELL_ENOTEMPTY,
|
||||
CELL_FS_ENOTSUP = CELL_ENOTSUP,
|
||||
CELL_FS_ETIMEDOUT = CELL_ETIMEDOUT,
|
||||
CELL_FS_EFSSPECIFIC = CELL_EFSSPECIFIC,
|
||||
CELL_FS_EOVERFLOW = CELL_EOVERFLOW,
|
||||
CELL_FS_ENOTMOUNTED = CELL_ENOTMOUNTED,
|
||||
CELL_FS_ENOTMSELF = CELL_ENOTMSELF,
|
||||
CELL_FS_ENOTSDATA = CELL_ENOTSDATA,
|
||||
CELL_FS_EAUTHFATAL = CELL_EAUTHFATAL,
|
||||
};
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
// Open Flags
|
||||
enum : s32
|
||||
@ -92,7 +33,7 @@ enum : s32
|
||||
CELL_FS_MAX_MP_LENGTH = 31,
|
||||
};
|
||||
|
||||
enum CellFsMode : s32
|
||||
enum : s32
|
||||
{
|
||||
CELL_FS_S_IFMT = 0170000,
|
||||
CELL_FS_S_IFDIR = 0040000, // directory
|
||||
@ -151,98 +92,117 @@ struct CellFsUtimbuf
|
||||
|
||||
CHECK_SIZE_ALIGN(CellFsUtimbuf, 16, 4);
|
||||
|
||||
// Stream Support Status (st_status)
|
||||
enum : u32
|
||||
{
|
||||
SSS_NOT_INITIALIZED = 0,
|
||||
SSS_INITIALIZED,
|
||||
SSS_STARTED,
|
||||
SSS_STOPPED,
|
||||
};
|
||||
struct lv2_fs_mount_point;
|
||||
|
||||
using fs_st_cb_t = vm::ptr<void(u32 xfd, u64 xsize)>;
|
||||
|
||||
struct alignas(16) fs_st_cb_rec_t
|
||||
struct lv2_fs_object
|
||||
{
|
||||
u64 size;
|
||||
fs_st_cb_t func;
|
||||
u32 pad;
|
||||
};
|
||||
|
||||
struct lv2_fs_object_t
|
||||
{
|
||||
using id_base = lv2_fs_object_t;
|
||||
// ID Manager setups
|
||||
using id_base = lv2_fs_object;
|
||||
|
||||
static constexpr u32 id_min = 3;
|
||||
static constexpr u32 id_max = 255;
|
||||
|
||||
const id_value<> id{};
|
||||
|
||||
// Mount Point
|
||||
const std::add_pointer_t<lv2_fs_mount_point> mp;
|
||||
|
||||
lv2_fs_object(lv2_fs_mount_point* mp)
|
||||
: mp(mp)
|
||||
{
|
||||
}
|
||||
|
||||
static lv2_fs_mount_point* get_mp(const char* filename);
|
||||
};
|
||||
|
||||
struct lv2_file_t : lv2_fs_object_t
|
||||
struct lv2_file : lv2_fs_object
|
||||
{
|
||||
const fs::file file;
|
||||
const s32 mode;
|
||||
const s32 flags;
|
||||
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
|
||||
atomic_t<u32> st_status;
|
||||
|
||||
u64 st_ringbuf_size;
|
||||
u64 st_block_size;
|
||||
u64 st_trans_rate;
|
||||
bool st_copyless;
|
||||
|
||||
std::shared_ptr<thread_ctrl> st_thread;
|
||||
|
||||
u32 st_buffer;
|
||||
u64 st_read_size;
|
||||
atomic_t<u64> st_total_read;
|
||||
atomic_t<u64> st_copied;
|
||||
|
||||
atomic_t<fs_st_cb_rec_t> st_callback;
|
||||
|
||||
lv2_file_t(fs::file file, s32 mode, s32 flags)
|
||||
: file(std::move(file))
|
||||
lv2_file(const char* filename, fs::file&& file, s32 mode, s32 flags)
|
||||
: lv2_fs_object(lv2_fs_object::get_mp(filename))
|
||||
, file(std::move(file))
|
||||
, mode(mode)
|
||||
, flags(flags)
|
||||
, st_status(SSS_NOT_INITIALIZED)
|
||||
, st_callback(fs_st_cb_rec_t{})
|
||||
{
|
||||
}
|
||||
|
||||
// File reading with intermediate buffer
|
||||
u64 op_read(vm::ps3::ptr<void> buf, u64 size);
|
||||
|
||||
// File writing with intermediate buffer
|
||||
u64 op_write(vm::ps3::cptr<void> buf, u64 size);
|
||||
};
|
||||
|
||||
struct lv2_dir_t : lv2_fs_object_t
|
||||
struct lv2_dir : lv2_fs_object
|
||||
{
|
||||
const fs::dir dir;
|
||||
|
||||
lv2_dir_t(fs::dir dir)
|
||||
: dir(std::move(dir))
|
||||
lv2_dir(const char* filename, fs::dir&& dir)
|
||||
: lv2_fs_object(lv2_fs_object::get_mp(filename))
|
||||
, dir(std::move(dir))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// sys_fs_fcntl arg base class (left empty for PODness)
|
||||
struct lv2_file_op
|
||||
{
|
||||
};
|
||||
|
||||
namespace vtable
|
||||
{
|
||||
struct lv2_file_op
|
||||
{
|
||||
// Speculation
|
||||
vm::bptrb<vm::ptrb<void>(vm::ptrb<lv2_file_op>)> get_data;
|
||||
vm::bptrb<u32(vm::ptrb<lv2_file_op>)> get_size;
|
||||
vm::bptrb<void(vm::ptrb<lv2_file_op>)> _dtor1;
|
||||
vm::bptrb<void(vm::ptrb<lv2_file_op>)> _dtor2;
|
||||
};
|
||||
}
|
||||
|
||||
// sys_fs_fcntl: read with offset, write with offset
|
||||
struct lv2_file_op_rw : lv2_file_op
|
||||
{
|
||||
vm::bptrb<vtable::lv2_file_op> _vtable;
|
||||
|
||||
be_t<u32> op;
|
||||
be_t<u32> _x8; // ???
|
||||
be_t<u32> _xc; // ???
|
||||
|
||||
be_t<u32> fd; // File descriptor (3..255)
|
||||
vm::bptrb<void> buf; // Buffer for data
|
||||
be_t<u64> offset; // File offset
|
||||
be_t<u64> size; // Access size
|
||||
|
||||
be_t<s32> out_code; // Op result
|
||||
be_t<u64> out_size; // Size processed
|
||||
};
|
||||
|
||||
CHECK_SIZE(lv2_file_op_rw, 0x38);
|
||||
|
||||
// SysCalls
|
||||
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6);
|
||||
s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size);
|
||||
s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread);
|
||||
s32 sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite);
|
||||
s32 sys_fs_close(u32 fd);
|
||||
s32 sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd);
|
||||
s32 sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread);
|
||||
s32 sys_fs_closedir(u32 fd);
|
||||
s32 sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb);
|
||||
s32 sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb);
|
||||
s32 sys_fs_mkdir(vm::cptr<char> path, s32 mode);
|
||||
s32 sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to);
|
||||
s32 sys_fs_rmdir(vm::cptr<char> path);
|
||||
s32 sys_fs_unlink(vm::cptr<char> path);
|
||||
s32 sys_fs_fcntl(u32 fd, s32 flags, u32 addr, u32 arg4, u32 arg5, u32 arg6);
|
||||
s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos);
|
||||
s32 sys_fs_fget_block_size(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4, vm::ptr<u64> arg5);
|
||||
s32 sys_fs_get_block_size(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size, vm::ptr<u64> arg4);
|
||||
s32 sys_fs_truncate(vm::cptr<char> path, u64 size);
|
||||
s32 sys_fs_ftruncate(u32 fd, u64 size);
|
||||
s32 sys_fs_chmod(vm::cptr<char> path, s32 mode);
|
||||
ppu_error_code sys_fs_test(u32 arg1, u32 arg2, vm::ps3::ptr<u32> arg3, u32 arg4, vm::ps3::ptr<char> arg5, u32 arg6);
|
||||
ppu_error_code sys_fs_open(vm::ps3::cptr<char> path, s32 flags, vm::ps3::ptr<u32> fd, s32 mode, vm::ps3::cptr<void> arg, u64 size);
|
||||
ppu_error_code sys_fs_read(u32 fd, vm::ps3::ptr<void> buf, u64 nbytes, vm::ps3::ptr<u64> nread);
|
||||
ppu_error_code sys_fs_write(u32 fd, vm::ps3::cptr<void> buf, u64 nbytes, vm::ps3::ptr<u64> nwrite);
|
||||
ppu_error_code sys_fs_close(u32 fd);
|
||||
ppu_error_code sys_fs_opendir(vm::ps3::cptr<char> path, vm::ps3::ptr<u32> fd);
|
||||
ppu_error_code sys_fs_readdir(u32 fd, vm::ps3::ptr<CellFsDirent> dir, vm::ps3::ptr<u64> nread);
|
||||
ppu_error_code sys_fs_closedir(u32 fd);
|
||||
ppu_error_code sys_fs_stat(vm::ps3::cptr<char> path, vm::ps3::ptr<CellFsStat> sb);
|
||||
ppu_error_code sys_fs_fstat(u32 fd, vm::ps3::ptr<CellFsStat> sb);
|
||||
ppu_error_code sys_fs_mkdir(vm::ps3::cptr<char> path, s32 mode);
|
||||
ppu_error_code sys_fs_rename(vm::ps3::cptr<char> from, vm::ps3::cptr<char> to);
|
||||
ppu_error_code sys_fs_rmdir(vm::ps3::cptr<char> path);
|
||||
ppu_error_code sys_fs_unlink(vm::ps3::cptr<char> path);
|
||||
ppu_error_code sys_fs_fcntl(u32 fd, u32 op, vm::ps3::ptr<void> arg, u32 size);
|
||||
ppu_error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ps3::ptr<u64> pos);
|
||||
ppu_error_code sys_fs_fget_block_size(u32 fd, vm::ps3::ptr<u64> sector_size, vm::ps3::ptr<u64> block_size, vm::ps3::ptr<u64> arg4, vm::ps3::ptr<u64> arg5);
|
||||
ppu_error_code sys_fs_get_block_size(vm::ps3::cptr<char> path, vm::ps3::ptr<u64> sector_size, vm::ps3::ptr<u64> block_size, vm::ps3::ptr<u64> arg4);
|
||||
ppu_error_code sys_fs_truncate(vm::ps3::cptr<char> path, u64 size);
|
||||
ppu_error_code sys_fs_ftruncate(u32 fd, u64 size);
|
||||
ppu_error_code sys_fs_chmod(vm::ps3::cptr<char> path, s32 mode);
|
||||
|
@ -89,7 +89,7 @@ s32 sys_process_get_number_of_object(u32 object, vm::ptr<u32> nump)
|
||||
case SYS_LWMUTEX_OBJECT: *nump = idm::get_count<lv2_lwmutex_t>(); break;
|
||||
case SYS_TIMER_OBJECT: *nump = idm::get_count<lv2_timer_t>(); break;
|
||||
case SYS_SEMAPHORE_OBJECT: *nump = idm::get_count<lv2_sema_t>(); break;
|
||||
case SYS_FS_FD_OBJECT: *nump = idm::get_count<lv2_fs_object_t>(); break;
|
||||
case SYS_FS_FD_OBJECT: *nump = idm::get_count<lv2_fs_object>(); break;
|
||||
case SYS_LWCOND_OBJECT: *nump = idm::get_count<lv2_lwcond_t>(); break;
|
||||
case SYS_EVENT_FLAG_OBJECT: *nump = idm::get_count<lv2_event_flag_t>(); break;
|
||||
|
||||
@ -136,7 +136,7 @@ s32 sys_process_get_id(u32 object, vm::ptr<u32> buffer, u32 size, vm::ptr<u32> s
|
||||
case SYS_LWMUTEX_OBJECT: idm_get_set<lv2_lwmutex_t>(objects); break;
|
||||
case SYS_TIMER_OBJECT: idm_get_set<lv2_timer_t>(objects); break;
|
||||
case SYS_SEMAPHORE_OBJECT: idm_get_set<lv2_sema_t>(objects); break;
|
||||
case SYS_FS_FD_OBJECT: idm_get_set<lv2_fs_object_t>(objects); break;
|
||||
case SYS_FS_FD_OBJECT: idm_get_set<lv2_fs_object>(objects); break;
|
||||
case SYS_LWCOND_OBJECT: idm_get_set<lv2_lwcond_t>(objects); break;
|
||||
case SYS_EVENT_FLAG_OBJECT: idm_get_set<lv2_event_flag_t>(objects); break;
|
||||
|
||||
|
@ -28,10 +28,17 @@
|
||||
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
|
||||
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
|
||||
|
||||
std::string g_cfg_defaults;
|
||||
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
|
||||
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
|
||||
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
|
||||
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
|
||||
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
|
||||
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
|
||||
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
|
||||
|
||||
extern cfg::string_entry g_cfg_vfs_dev_bdvd;
|
||||
extern cfg::string_entry g_cfg_vfs_app_home;
|
||||
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true);
|
||||
|
||||
std::string g_cfg_defaults;
|
||||
|
||||
extern atomic_t<u32> g_thread_count;
|
||||
|
||||
@ -124,6 +131,22 @@ bool Emulator::BootGame(const std::string& path, bool direct)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Emulator::GetGameDir()
|
||||
{
|
||||
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
||||
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
||||
|
||||
return fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
|
||||
}
|
||||
|
||||
std::string Emulator::GetLibDir()
|
||||
{
|
||||
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
||||
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
||||
|
||||
return fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
|
||||
}
|
||||
|
||||
void Emulator::Load()
|
||||
{
|
||||
Stop();
|
||||
@ -208,33 +231,49 @@ void Emulator::Load()
|
||||
|
||||
LOG_NOTICE(LOADER, "Title: %s", GetTitle());
|
||||
LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
|
||||
LOG_NOTICE(LOADER, "");
|
||||
|
||||
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
|
||||
// Mount all devices
|
||||
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
||||
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
||||
const std::string& bdvd_dir = g_cfg_vfs_dev_bdvd;
|
||||
const std::string& home_dir = g_cfg_vfs_app_home;
|
||||
|
||||
// Mount /dev_bdvd/
|
||||
if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
|
||||
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir));
|
||||
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir));
|
||||
vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir));
|
||||
vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
|
||||
vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
|
||||
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
|
||||
|
||||
// Mount /dev_bdvd/ if necessary
|
||||
if (bdvd_dir.empty() && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
|
||||
{
|
||||
const auto dir_list = fmt::split(elf_dir, { "/", "\\" });
|
||||
|
||||
// Check latest two directories
|
||||
if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
|
||||
{
|
||||
g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15);
|
||||
vfs::mount("dev_bdvd", elf_dir.substr(0, elf_dir.length() - 15));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_cfg_vfs_dev_bdvd = elf_dir + "/../../";
|
||||
vfs::mount("dev_bdvd", elf_dir + "/../../");
|
||||
}
|
||||
}
|
||||
|
||||
// Mount /app_home/
|
||||
if (g_cfg_vfs_app_home.size() == 0)
|
||||
LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
|
||||
}
|
||||
else if (bdvd_dir.size())
|
||||
{
|
||||
g_cfg_vfs_app_home = elf_dir + '/';
|
||||
vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
|
||||
}
|
||||
|
||||
vfs::dump();
|
||||
// Mount /host_root/ if necessary
|
||||
if (g_cfg_vfs_allow_host_root)
|
||||
{
|
||||
vfs::mount("host_root", {});
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
|
||||
|
||||
ppu_load_exec(ppu_exec);
|
||||
|
||||
|
@ -172,6 +172,9 @@ public:
|
||||
|
||||
bool BootGame(const std::string& path, bool direct = false);
|
||||
|
||||
static std::string GetGameDir();
|
||||
static std::string GetLibDir();
|
||||
|
||||
void Load();
|
||||
void Run();
|
||||
bool Pause();
|
||||
|
@ -1,79 +1,51 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "IdManager.h"
|
||||
#include "VFS.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include <regex>
|
||||
|
||||
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
|
||||
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
|
||||
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
|
||||
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
|
||||
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
|
||||
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
|
||||
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
|
||||
|
||||
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true);
|
||||
|
||||
void vfs::dump()
|
||||
struct vfs_manager
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Mount info:");
|
||||
LOG_NOTICE(LOADER, "/dev_hdd0/ -> %s", g_cfg_vfs_dev_hdd0.get());
|
||||
LOG_NOTICE(LOADER, "/dev_hdd1/ -> %s", g_cfg_vfs_dev_hdd1.get());
|
||||
LOG_NOTICE(LOADER, "/dev_flash/ -> %s", g_cfg_vfs_dev_flash.get());
|
||||
LOG_NOTICE(LOADER, "/dev_usb/ -> %s", g_cfg_vfs_dev_usb000.get());
|
||||
LOG_NOTICE(LOADER, "/dev_usb000/ -> %s", g_cfg_vfs_dev_usb000.get());
|
||||
if (g_cfg_vfs_dev_bdvd.size()) LOG_NOTICE(LOADER, "/dev_bdvd/ -> %s", g_cfg_vfs_dev_bdvd.get());
|
||||
if (g_cfg_vfs_app_home.size()) LOG_NOTICE(LOADER, "/app_home/ -> %s", g_cfg_vfs_app_home.get());
|
||||
if (g_cfg_vfs_allow_host_root) LOG_NOTICE(LOADER, "/host_root/ -> .");
|
||||
LOG_NOTICE(LOADER, "");
|
||||
shared_mutex mutex;
|
||||
|
||||
// Device name -> Real path
|
||||
std::unordered_map<std::string, std::string> mounted;
|
||||
};
|
||||
|
||||
const std::regex s_regex_ps3("^/+(.*?)(?:$|/)(.*)", std::regex::optimize);
|
||||
const std::regex s_regex_psv("^(.*?):(.*)", std::regex::optimize);
|
||||
|
||||
bool vfs::mount(const std::string& dev_name, const std::string& path)
|
||||
{
|
||||
const auto table = fxm::get_always<vfs_manager>();
|
||||
|
||||
writer_lock lock(table->mutex);
|
||||
|
||||
return table->mounted.emplace(dev_name, path).second;
|
||||
}
|
||||
|
||||
std::string vfs::get(const std::string& vpath)
|
||||
std::string vfs::get(const std::string& vpath, vfs::type _type)
|
||||
{
|
||||
const cfg::string_entry* vdir = nullptr;
|
||||
std::size_t f_pos = vpath.find_first_not_of('/');
|
||||
std::size_t start = 0;
|
||||
std::smatch match;
|
||||
|
||||
// Compare vpath with device name
|
||||
auto detect = [&](const auto& vdev) -> bool
|
||||
if (!std::regex_match(vpath, match, _type == type::ps3 ? s_regex_ps3 : s_regex_psv))
|
||||
{
|
||||
const std::size_t size = ::size32(vdev) - 1; // Char array size
|
||||
|
||||
if (f_pos && f_pos != -1 && vpath.compare(f_pos - 1, size, vdev, size) == 0)
|
||||
{
|
||||
start = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (g_cfg_vfs_allow_host_root && detect("/host_root/"))
|
||||
return vpath.substr(start); // Accessing host FS directly
|
||||
else if (detect("/dev_hdd0/"))
|
||||
vdir = &g_cfg_vfs_dev_hdd0;
|
||||
else if (detect("/dev_hdd1/"))
|
||||
vdir = &g_cfg_vfs_dev_hdd1;
|
||||
else if (detect("/dev_flash/"))
|
||||
vdir = &g_cfg_vfs_dev_flash;
|
||||
else if (detect("/dev_usb000/"))
|
||||
vdir = &g_cfg_vfs_dev_usb000;
|
||||
else if (detect("/dev_usb/"))
|
||||
vdir = &g_cfg_vfs_dev_usb000;
|
||||
else if (detect("/dev_bdvd/"))
|
||||
vdir = &g_cfg_vfs_dev_bdvd;
|
||||
else if (detect("/app_home/"))
|
||||
vdir = &g_cfg_vfs_app_home;
|
||||
|
||||
// Return empty path if not mounted
|
||||
if (!vdir || !start)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "vfs::get() failed for %s", vpath);
|
||||
LOG_WARNING(GENERAL, "vfs::get(): invalid input: %s", vpath);
|
||||
return{};
|
||||
}
|
||||
|
||||
// Replace $(EmulatorDir), concatenate
|
||||
return fmt::replace_all(*vdir, "$(EmulatorDir)", g_cfg_vfs_emulator_dir.size() == 0 ? fs::get_executable_dir() : g_cfg_vfs_emulator_dir) + vpath.substr(start);
|
||||
const auto table = fxm::get_always<vfs_manager>();
|
||||
|
||||
reader_lock lock(table->mutex);
|
||||
|
||||
const auto found = table->mounted.find(match.str(1));
|
||||
|
||||
if (found == table->mounted.end())
|
||||
{
|
||||
LOG_WARNING(GENERAL, "vfs::get(): device not found: %s", vpath);
|
||||
return{};
|
||||
}
|
||||
|
||||
// Concatenate
|
||||
return found->second + match.str(2);
|
||||
}
|
||||
|
@ -2,9 +2,16 @@
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
// Print mounted directories
|
||||
void dump();
|
||||
// VFS type
|
||||
enum class type
|
||||
{
|
||||
ps3,
|
||||
psv,
|
||||
};
|
||||
|
||||
// Convert PS3/PSV path to fs-compatible path
|
||||
std::string get(const std::string& vpath);
|
||||
// Mount VFS device
|
||||
bool mount(const std::string& dev_name, const std::string& path);
|
||||
|
||||
// Convert VFS path to fs path
|
||||
std::string get(const std::string& vpath, type _type = type::ps3);
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ GameViewer::GameViewer(wxWindow* parent) : wxListView(parent)
|
||||
|
||||
m_sortColumn = 1;
|
||||
m_sortAscending = true;
|
||||
m_path = "/dev_hdd0/game/";
|
||||
m_popup = new wxMenu();
|
||||
|
||||
Bind(wxEVT_LIST_ITEM_ACTIVATED, &GameViewer::DClick, this);
|
||||
@ -80,7 +79,7 @@ void GameViewer::LoadGames()
|
||||
{
|
||||
m_games.clear();
|
||||
|
||||
for (const auto& entry : fs::dir(vfs::get(m_path)))
|
||||
for (const auto& entry : fs::dir(Emu.GetGameDir()))
|
||||
{
|
||||
if (entry.is_directory)
|
||||
{
|
||||
@ -93,10 +92,13 @@ void GameViewer::LoadPSF()
|
||||
{
|
||||
m_game_data.clear();
|
||||
|
||||
const std::string& game_path = Emu.GetGameDir();
|
||||
|
||||
for (u32 i = 0; i < m_games.size(); ++i)
|
||||
{
|
||||
const std::string sfb = vfs::get(m_path) + m_games[i] + "/PS3_DISC.SFB";
|
||||
const std::string sfo = vfs::get(m_path) + m_games[i] + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
|
||||
const std::string& dir = game_path + m_games[i];
|
||||
const std::string& sfb = dir + "/PS3_DISC.SFB";
|
||||
const std::string& sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
|
||||
|
||||
const fs::file sfo_file(sfo);
|
||||
if (!sfo_file)
|
||||
@ -125,27 +127,27 @@ void GameViewer::LoadPSF()
|
||||
if (game.category == "HG")
|
||||
{
|
||||
game.category = "HDD Game";
|
||||
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
|
||||
game.icon_path = dir + "/ICON0.PNG";
|
||||
}
|
||||
else if (game.category == "DG")
|
||||
{
|
||||
game.category = "Disc Game";
|
||||
game.icon_path = vfs::get(m_path) + m_games[i] + "/PS3_GAME/ICON0.PNG";
|
||||
game.icon_path = dir + "/PS3_GAME/ICON0.PNG";
|
||||
}
|
||||
else if (game.category == "HM")
|
||||
{
|
||||
game.category = "Home";
|
||||
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
|
||||
game.icon_path = dir + "/ICON0.PNG";
|
||||
}
|
||||
else if (game.category == "AV")
|
||||
{
|
||||
game.category = "Audio/Video";
|
||||
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
|
||||
game.icon_path = dir + "/ICON0.PNG";
|
||||
}
|
||||
else if (game.category == "GD")
|
||||
{
|
||||
game.category = "Game Data";
|
||||
game.icon_path = vfs::get(m_path) + m_games[i] + "/ICON0.PNG";
|
||||
game.icon_path = dir + "/ICON0.PNG";
|
||||
}
|
||||
|
||||
m_game_data.push_back(game);
|
||||
@ -183,13 +185,13 @@ void GameViewer::DClick(wxListEvent& event)
|
||||
long i = GetFirstSelected();
|
||||
if (i < 0) return;
|
||||
|
||||
const std::string& path = m_path + m_game_data[i].root;
|
||||
const std::string& path = Emu.GetGameDir() + m_game_data[i].root;
|
||||
|
||||
Emu.Stop();
|
||||
|
||||
if (!Emu.BootGame(vfs::get(path)))
|
||||
if (!Emu.BootGame(path))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to boot %s", path);
|
||||
LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].root);
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +240,7 @@ void GameViewer::RemoveGame(wxCommandEvent& event)
|
||||
|
||||
if (wxMessageBox("Permanently delete game files?", "Confirm Delete", wxYES_NO | wxNO_DEFAULT) == wxYES)
|
||||
{
|
||||
fs::remove_all(vfs::get(m_path) + this->GetItemText(i, 6).ToStdString());
|
||||
fs::remove_all(Emu.GetGameDir() + this->GetItemText(i, 6).ToStdString());
|
||||
}
|
||||
|
||||
Refresh();
|
||||
|
@ -63,7 +63,6 @@ class GameViewer : public wxListView
|
||||
{
|
||||
int m_sortColumn;
|
||||
bool m_sortAscending;
|
||||
std::string m_path;
|
||||
std::vector<std::string> m_games;
|
||||
std::vector<GameInfo> m_game_data;
|
||||
ColumnsArr m_columns;
|
||||
|
@ -253,7 +253,7 @@ void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event))
|
||||
pkg_f.seek(0);
|
||||
|
||||
// Get full path
|
||||
const auto& local_path = vfs::get("/dev_hdd0/game/") + std::string(std::begin(title_id), std::end(title_id));
|
||||
const auto& local_path = Emu.GetGameDir() + std::string(std::begin(title_id), std::end(title_id));
|
||||
|
||||
if (!fs::create_dir(local_path))
|
||||
{
|
||||
|
@ -332,7 +332,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent)
|
||||
chbox_list_core_lle->Check(chbox_list_core_lle->Append(unk));
|
||||
}
|
||||
|
||||
const std::string& lle_dir = vfs::get("/dev_flash/sys/external/"); // TODO
|
||||
const std::string& lle_dir = Emu.GetLibDir(); // TODO
|
||||
|
||||
std::unordered_set<std::string> set(data.begin(), data.end());
|
||||
std::vector<std::string> lle_module_list_unselected;
|
||||
|
Loading…
x
Reference in New Issue
Block a user