1
0
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:
Nekotekina 2016-06-02 18:16:01 +03:00
parent 59433bfcd5
commit 438e057dc8
19 changed files with 598 additions and 638 deletions

View File

@ -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);
}
}

View File

@ -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;
}
}
}
};

View File

@ -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>

View File

@ -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);

View File

@ -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;
};

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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))
{

View File

@ -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;