rpcsx/rpcs3/Emu/Cell/lv2/sys_fs.cpp

595 lines
13 KiB
C++
Raw Normal View History

2015-03-12 20:02:02 +01:00
#include "stdafx.h"
#include "sys_fs.h"
2016-06-02 17:16:01 +02:00
#include <mutex>
#include "Emu/VFS.h"
#include "Utilities/StrUtil.h"
2016-06-02 17:16:01 +02:00
namespace vm { using namespace ps3; }
2016-05-13 15:55:34 +02:00
logs::channel sys_fs("sys_fs", logs::level::notice);
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
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);
}
error_code sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
2015-03-15 01:41:08 +01:00
{
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);
2015-03-15 01:41:08 +01:00
return CELL_OK;
}
error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
2015-03-12 20:02:02 +01:00
2015-04-21 17:16:29 +02:00
if (!path[0])
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_open(%s) failed: path is invalid", path);
2016-06-02 17:16:01 +02:00
return CELL_EINVAL;
2015-04-21 17:16:29 +02:00
}
2016-04-14 00:23:53 +02:00
const std::string& local_path = vfs::get(path.get_ptr());
2016-06-02 17:16:01 +02:00
2016-04-14 00:23:53 +02:00
if (local_path.empty())
2015-04-21 17:16:29 +02:00
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_open(%s) failed: device not mounted", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOTMOUNTED;
2015-04-21 17:16:29 +02:00
}
2015-03-13 16:06:27 +01:00
// TODO: other checks for path
2015-04-24 23:38:11 +02:00
if (fs::is_dir(local_path))
2015-03-13 16:06:27 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_open(%s) failed: path is a directory", path);
2016-06-02 17:16:01 +02:00
return CELL_EISDIR;
2015-03-13 16:06:27 +01:00
}
2015-03-12 20:02:02 +01:00
2016-08-07 21:01:27 +02:00
bs_t<fs::open_mode> open_mode{};
2015-03-13 21:43:11 +01:00
2015-04-19 15:19:24 +02:00
switch (flags & CELL_FS_O_ACCMODE)
2015-03-13 21:43:11 +01:00
{
2016-04-14 00:23:53 +02:00
case CELL_FS_O_RDONLY: open_mode += fs::read; break;
case CELL_FS_O_WRONLY: open_mode += fs::write; break;
case CELL_FS_O_RDWR: open_mode += fs::read + fs::write; break;
2015-03-13 21:43:11 +01:00
}
2015-04-19 15:19:24 +02:00
if (flags & CELL_FS_O_CREAT)
2015-03-13 21:43:11 +01:00
{
2016-04-14 00:23:53 +02:00
open_mode += fs::create;
2015-03-13 21:43:11 +01:00
}
2015-04-19 15:19:24 +02:00
if (flags & CELL_FS_O_TRUNC)
2015-03-13 21:43:11 +01:00
{
2016-04-14 00:23:53 +02:00
open_mode += fs::trunc;
2015-03-13 21:43:11 +01:00
}
2015-03-12 20:02:02 +01:00
if (flags & CELL_FS_O_APPEND)
{
2016-04-14 00:23:53 +02:00
open_mode += fs::append;
}
2015-04-19 15:19:24 +02:00
if (flags & CELL_FS_O_EXCL)
2015-03-13 16:06:27 +01:00
{
2015-04-20 17:53:31 +02:00
if (flags & CELL_FS_O_CREAT)
2015-03-12 20:02:02 +01:00
{
2016-04-14 00:23:53 +02:00
open_mode += fs::excl;
2015-04-19 15:19:24 +02:00
}
else
{
2016-04-14 00:23:53 +02:00
open_mode = {}; // error
2015-03-12 20:02:02 +01:00
}
2015-03-13 16:06:27 +01:00
}
2015-03-13 21:43:11 +01:00
if (flags & ~(CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL))
2015-03-13 16:06:27 +01:00
{
2016-04-14 00:23:53 +02:00
open_mode = {}; // error
2015-03-13 16:06:27 +01:00
}
2015-03-12 20:02:02 +01:00
2015-04-19 15:19:24 +02:00
if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE)
2015-03-13 16:06:27 +01:00
{
2016-04-14 00:23:53 +02:00
open_mode = {}; // error
2015-03-12 20:02:02 +01:00
}
2015-03-13 21:43:11 +01:00
2016-08-07 21:01:27 +02:00
if (!test(open_mode))
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
fmt::throw_exception("sys_fs_open(%s): Invalid or unimplemented flags: %#o" HERE, path, flags);
2015-03-13 16:06:27 +01:00
}
2015-04-19 15:19:24 +02:00
2016-04-14 00:23:53 +02:00
fs::file file(local_path, open_mode);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!file)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_open(%s): failed to open file (flags=%#o, mode=%#o)", path, flags, mode);
2015-04-20 17:53:31 +02:00
2016-08-07 21:01:27 +02:00
if (test(open_mode & fs::excl))
2015-04-20 17:53:31 +02:00
{
2016-06-02 17:16:01 +02:00
return CELL_EEXIST; // approximation
2015-04-20 17:53:31 +02:00
}
2016-06-02 17:16:01 +02:00
return CELL_ENOENT;
2015-03-12 20:02:02 +01:00
}
2017-01-26 02:12:50 +01:00
const auto _file = idm::make_ptr<lv2_fs_object, lv2_file>(path.get_ptr(), std::move(file), mode, flags);
if (!_file)
{
// out of file descriptors
2016-06-02 17:16:01 +02:00
return CELL_EMFILE;
}
2016-04-14 00:23:53 +02:00
*fd = _file->id;
return CELL_OK;
2015-03-12 20:02:02 +01:00
}
error_code sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
2015-03-12 20:02:02 +01:00
{
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
if (!buf)
{
return CELL_EFAULT;
}
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-12 20:02:02 +01:00
2015-04-12 03:36:25 +02:00
if (!file || file->flags & CELL_FS_O_WRONLY)
2015-03-13 16:06:27 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-13 16:06:27 +01:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
std::lock_guard<std::mutex> lock(file->mp->mutex);
2015-03-16 01:21:40 +01:00
2016-06-02 17:16:01 +02:00
*nread = file->op_read(buf, nbytes);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_write(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
2015-03-12 20:02:02 +01:00
{
sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-12 20:02:02 +01:00
2015-04-12 03:36:25 +02:00
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
2015-03-13 16:06:27 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-13 16:06:27 +01:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
// TODO: return CELL_EBUSY if locked by stream
2015-03-16 01:21:40 +01:00
2016-06-02 17:16:01 +02:00
std::lock_guard<std::mutex> lock(file->mp->mutex);
2015-03-13 23:05:48 +01:00
2016-06-02 17:16:01 +02:00
*nwrite = file->op_write(buf, nbytes);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_close(u32 fd)
2015-03-12 20:02:02 +01:00
{
sys_fs.trace("sys_fs_close(fd=%d)", fd);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-13 16:06:27 +01:00
2015-04-12 03:36:25 +02:00
if (!file)
2015-03-13 16:06:27 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-13 16:06:27 +01:00
}
2016-06-02 17:16:01 +02:00
// TODO: return CELL_EBUSY if locked
2015-03-13 16:06:27 +01:00
2017-01-26 02:12:50 +01:00
idm::remove<lv2_fs_object, lv2_file>(fd);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_opendir(path=%s, fd=*0x%x)", path, fd);
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
const std::string& local_path = vfs::get(path.get_ptr());
if (local_path.empty())
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_opendir(%s) failed: device not mounted", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOTMOUNTED;
}
// TODO: other checks for path
if (fs::is_file(local_path))
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_opendir(%s) failed: path is a file", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOTDIR;
}
fs::dir dir(local_path);
2015-03-13 16:06:27 +01:00
2016-04-14 00:23:53 +02:00
if (!dir)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_opendir(%s): failed to open directory", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOENT;
2015-03-12 20:02:02 +01:00
}
2017-01-26 02:12:50 +01:00
const auto _dir = idm::make_ptr<lv2_fs_object, lv2_dir>(path.get_ptr(), std::move(dir));
if (!_dir)
{
// out of file descriptors
2016-06-02 17:16:01 +02:00
return CELL_EMFILE;
}
2016-04-14 00:23:53 +02:00
*fd = _dir->id;
2016-08-18 12:27:20 +02:00
sys_fs.notice("sys_fs_opendir(%s) -> lv2_fs_id %d", path, _dir->id);
return CELL_OK;
2015-03-12 20:02:02 +01:00
}
error_code sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
2015-03-12 20:02:02 +01:00
{
sys_fs.warning("sys_fs_readdir(fd=%d, dir=*0x%x, nread=*0x%x)", fd, dir, nread);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto directory = idm::get<lv2_fs_object, lv2_dir>(fd);
2015-03-13 16:06:27 +01:00
2015-04-12 03:36:25 +02:00
if (!directory)
2015-03-13 16:06:27 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-13 16:06:27 +01:00
}
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
fs::dir_entry info;
2015-03-13 16:06:27 +01:00
2016-04-14 00:23:53 +02:00
if (directory->dir.read(info))
2015-03-12 20:02:02 +01:00
{
2016-04-14 00:23:53 +02:00
dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
dir->d_namlen = u8(std::min<size_t>(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(dir->d_name, info.name);
2015-03-12 20:02:02 +01:00
*nread = sizeof(CellFsDirent);
}
else
{
*nread = 0;
}
return CELL_OK;
}
error_code sys_fs_closedir(u32 fd)
2015-03-12 20:02:02 +01:00
{
2016-08-18 12:27:20 +02:00
sys_fs.warning("sys_fs_closedir(fd=%d)", fd);
2015-03-13 16:06:27 +01:00
2017-01-26 02:12:50 +01:00
const auto directory = idm::get<lv2_fs_object, lv2_dir>(fd);
2015-03-12 20:02:02 +01:00
2015-04-12 03:36:25 +02:00
if (!directory)
2015-03-13 16:06:27 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-13 16:06:27 +01:00
}
2017-01-26 02:12:50 +01:00
idm::remove<lv2_fs_object, lv2_dir>(fd);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_stat(path=%s, sb=*0x%x)", path, sb);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
const std::string& local_path = vfs::get(path.get_ptr());
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (local_path.empty())
2015-04-21 17:16:29 +02:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_stat(%s) failed: not mounted", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOTMOUNTED;
2015-04-21 17:16:29 +02:00
}
2015-03-12 20:02:02 +01:00
2015-04-24 23:38:11 +02:00
fs::stat_t info;
2015-03-12 20:02:02 +01:00
2015-04-25 21:15:53 +02:00
if (!fs::stat(local_path, info))
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.error("sys_fs_stat(%s) failed: not found", path);
2016-06-02 17:16:01 +02:00
return CELL_ENOENT;
2015-03-12 20:02:02 +01:00
}
2015-04-24 23:38:11 +02:00
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
2015-04-19 18:02:35 +02:00
sb->uid = 1; // ???
sb->gid = 1; // ???
sb->atime = info.atime;
sb->mtime = info.mtime;
sb->ctime = info.ctime;
sb->size = info.size;
2015-04-21 20:18:15 +02:00
sb->blksize = 4096; // ???
2015-03-12 20:02:02 +01:00
2015-04-19 18:02:35 +02:00
return CELL_OK;
2015-03-12 20:02:02 +01:00
}
error_code sys_fs_fstat(u32 fd, vm::ptr<CellFsStat> sb)
2015-03-12 20:02:02 +01:00
{
sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-16 17:20:02 +01:00
2015-04-12 03:36:25 +02:00
if (!file)
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
std::lock_guard<std::mutex> lock(file->mp->mutex);
2015-04-19 19:57:04 +02:00
2016-04-14 00:23:53 +02:00
const fs::stat_t& info = file->file.stat();
2015-04-19 19:57:04 +02:00
2015-04-24 23:38:11 +02:00
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
2015-04-19 18:02:35 +02:00
sb->uid = 1; // ???
sb->gid = 1; // ???
2015-04-19 19:57:04 +02:00
sb->atime = info.atime;
sb->mtime = info.mtime;
2015-04-21 20:18:15 +02:00
sb->ctime = info.ctime; // ctime may be incorrect
2015-04-19 19:57:04 +02:00
sb->size = info.size;
2015-04-21 20:18:15 +02:00
sb->blksize = 4096; // ???
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_mkdir(path=%s, mode=%#o)", path, mode);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
const std::string& local_path = vfs::get(path.get_ptr());
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (fs::is_dir(local_path))
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EEXIST;
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!fs::create_path(local_path))
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EIO; // ???
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
2016-08-11 01:29:59 +02:00
sys_fs.notice("sys_fs_mkdir(): directory %s created", path);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
2015-03-12 20:02:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_ENOENT; // ???
2015-03-12 20:02:02 +01:00
}
2016-08-11 01:29:59 +02:00
sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to);
return CELL_OK;
2015-03-12 20:02:02 +01:00
}
error_code sys_fs_rmdir(vm::cptr<char> path)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_rmdir(path=%s)", path);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!fs::remove_dir(vfs::get(path.get_ptr())))
2015-03-16 17:20:02 +01:00
{
2016-05-13 15:55:34 +02:00
switch (auto error = fs::g_tls_error)
2016-04-14 00:23:53 +02:00
{
2016-06-02 17:16:01 +02:00
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_rmdir(): unknown error %s", error);
2016-04-14 00:23:53 +02:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
return CELL_EIO; // ???
2015-04-20 17:53:31 +02:00
}
2016-08-11 01:29:59 +02:00
sys_fs.notice("sys_fs_rmdir(): directory %s removed", path);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_unlink(vm::cptr<char> path)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_unlink(path=%s)", path);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!fs::remove_file(vfs::get(path.get_ptr())))
2015-03-16 17:20:02 +01:00
{
2016-05-13 15:55:34 +02:00
switch (auto error = fs::g_tls_error)
2016-04-14 00:23:53 +02:00
{
2016-06-02 17:16:01 +02:00
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_unlink(): unknown error %s", error);
2016-04-14 00:23:53 +02:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
return CELL_EIO; // ???
2015-04-20 17:53:31 +02:00
}
2016-08-11 01:29:59 +02:00
sys_fs.notice("sys_fs_unlink(): file %s deleted", path);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
2015-03-15 01:41:08 +01:00
{
2016-06-02 17:16:01 +02:00
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;
}
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2016-06-02 17:16:01 +02:00
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);
2016-08-15 02:11:49 +02:00
verify(HERE), old_pos == file->file.seek(old_pos);
2016-06-02 17:16:01 +02:00
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);
}
}
2015-03-15 01:41:08 +01:00
return CELL_OK;
}
error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
2015-03-12 20:02:02 +01:00
{
sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
2015-03-12 20:02:02 +01:00
2015-04-19 15:19:24 +02:00
if (whence >= 3)
2015-03-12 20:02:02 +01:00
{
2016-04-14 00:23:53 +02:00
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
2016-06-02 17:16:01 +02:00
return CELL_EINVAL;
2015-03-12 20:02:02 +01:00
}
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-16 17:20:02 +01:00
2015-04-12 03:36:25 +02:00
if (!file)
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
std::lock_guard<std::mutex> lock(file->mp->mutex);
2015-03-16 17:20:02 +01:00
2016-04-14 00:23:53 +02:00
*pos = file->file.seek(offset, static_cast<fs::seek_mode>(whence));
2015-03-16 17:20:02 +01:00
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
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)
2015-03-12 20:02:02 +01:00
{
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);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-16 17:20:02 +01:00
2015-04-12 03:36:25 +02:00
if (!file)
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
*sector_size = 4096; // ?
*block_size = 4096; // ?
return CELL_OK;
}
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)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.todo("sys_fs_get_block_size(path=%s, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, arg5=*0x%x)", path, sector_size, block_size, arg4);
2015-03-12 20:02:02 +01:00
*sector_size = 4096; // ?
*block_size = 4096; // ?
return CELL_OK;
}
error_code sys_fs_truncate(vm::cptr<char> path, u64 size)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.warning("sys_fs_truncate(path=%s, size=0x%llx)", path, size);
2015-03-12 20:02:02 +01:00
2016-04-14 00:23:53 +02:00
if (!fs::truncate_file(vfs::get(path.get_ptr()), size))
2015-03-12 20:02:02 +01:00
{
2016-05-13 15:55:34 +02:00
switch (auto error = fs::g_tls_error)
2016-04-14 00:23:53 +02:00
{
2016-06-02 17:16:01 +02:00
case fs::error::noent: return CELL_ENOENT;
default: sys_fs.error("sys_fs_truncate(): unknown error %s", error);
2016-04-14 00:23:53 +02:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
return CELL_EIO; // ???
2015-03-12 20:02:02 +01:00
}
return CELL_OK;
}
error_code sys_fs_ftruncate(u32 fd, u64 size)
2015-03-12 20:02:02 +01:00
{
sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size);
2015-03-12 20:02:02 +01:00
2017-01-26 02:12:50 +01:00
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
2015-03-16 17:20:02 +01:00
if (!file || !(file->flags & CELL_FS_O_ACCMODE))
2015-03-16 17:20:02 +01:00
{
2016-06-02 17:16:01 +02:00
return CELL_EBADF;
2015-03-16 17:20:02 +01:00
}
2015-03-12 20:02:02 +01:00
2016-06-02 17:16:01 +02:00
std::lock_guard<std::mutex> lock(file->mp->mutex);
2015-04-12 03:36:25 +02:00
2016-04-14 00:23:53 +02:00
if (!file->file.trunc(size))
{
2016-05-13 15:55:34 +02:00
switch (auto error = fs::g_tls_error)
2016-04-14 00:23:53 +02:00
{
2016-05-13 15:55:34 +02:00
case fs::error::ok:
default: sys_fs.error("sys_fs_ftruncate(): unknown error %s", error);
2016-04-14 00:23:53 +02:00
}
2016-06-02 17:16:01 +02:00
return CELL_EIO; // ???
}
2015-03-12 20:02:02 +01:00
return CELL_OK;
}
error_code sys_fs_chmod(vm::cptr<char> path, s32 mode)
2015-03-12 20:02:02 +01:00
{
2016-08-11 01:29:59 +02:00
sys_fs.todo("sys_fs_chmod(path=%s, mode=%#o) -> CELL_OK", path, mode);
2015-03-12 20:02:02 +01:00
return CELL_OK;
}