2018-11-03 21:56:57 +01:00
# include " stdafx.h "
2019-03-08 17:07:14 +01:00
# include "sys_sync.h"
2015-03-12 20:02:02 +01:00
# include "sys_fs.h"
2016-06-02 17:16:01 +02:00
# include <mutex>
2017-03-07 01:59:05 +01:00
# include "Emu/Cell/PPUThread.h"
# include "Crypto/unedat.h"
2016-06-02 17:16:01 +02:00
# include "Emu/VFS.h"
2017-02-04 16:09:02 +01:00
# include "Emu/IdManager.h"
2016-04-27 00:27:24 +02:00
# include "Utilities/StrUtil.h"
2016-06-02 17:16:01 +02:00
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( sys_fs ) ;
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 ;
2017-03-07 01:59:05 +01:00
bool verify_mself ( u32 fd , fs : : file const & mself_file )
{
FsMselfHeader mself_header ;
if ( ! mself_file . read < FsMselfHeader > ( mself_header ) )
{
sys_fs . error ( " verify_mself: Didn't read expected bytes for header. " ) ;
return false ;
}
if ( mself_header . m_magic ! = 0x4D534600 )
{
sys_fs . error ( " verify_mself: Header magic is incorrect. " ) ;
return false ;
}
if ( mself_header . m_format_version ! = 1 )
{
sys_fs . error ( " verify_mself: Unexpected header format version. " ) ;
return false ;
}
// sanity check
if ( mself_header . m_entry_size ! = sizeof ( FsMselfEntry ) )
{
sys_fs . error ( " verify_mself: Unexpected header entry size. " ) ;
return false ;
}
2017-12-23 20:18:55 +01:00
mself_file . seek ( 0 ) ;
2017-03-07 01:59:05 +01:00
return true ;
}
2016-06-02 17:16:01 +02:00
lv2_fs_mount_point * lv2_fs_object : : get_mp ( const char * filename )
{
// TODO
return & g_mp_sys_dev_hdd0 ;
}
2018-02-09 15:49:37 +01:00
u64 lv2_file : : op_read ( vm : : ptr < void > buf , u64 size )
2016-06-02 17:16:01 +02:00
{
// 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 ;
}
2018-02-09 15:49:37 +01:00
u64 lv2_file : : op_write ( vm : : cptr < void > buf , u64 size )
2016-06-02 17:16:01 +02:00
{
// 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 ) ;
}
2017-03-04 12:54:53 +01:00
struct lv2_file : : file_view : fs : : file_base
{
const std : : shared_ptr < lv2_file > m_file ;
const u64 m_off ;
u64 m_pos ;
explicit file_view ( const std : : shared_ptr < lv2_file > & _file , u64 offset )
: m_file ( _file )
, m_off ( offset )
, m_pos ( 0 )
{
}
~ file_view ( ) override
{
}
fs : : stat_t stat ( ) override
{
return m_file - > file . stat ( ) ;
}
bool trunc ( u64 length ) override
{
return false ;
}
u64 read ( void * buffer , u64 size ) override
{
const u64 old_pos = m_file - > file . pos ( ) ;
const u64 new_pos = m_file - > file . seek ( m_off + m_pos ) ;
const u64 result = m_file - > file . read ( buffer , size ) ;
verify ( HERE ) , old_pos = = m_file - > file . seek ( old_pos ) ;
m_pos + = result ;
return result ;
}
u64 write ( const void * buffer , u64 size ) override
{
return 0 ;
}
u64 seek ( s64 offset , fs : : seek_mode whence ) override
{
2017-03-23 19:32:59 +01:00
const s64 new_pos =
whence = = fs : : seek_set ? offset :
whence = = fs : : seek_cur ? offset + m_pos :
whence = = fs : : seek_end ? offset + size ( ) :
2017-03-04 12:54:53 +01:00
( fmt : : raw_error ( " lv2_file::file_view::seek(): invalid whence " ) , 0 ) ;
2017-03-23 19:32:59 +01:00
if ( new_pos < 0 )
{
fs : : g_tls_error = fs : : error : : inval ;
return - 1 ;
}
m_pos = new_pos ;
return m_pos ;
2017-03-04 12:54:53 +01:00
}
u64 size ( ) override
{
2017-03-10 10:06:36 +01:00
return m_file - > file . size ( ) ;
2017-03-04 12:54:53 +01:00
}
} ;
fs : : file lv2_file : : make_view ( const std : : shared_ptr < lv2_file > & _file , u64 offset )
{
fs : : file result ;
result . reset ( std : : make_unique < lv2_file : : file_view > ( _file , offset ) ) ;
return result ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_test ( ppu_thread & ppu , u32 arg1 , u32 arg2 , vm : : ptr < u32 > arg3 , u32 arg4 , vm : : ptr < char > buf , u32 buf_size )
2015-03-15 01:41:08 +01:00
{
2017-04-24 18:49:53 +02:00
sys_fs . trace ( " sys_fs_test(arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x, buf=*0x%x, buf_size=0x%x) " , arg1 , arg2 , arg3 , arg4 , buf , buf_size ) ;
2015-03-15 01:41:08 +01:00
2017-04-24 18:49:53 +02:00
if ( arg1 ! = 6 | | arg2 ! = 0 | | arg4 ! = sizeof ( u32 ) )
{
sys_fs . todo ( " sys_fs_test: unknown arguments (arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x) " , arg1 , arg2 , arg3 , arg4 ) ;
}
if ( ! arg3 )
{
return CELL_EFAULT ;
}
const auto file = idm : : get < lv2_fs_object > ( * arg3 ) ;
if ( ! file )
{
return CELL_EBADF ;
}
for ( u32 i = 0 ; i < buf_size ; i + + )
{
if ( ! ( buf [ i ] = file - > name [ i ] ) )
{
return CELL_OK ;
}
}
buf [ buf_size - 1 ] = 0 ;
2015-03-15 01:41:08 +01:00
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_open ( ppu_thread & ppu , 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
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
2015-04-21 17:16:29 +02:00
if ( ! path [ 0 ] )
2018-03-21 20:02:36 +01:00
return CELL_ENOENT ;
2015-04-21 17:16:29 +02:00
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
{
return { CELL_EISDIR , path } ;
}
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
{
2017-08-08 21:13:48 +02:00
return { CELL_ENOTMOUNTED , path } ;
2015-04-21 17:16:29 +02:00
}
2015-03-13 16:06:27 +01:00
// TODO: other checks for path
2018-09-11 18:02:19 +02:00
if ( fs : : is_dir ( local_path ) )
2015-03-13 16:06:27 +01:00
{
2017-08-08 21:13:48 +02:00
return { CELL_EISDIR , path } ;
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 ;
2018-11-23 17:38:24 +01:00
if ( flags & CELL_FS_O_EXCL )
{
open_mode + = fs : : excl ;
}
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
2015-06-18 13:55:11 +02:00
if ( flags & CELL_FS_O_APPEND )
{
2016-04-14 00:23:53 +02:00
open_mode + = fs : : append ;
2015-06-18 13:55:11 +02:00
}
2017-03-07 01:59:05 +01:00
if ( flags & CELL_FS_O_MSELF )
{
open_mode = fs : : read ;
// mself can be mself or mself | rdonly
if ( flags & ~ ( CELL_FS_O_MSELF | CELL_FS_O_RDONLY ) )
{
open_mode = { } ;
}
}
2018-02-14 18:06:46 +01:00
if ( flags & CELL_FS_O_UNK )
2015-03-13 16:06:27 +01:00
{
2018-02-14 18:06:46 +01:00
sys_fs . warning ( " sys_fs_open called with CELL_FS_O_UNK flag enabled. FLAGS: %#o " , flags ) ;
}
// Tests have shown that invalid combinations get resolved internally (without exceptions), but that would complicate code with minimal accuracy gains.
// For example, no games are known to try and call TRUNCATE | APPEND | RW, or APPEND | READ, which currently would cause an exception.
if ( flags & ~ ( CELL_FS_O_UNK | CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL | CELL_FS_O_MSELF ) )
2018-03-21 20:02:36 +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
2018-09-02 19:22:35 +02:00
if ( ! 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
2018-08-13 00:06:34 +02:00
if ( ! file & & open_mode = = fs : : read & & fs : : g_tls_error = = fs : : error : : noent )
{
// Try to gather split file (TODO)
std : : vector < fs : : file > fragments ;
for ( u32 i = 66600 ; i < = 66699 ; i + + )
{
if ( fs : : file fragment { fmt : : format ( " %s.%u " , local_path , i ) } )
{
fragments . emplace_back ( std : : move ( fragment ) ) ;
}
else
{
break ;
}
}
if ( ! fragments . empty ( ) )
{
file = fs : : make_gather ( std : : move ( fragments ) ) ;
}
}
2016-04-14 00:23:53 +02:00
if ( ! file )
2015-03-12 20:02:02 +01:00
{
2018-09-02 19:22:35 +02:00
if ( open_mode & fs : : excl & & fs : : g_tls_error = = fs : : error : : exist )
2015-04-20 17:53:31 +02:00
{
2017-09-08 16:17:03 +02:00
return not_an_error ( CELL_EEXIST ) ;
2015-04-20 17:53:31 +02:00
}
2017-09-08 16:17:03 +02:00
switch ( auto error = fs : : g_tls_error )
{
case fs : : error : : noent : return { CELL_ENOENT , path } ;
default : sys_fs . error ( " sys_fs_open(): unknown error %s " , error ) ;
}
return { CELL_EIO , path } ;
2015-03-12 20:02:02 +01:00
}
2017-03-07 01:59:05 +01:00
if ( ( flags & CELL_FS_O_MSELF ) & & ( ! verify_mself ( * fd , file ) ) )
2017-08-08 21:13:48 +02:00
{
return { CELL_ENOTMSELF , path } ;
}
const auto casted_arg = vm : : static_ptr_cast < const u64 > ( arg ) ;
2017-03-07 01:59:05 +01:00
2017-03-10 10:06:36 +01:00
if ( size = = 8 )
2017-03-07 01:59:05 +01:00
{
2017-12-16 01:03:49 +01:00
// check for sdata
2017-03-10 10:06:36 +01:00
if ( * casted_arg = = 0x18000000010 )
2017-03-07 01:59:05 +01:00
{
2017-03-10 10:06:36 +01:00
// check if the file has the NPD header, or else assume its not encrypted
u32 magic ;
file . read < u32 > ( magic ) ;
file . seek ( 0 ) ;
if ( magic = = " NPD \0 " _u32 )
2017-03-07 01:59:05 +01:00
{
2017-03-10 10:06:36 +01:00
auto sdata_file = std : : make_unique < EDATADecrypter > ( std : : move ( file ) ) ;
if ( ! sdata_file - > ReadHeader ( ) )
{
2017-08-08 21:13:48 +02:00
return { CELL_EFSSPECIFIC , path } ;
2017-03-10 10:06:36 +01:00
}
file . reset ( std : : move ( sdata_file ) ) ;
}
}
2017-12-16 01:03:49 +01:00
// edata
2017-03-10 10:06:36 +01:00
else if ( * casted_arg = = 0x2 )
{
// check if the file has the NPD header, or else assume its not encrypted
u32 magic ;
file . read < u32 > ( magic ) ;
file . seek ( 0 ) ;
if ( magic = = " NPD \0 " _u32 )
{
2017-03-22 12:13:20 +01:00
auto edatkeys = fxm : : get_always < LoadedNpdrmKeys_t > ( ) ;
2017-03-10 10:06:36 +01:00
auto sdata_file = std : : make_unique < EDATADecrypter > ( std : : move ( file ) , edatkeys - > devKlic , edatkeys - > rifKey ) ;
if ( ! sdata_file - > ReadHeader ( ) )
{
2017-08-08 21:13:48 +02:00
return { CELL_EFSSPECIFIC , path } ;
2017-03-10 10:06:36 +01:00
}
file . reset ( std : : move ( sdata_file ) ) ;
2017-03-07 01:59:05 +01:00
}
}
}
2017-08-08 21:13:48 +02:00
2017-02-04 16:09:02 +01:00
if ( const u32 id = idm : : make < lv2_fs_object , lv2_file > ( path . get_ptr ( ) , std : : move ( file ) , mode , flags ) )
2015-08-11 18:14:53 +02:00
{
2017-02-04 16:09:02 +01:00
* fd = id ;
return CELL_OK ;
2015-07-28 23:34:22 +02:00
}
2017-02-04 16:09:02 +01:00
// Out of file descriptors
2017-08-08 21:13:48 +02:00
return { CELL_EMFILE , path } ;
2015-03-12 20:02:02 +01:00
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_read ( ppu_thread & ppu , u32 fd , vm : : ptr < void > buf , u64 nbytes , vm : : ptr < u64 > nread )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-04-09 11:45:45 +02: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
2018-09-03 21:28:33 +02:00
std : : lock_guard 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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_write ( ppu_thread & ppu , u32 fd , vm : : cptr < void > buf , u64 nbytes , vm : : ptr < u64 > nwrite )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +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
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2015-03-13 23:05:48 +01:00
2017-04-24 22:30:15 +02:00
if ( file - > lock )
{
return CELL_EBUSY ;
}
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_close ( ppu_thread & ppu , u32 fd )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +01:00
sys_fs . trace ( " sys_fs_close(fd=%d) " , fd ) ;
2015-03-12 20:02:02 +01:00
2017-04-24 22:30:15 +02:00
const auto file = idm : : withdraw < lv2_fs_object , lv2_file > ( fd , [ ] ( lv2_file & file ) - > CellError
{
if ( file . lock )
{
return CELL_EBUSY ;
}
return { } ;
} ) ;
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
}
2017-04-24 22:30:15 +02:00
if ( file . ret )
{
return file . ret ;
}
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_opendir ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < u32 > fd )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-15 16:04:35 +02:00
std : : vector < std : : string > ext ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
2018-09-15 16:04:35 +02:00
const std : : string local_path = vfs : : get ( vpath , & ext ) ;
2018-09-11 18:02:19 +02:00
2018-09-15 16:04:35 +02:00
if ( local_path . empty ( ) & & ext . empty ( ) )
2016-06-02 17:16:01 +02:00
{
2017-08-08 21:13:48 +02:00
return { CELL_ENOTMOUNTED , path } ;
2016-06-02 17:16:01 +02:00
}
// TODO: other checks for path
if ( fs : : is_file ( local_path ) )
{
2017-08-08 21:13:48 +02:00
return { CELL_ENOTDIR , path } ;
2016-06-02 17:16:01 +02:00
}
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
{
2017-09-08 16:17:03 +02:00
switch ( auto error = fs : : g_tls_error )
{
2018-09-15 16:04:35 +02:00
case fs : : error : : noent :
{
if ( ext . empty ( ) )
{
return { CELL_ENOENT , path } ;
}
break ;
}
default :
{
sys_fs . error ( " sys_fs_opendir(): unknown error %s " , error ) ;
return { CELL_EIO , path } ;
2017-09-08 16:17:03 +02:00
}
2018-09-15 16:04:35 +02:00
}
}
2017-09-08 16:17:03 +02:00
2018-09-15 16:04:35 +02:00
// Build directory as a vector of entries
std : : vector < fs : : dir_entry > data ;
if ( dir )
{
// Add real directories
while ( dir . read ( data . emplace_back ( ) ) )
{
// Preprocess entries
data . back ( ) . name = vfs : : unescape ( data . back ( ) . name ) ;
// Add additional entries for split file candidates (while ends with .66600)
while ( data . back ( ) . name . size ( ) > = 6 & & data . back ( ) . name . compare ( data . back ( ) . name . size ( ) - 6 , 6 , " .66600 " , 6 ) = = 0 )
{
data . emplace_back ( data . back ( ) ) . name . resize ( data . back ( ) . name . size ( ) - 6 ) ;
}
}
data . resize ( data . size ( ) - 1 ) ;
}
else
{
data . emplace_back ( ) . name = " . " ;
data . back ( ) . is_directory = true ;
data . emplace_back ( ) . name = " .. " ;
data . back ( ) . is_directory = true ;
2015-03-12 20:02:02 +01:00
}
2018-09-15 16:04:35 +02:00
// Add mount points (TODO)
for ( auto & & ex : ext )
{
data . emplace_back ( ) . name = std : : move ( ex ) ;
data . back ( ) . is_directory = true ;
}
// Sort files, keeping . and ..
std : : stable_sort ( data . begin ( ) + 2 , data . end ( ) , [ ] ( const fs : : dir_entry & a , const fs : : dir_entry & b )
{
return a . name < b . name ;
} ) ;
// Remove duplicates
const auto last = std : : unique ( data . begin ( ) , data . end ( ) , [ ] ( const fs : : dir_entry & a , const fs : : dir_entry & b )
{
return a . name = = b . name ;
} ) ;
data . erase ( last , data . end ( ) ) ;
if ( const u32 id = idm : : make < lv2_fs_object , lv2_dir > ( path . get_ptr ( ) , std : : move ( data ) ) )
2015-08-11 18:14:53 +02:00
{
2017-02-04 16:09:02 +01:00
* fd = id ;
return CELL_OK ;
2015-07-28 23:34:22 +02:00
}
2017-02-04 16:09:02 +01:00
// Out of file descriptors
return CELL_EMFILE ;
2015-03-12 20:02:02 +01:00
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_readdir ( ppu_thread & ppu , u32 fd , vm : : ptr < CellFsDirent > dir , vm : : ptr < u64 > nread )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +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
2018-09-15 16:04:35 +02:00
if ( auto * info = directory - > dir_read ( ) )
2015-03-12 20:02:02 +01:00
{
2018-09-15 16:04:35 +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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_closedir ( ppu_thread & ppu , u32 fd )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_stat ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < CellFsStat > sb )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2017-12-16 01:03:49 +01:00
if ( ! path )
return CELL_EFAULT ;
2018-03-21 20:02:36 +01:00
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
{
* sb = { CELL_FS_S_IFDIR | 0444 } ;
return CELL_OK ;
}
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
{
2017-08-08 21:13:48 +02:00
return { CELL_ENOTMOUNTED , path } ;
2015-04-21 17:16:29 +02:00
}
2015-03-12 20:02:02 +01:00
2017-09-18 23:03:26 +02:00
fs : : stat_t info { } ;
2015-04-25 21:15:53 +02:00
if ( ! fs : : stat ( local_path , info ) )
2015-03-12 20:02:02 +01:00
{
2017-09-08 16:17:03 +02:00
switch ( auto error = fs : : g_tls_error )
{
2018-08-26 23:38:21 +02:00
case fs : : error : : noent :
{
// Try to analyse split file (TODO)
u64 total_size = 0 ;
u32 total_count = 0 ;
2017-09-08 16:17:03 +02:00
2018-08-26 23:38:21 +02:00
for ( u32 i = 66600 ; i < = 66699 ; i + + )
{
if ( fs : : stat ( fmt : : format ( " %s.%u " , local_path , i ) , info ) & & ! info . is_directory )
{
total_size + = info . size ;
total_count + + ;
}
else
{
break ;
}
}
// Use attributes from the first fragment (consistently with sys_fs_open+fstat)
if ( total_count > 1 & & fs : : stat ( local_path + " .66600 " , info ) & & ! info . is_directory )
{
// Success
info . size = total_size ;
break ;
}
return { CELL_ENOENT , path } ;
}
default :
{
sys_fs . error ( " sys_fs_stat(): unknown error %s " , error ) ;
return { CELL_EIO , path } ;
}
}
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 ;
2017-02-08 15:27:13 +01:00
sb - > uid = 0 ; // Always zero
sb - > gid = 0 ; // Always zero
2015-04-19 18:02:35 +02:00
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
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_fstat ( ppu_thread & ppu , u32 fd , vm : : ptr < CellFsStat > sb )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +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
2018-09-03 21:28:33 +02:00
std : : lock_guard 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 ;
2017-02-08 15:27:13 +01:00
sb - > uid = 0 ; // Always zero
sb - > gid = 0 ; // Always zero
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_link ( ppu_thread & ppu , vm : : cptr < char > from , vm : : cptr < char > to )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_link(from=%s, to=%s) " , from , to ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_mkdir ( ppu_thread & ppu , vm : : cptr < char > path , s32 mode )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EEXIST , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
2018-11-11 10:54:32 +01:00
if ( ! fs : : create_dir ( local_path ) )
2015-03-16 17:20:02 +01:00
{
2017-09-08 16:17:03 +02:00
switch ( auto error = fs : : g_tls_error )
{
2017-09-18 22:04:11 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2017-09-08 16:17:03 +02:00
case fs : : error : : exist : return { CELL_EEXIST , path } ;
default : sys_fs . error ( " sys_fs_mkdir(): unknown error %s " , error ) ;
}
2015-03-12 20:02:02 +01:00
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_rename ( ppu_thread & ppu , vm : : cptr < char > from , vm : : cptr < char > to )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-09-11 18:02:19 +02:00
const std : : string_view vfrom = from . get_ptr ( ) ;
const std : : string local_from = vfs : : get ( vfrom ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
const std : : string_view vto = to . get_ptr ( ) ;
const std : : string local_to = vfs : : get ( vto ) ;
if ( vfrom . find_first_not_of ( ' / ' ) = = - 1 | | vto . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return CELL_EPERM ;
2017-09-18 23:03:26 +02:00
}
2017-12-16 01:03:49 +01:00
2018-09-11 18:02:19 +02:00
if ( local_from . empty ( ) | | local_to . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return CELL_ENOTMOUNTED ;
2017-09-18 23:03:26 +02:00
}
2019-04-07 11:58:08 +02:00
if ( ! vfs : : host : : rename ( local_from , local_to , false ) )
2015-03-12 20:02:02 +01:00
{
2017-08-30 16:14:30 +02:00
switch ( auto error = fs : : g_tls_error )
{
case fs : : error : : noent : return { CELL_ENOENT , from } ;
case fs : : error : : exist : return { CELL_EEXIST , to } ;
default : sys_fs . error ( " sys_fs_rename(): unknown error %s " , error ) ;
}
return { CELL_EIO , from } ; // ???
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 ) ;
2015-08-08 15:17:28 +02:00
return CELL_OK ;
2015-03-12 20:02:02 +01:00
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_rmdir ( ppu_thread & ppu , vm : : cptr < char > path )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EPERM , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
if ( ! fs : : remove_dir ( local_path ) )
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
{
2017-08-08 21:13:48 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2017-09-12 19:05:38 +02:00
case fs : : error : : notempty : return { CELL_ENOTEMPTY , path } ;
2016-07-21 00:00:31 +02:00
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
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_unlink ( ppu_thread & ppu , vm : : cptr < char > path )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
2017-12-16 01:03:49 +01:00
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EISDIR , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
2019-04-12 11:24:36 +02:00
if ( fs : : is_dir ( local_path ) )
{
return { CELL_EISDIR , path } ;
}
2019-04-07 23:53:56 +02:00
if ( ! vfs : : host : : unlink ( local_path ) )
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
{
2017-08-08 21:13:48 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2016-07-21 00:00:31 +02:00
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
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_access ( ppu_thread & ppu , vm : : cptr < char > path , s32 mode )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_access(path=%s, mode=%#o) " , path , mode ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_fcntl ( ppu_thread & ppu , 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 )
{
2017-04-26 14:48:50 +02:00
case 0x80000006 : // cellFsAllocateFileAreaByFdWithInitialData
{
break ;
}
case 0x80000007 : // cellFsAllocateFileAreaByFdWithoutZeroFill
{
break ;
}
case 0x80000008 : // cellFsChangeFileSizeByFdWithoutAllocation
{
break ;
}
case 0x8000000a : // cellFsReadWithOffset
case 0x8000000b : // cellFsWriteWithOffset
2016-06-02 17:16:01 +02:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-06-02 17:16:01 +02:00
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 ;
}
2017-04-26 14:48:50 +02:00
if ( op = = 0x8000000a & & file - > flags & CELL_FS_O_WRONLY )
2016-06-02 17:16:01 +02:00
{
return CELL_EBADF ;
}
2017-04-26 14:48:50 +02:00
if ( op = = 0x8000000b & & ! ( file - > flags & CELL_FS_O_ACCMODE ) )
2016-06-02 17:16:01 +02:00
{
return CELL_EBADF ;
}
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2016-06-02 17:16:01 +02:00
2017-04-26 14:48:50 +02:00
if ( op = = 0x8000000b & & file - > lock )
2017-04-24 22:30:15 +02:00
{
return CELL_EBUSY ;
}
2016-06-02 17:16:01 +02:00
const u64 old_pos = file - > file . pos ( ) ;
const u64 new_pos = file - > file . seek ( arg - > offset ) ;
2017-04-26 14:48:50 +02:00
arg - > out_size = op = = 0x8000000a
2016-06-02 17:16:01 +02:00
? 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 ;
2017-04-26 14:48:50 +02:00
return CELL_OK ;
2016-06-02 17:16:01 +02:00
}
2017-03-04 12:54:53 +01:00
case 0x80000009 : // cellFsSdataOpenByFd
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-03-04 12:54:53 +01:00
const auto arg = vm : : static_ptr_cast < lv2_file_op_09 > ( _arg ) ;
if ( _size < arg . size ( ) )
{
return CELL_EINVAL ;
}
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
if ( ! file )
{
return CELL_EBADF ;
}
2017-03-10 10:06:36 +01:00
auto sdata_file = std : : make_unique < EDATADecrypter > ( lv2_file : : make_view ( file , arg - > offset ) ) ;
2017-03-07 01:59:05 +01:00
if ( ! sdata_file - > ReadHeader ( ) )
{
return CELL_EFSSPECIFIC ;
}
fs : : file stream ;
stream . reset ( std : : move ( sdata_file ) ) ;
2017-04-24 18:49:53 +02:00
if ( const u32 id = idm : : make < lv2_fs_object , lv2_file > ( * file , std : : move ( stream ) , file - > mode , file - > flags ) )
2017-03-04 12:54:53 +01:00
{
arg - > out_code = CELL_OK ;
arg - > out_fd = id ;
return CELL_OK ;
}
// Out of file descriptors
return CELL_EMFILE ;
}
2017-04-25 02:13:45 +02:00
case 0xc0000002 : // cellFsGetFreeSize (TODO)
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-04-25 02:13:45 +02:00
const auto arg = vm : : static_ptr_cast < lv2_file_c0000002 > ( _arg ) ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = arg - > path . get_ptr ( ) ;
2018-12-10 12:40:59 +01:00
const std : : size_t non_slash = vpath . find_first_not_of ( ' / ' ) ;
2017-09-18 23:03:26 +02:00
2018-12-10 12:40:59 +01:00
if ( non_slash = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EPERM , vpath } ;
2017-09-18 23:03:26 +02:00
}
2018-11-03 21:56:57 +01:00
// Extract device from path
2018-12-10 12:40:59 +01:00
const std : : string_view device_path = vpath . substr ( 0 , vpath . find_first_of ( ' / ' , non_slash ) ) ;
2018-11-03 21:56:57 +01:00
const std : : string local_path = vfs : : get ( device_path ) ;
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , vpath } ;
2017-09-18 23:03:26 +02:00
}
2017-04-25 02:13:45 +02:00
fs : : device_stat info ;
2017-09-18 23:03:26 +02:00
if ( ! fs : : statfs ( local_path , info ) )
2017-04-25 02:13:45 +02:00
{
2017-09-08 16:17:03 +02:00
switch ( auto error = fs : : g_tls_error )
{
2018-09-11 18:02:19 +02:00
case fs : : error : : noent : return { CELL_ENOENT , vpath } ;
2017-09-08 16:17:03 +02:00
default : sys_fs . error ( " sys_fs_fcntl(0xc0000002): unknown error %s " , error ) ;
}
2017-04-25 02:13:45 +02:00
return CELL_EIO ; // ???
}
arg - > out_code = CELL_OK ;
arg - > out_block_size = 4096 ;
arg - > out_block_count = info . avail_free / 4096 ;
return CELL_OK ;
}
2017-04-22 15:01:24 +02:00
case 0xc0000006 : // Unknown
{
const auto arg = vm : : static_ptr_cast < lv2_file_c0000006 > ( _arg ) ;
sys_fs . warning ( " 0xc0000006: 0x%x, 0x%x, 0x%x, %s, 0x%x, 0x%x, 0x%x " , arg - > size , arg - > _x4 , arg - > _x8 , arg - > name , arg - > _x14 , arg - > _x18 , arg - > _x1c ) ;
return CELL_OK ;
}
2017-04-26 14:48:50 +02:00
case 0xc0000007 : // cellFsArcadeHddSerialNumber
{
break ;
}
case 0xc0000008 : // cellFsSetDefaultContainer, cellFsSetIoBuffer, cellFsSetIoBufferFromDefaultContainer
{
break ;
}
case 0xc0000015 : // Unknown
{
break ;
}
case 0xc0000016 : // ps2disc_8160A811
{
break ;
}
case 0xc000001a : // cellFsSetDiscReadRetrySetting, 5731DF45
{
break ;
}
case 0xc0000021 : // 9FDBBA89
{
break ;
}
case 0xe0000000 : // Unknown (cellFsGetBlockSize)
{
break ;
}
2017-05-07 00:08:44 +02:00
case 0xe0000001 : // Unknown (cellFsStat)
2017-04-26 14:48:50 +02:00
{
break ;
}
case 0xe0000003 : // Unknown
{
break ;
}
case 0xe0000004 : // Unknown
{
break ;
}
case 0xe0000005 : // Unknown (cellFsMkdir)
{
break ;
}
case 0xe0000006 : // Unknown
{
break ;
}
case 0xe0000007 : // Unknown
{
break ;
}
case 0xe0000008 : // Unknown (cellFsAclRead)
{
break ;
}
case 0xe0000009 : // Unknown (cellFsAccess)
{
break ;
}
case 0xe000000a : // Unknown (E3D28395)
{
break ;
}
case 0xe000000b : // Unknown (cellFsRename, FF29F478)
{
break ;
}
case 0xe000000c : // Unknown (cellFsTruncate)
{
break ;
}
case 0xe000000d : // Unknown (cellFsUtime)
{
break ;
}
case 0xe000000e : // Unknown (cellFsAclWrite)
{
break ;
}
case 0xe000000f : // Unknown (cellFsChmod)
{
break ;
}
case 0xe0000010 : // Unknown (cellFsChown)
{
break ;
}
case 0xe0000011 : // Unknown
{
break ;
}
2017-04-22 14:29:20 +02:00
case 0xe0000012 : // cellFsGetDirectoryEntries
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-04-22 14:29:20 +02:00
const auto arg = vm : : static_ptr_cast < lv2_file_op_dir : : dir_info > ( _arg ) ;
if ( _size < arg . size ( ) )
{
return CELL_EINVAL ;
}
const auto directory = idm : : get < lv2_fs_object , lv2_dir > ( fd ) ;
if ( ! directory )
{
return CELL_EBADF ;
}
for ( ; arg - > _size < arg - > max ; arg - > _size + + )
{
2018-09-15 16:04:35 +02:00
if ( auto * info = directory - > dir_read ( ) )
2017-04-22 14:29:20 +02:00
{
auto & entry = arg - > ptr [ arg - > _size ] ;
2018-09-15 16:04:35 +02:00
entry . attribute . mode = info - > is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666 ;
2017-04-22 14:29:20 +02:00
entry . attribute . uid = 0 ;
entry . attribute . gid = 0 ;
2018-09-15 16:04:35 +02:00
entry . attribute . atime = info - > atime ;
entry . attribute . mtime = info - > mtime ;
entry . attribute . ctime = info - > ctime ;
entry . attribute . size = info - > size ;
2017-04-22 14:29:20 +02:00
entry . attribute . blksize = 4096 ; // ???
2018-09-15 16:04:35 +02:00
entry . entry_name . d_type = info - > is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR ;
entry . entry_name . d_namlen = u8 ( std : : min < size_t > ( info - > name . size ( ) , CELL_FS_MAX_FS_FILE_NAME_LENGTH ) ) ;
strcpy_trunc ( entry . entry_name . d_name , info - > name ) ;
2017-04-22 14:29:20 +02:00
}
else
{
break ;
}
}
arg - > _code = CELL_OK ;
return CELL_OK ;
}
2017-04-26 14:48:50 +02:00
case 0xe0000015 : // Unknown
{
break ;
}
case 0xe0000016 : // cellFsAllocateFileAreaWithInitialData
2016-06-02 17:16:01 +02:00
{
2017-04-26 14:48:50 +02:00
break ;
}
case 0xe0000017 : // cellFsAllocateFileAreaWithoutZeroFill
{
2017-05-07 00:08:44 +02:00
const auto arg = vm : : static_ptr_cast < lv2_file_e0000017 > ( _arg ) ;
if ( _size < arg - > size | | arg - > _x4 ! = 0x10 | | arg - > _x8 ! = 0x20 )
{
return CELL_EINVAL ;
}
2019-06-08 18:34:55 +02:00
arg - > out_code = sys_fs_truncate ( ppu , arg - > file_path , arg - > file_size ) ;
2017-05-07 00:08:44 +02:00
return CELL_OK ;
2017-04-26 14:48:50 +02:00
}
case 0xe0000018 : // cellFsChangeFileSizeWithoutAllocation
{
break ;
}
case 0xe0000019 : // Unknown
{
break ;
}
case 0xe000001b : // Unknown
{
break ;
}
case 0xe000001d : // Unknown
{
break ;
}
case 0xe000001e : // Unknown
{
break ;
}
case 0xe000001f : // Unknown
{
break ;
}
case 0xe0000020 : // Unknown
{
break ;
}
case 0x00000025 : // cellFsSdataOpenWithVersion
{
break ;
2016-06-02 17:16:01 +02:00
}
}
2015-03-15 01:41:08 +01:00
2017-04-26 14:48:50 +02:00
sys_fs . fatal ( " 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 ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lseek ( ppu_thread & ppu , u32 fd , s64 offset , s32 whence , vm : : ptr < u64 > pos )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +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
{
2017-08-08 21:13:48 +02:00
return { CELL_EINVAL , whence } ;
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
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2015-03-16 17:20:02 +01:00
2017-03-23 19:32:59 +01:00
const u64 result = file - > file . seek ( offset , static_cast < fs : : seek_mode > ( whence ) ) ;
if ( result = = - 1 )
{
switch ( auto error = fs : : g_tls_error )
{
case fs : : error : : inval : return CELL_EINVAL ;
default : sys_fs . error ( " sys_fs_lseek(): unknown error %s " , error ) ;
}
return CELL_EIO ; // ???
}
2015-03-16 17:20:02 +01:00
2017-03-23 19:32:59 +01:00
* pos = result ;
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2019-03-08 17:07:14 +01:00
error_code sys_fs_fdatasync ( ppu_thread & ppu , u32 fd )
2017-04-24 17:43:27 +02:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-04-24 17:43:27 +02:00
sys_fs . trace ( " sys_fs_fdadasync(fd=%d) " , fd ) ;
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
2017-05-01 20:34:50 +02:00
if ( ! file | | ! ( file - > flags & CELL_FS_O_ACCMODE ) )
2017-04-24 17:43:27 +02:00
{
return CELL_EBADF ;
}
file - > file . sync ( ) ;
return CELL_OK ;
}
2019-03-08 17:07:14 +01:00
error_code sys_fs_fsync ( ppu_thread & ppu , u32 fd )
2017-04-24 17:43:27 +02:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-04-24 17:43:27 +02:00
sys_fs . trace ( " sys_fs_fsync(fd=%d) " , fd ) ;
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
2017-05-01 20:34:50 +02:00
if ( ! file | | ! ( file - > flags & CELL_FS_O_ACCMODE ) )
2017-04-24 17:43:27 +02:00
{
return CELL_EBADF ;
}
file - > file . sync ( ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_fget_block_size ( ppu_thread & ppu , u32 fd , vm : : ptr < u64 > sector_size , vm : : ptr < u64 > block_size , vm : : ptr < u64 > arg4 , vm : : ptr < s32 > arg5 )
2015-03-12 20:02:02 +01:00
{
2017-04-26 19:31:39 +02:00
sys_fs . warning ( " 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
2017-04-26 19:31:39 +02:00
// TODO
* sector_size = 4096 ;
* block_size = 4096 ;
2017-04-25 02:13:45 +02:00
* arg4 = 0 ;
2017-04-26 19:31:39 +02:00
* arg5 = file - > mode ;
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_get_block_size ( ppu_thread & ppu , 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
{
2017-04-26 19:31:39 +02:00
sys_fs . warning ( " 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
2017-04-26 19:31:39 +02:00
// TODO
* sector_size = 4096 ;
* block_size = 4096 ;
2017-04-25 02:13:45 +02:00
* arg4 = 0 ;
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_truncate ( ppu_thread & ppu , vm : : cptr < char > path , u64 size )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
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
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EISDIR , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
if ( ! fs : : truncate_file ( local_path , 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
{
2017-08-08 21:13:48 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2016-07-21 00:00:31 +02:00
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
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
2015-03-12 20:02:02 +01:00
}
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_ftruncate ( ppu_thread & ppu , u32 fd , u64 size )
2015-03-12 20:02:02 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2016-01-12 22:57:16 +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
2015-04-19 19:14:16 +02: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
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2015-04-12 03:36:25 +02:00
2017-09-04 01:09:22 +02:00
if ( file - > lock )
{
return CELL_EBUSY ;
}
if ( file - > flags & CELL_FS_O_APPEND )
{
const u64 fsize = file - > file . size ( ) ;
if ( size > fsize & & ! file - > file . write ( std : : vector < u8 > ( size - fsize ) ) )
{
return CELL_ENOSPC ;
}
}
else if ( ! file - > file . trunc ( size ) )
2015-04-19 19:14:16 +02: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-05-13 15:55:34 +02:00
case fs : : error : : ok :
2016-07-21 00:00:31 +02:00
default : sys_fs . error ( " sys_fs_ftruncate(): unknown error %s " , error ) ;
2016-04-14 00:23:53 +02:00
}
2015-04-19 19:14:16 +02:00
2016-06-02 17:16:01 +02:00
return CELL_EIO ; // ???
2015-04-19 19:14:16 +02:00
}
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_symbolic_link ( ppu_thread & ppu , vm : : cptr < char > target , vm : : cptr < char > linkpath )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_symbolic_link(target=%s, linkpath=%s) " , target , linkpath ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_chmod ( ppu_thread & ppu , vm : : cptr < char > path , s32 mode )
2015-03-12 20:02:02 +01:00
{
2017-05-10 16:43:04 +02:00
sys_fs . todo ( " sys_fs_chmod(path=%s, mode=%#o) " , path , mode ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_chown ( ppu_thread & ppu , vm : : cptr < char > path , s32 uid , s32 gid )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_chown(path=%s, uid=%d, gid=%d) " , path , uid , gid ) ;
2015-03-12 20:02:02 +01:00
return CELL_OK ;
}
2017-01-26 13:01:21 +01:00
2019-06-08 18:34:55 +02:00
error_code sys_fs_disk_free ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < u64 > total_free , vm : : ptr < u64 > avail_free )
2017-06-25 11:31:50 +02:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-06-25 11:31:50 +02:00
sys_fs . warning ( " sys_fs_disk_free(path=%s total_free=*0x%x avail_free=*0x%x) " , path , total_free , avail_free ) ;
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_EINVAL ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EPERM , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
2017-06-25 11:31:50 +02:00
fs : : device_stat info ;
2017-09-18 23:03:26 +02:00
if ( ! fs : : statfs ( local_path , info ) )
2017-06-25 11:31:50 +02:00
{
switch ( auto error = fs : : g_tls_error )
{
2017-08-08 21:13:48 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2017-06-25 11:31:50 +02:00
default : sys_fs . error ( " sys_fs_disk_free(): unknown error %s " , error ) ;
}
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
2017-06-25 11:31:50 +02:00
}
* total_free = info . total_free ;
* avail_free = info . avail_free ; //Only value used by cellFsGetFreeSize
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_utime ( ppu_thread & ppu , vm : : cptr < char > path , vm : : cptr < CellFsUtimbuf > timep )
2017-01-26 13:01:21 +01:00
{
2019-06-08 18:34:55 +02:00
lv2_obj : : sleep ( ppu ) ;
2017-01-26 13:01:21 +01:00
sys_fs . warning ( " sys_fs_utime(path=%s, timep=*0x%x) " , path , timep ) ;
2017-11-20 17:06:17 +01:00
sys_fs . warning ( " ** actime=%u, modtime=%u " , timep - > actime , timep - > modtime ) ;
2017-01-26 13:01:21 +01:00
2018-03-21 20:02:36 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
2018-09-11 18:02:19 +02:00
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2017-09-18 23:03:26 +02:00
2018-09-11 18:02:19 +02:00
if ( vpath . find_first_not_of ( ' / ' ) = = - 1 )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_EISDIR , path } ;
2017-09-18 23:03:26 +02:00
}
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2018-09-11 18:02:19 +02:00
return { CELL_ENOTMOUNTED , path } ;
2017-09-18 23:03:26 +02:00
}
if ( ! fs : : utime ( local_path , timep - > actime , timep - > modtime ) )
2017-01-26 13:01:21 +01:00
{
switch ( auto error = fs : : g_tls_error )
{
2017-08-08 21:13:48 +02:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
2017-01-26 13:01:21 +01:00
default : sys_fs . error ( " sys_fs_utime(): unknown error %s " , error ) ;
}
2017-08-08 21:13:48 +02:00
return { CELL_EIO , path } ; // ???
2017-01-26 13:01:21 +01:00
}
return CELL_OK ;
}
2017-04-24 22:30:15 +02:00
2019-06-08 18:34:55 +02:00
error_code sys_fs_acl_read ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < void > ptr )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_acl_read(path=%s, ptr=*0x%x) " , path , ptr ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_acl_write ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < void > ptr )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_acl_write(path=%s, ptr=*0x%x) " , path , ptr ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_get_cda_size ( ppu_thread & ppu , u32 fd , vm : : ptr < u64 > ptr )
2017-04-26 19:26:29 +02:00
{
sys_fs . warning ( " sys_fs_lsn_get_cda_size(fd=%d, ptr=*0x%x) " , fd , ptr ) ;
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
if ( ! file )
{
return CELL_EBADF ;
}
// TODO
* ptr = 0 ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_get_cda ( ppu_thread & ppu , u32 fd , vm : : ptr < void > arg2 , u64 arg3 , vm : : ptr < u64 > arg4 )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_lsn_get_cda(fd=%d, arg2=*0x%x, arg3=0x%x, arg4=*0x%x) " , fd , arg2 , arg3 , arg4 ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_lock ( ppu_thread & ppu , u32 fd )
2017-04-24 22:30:15 +02:00
{
sys_fs . trace ( " sys_fs_lsn_lock(fd=%d) " , fd ) ;
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
if ( ! file )
{
return CELL_EBADF ;
}
// TODO: research correct implementation
if ( ! file - > lock . compare_and_swap_test ( 0 , 1 ) )
{
return CELL_EBUSY ;
}
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_unlock ( ppu_thread & ppu , u32 fd )
2017-04-24 22:30:15 +02:00
{
sys_fs . trace ( " sys_fs_lsn_unlock(fd=%d) " , fd ) ;
const auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
if ( ! file )
{
return CELL_EBADF ;
}
// TODO: research correct implementation
if ( ! file - > lock . compare_and_swap_test ( 1 , 0 ) )
{
return CELL_EPERM ;
}
return CELL_OK ;
}
2017-05-10 16:43:04 +02:00
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_read ( ppu_thread & ppu , u32 fd , vm : : cptr < void > ptr , u64 size )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_lsn_read(fd=%d, ptr=*0x%x, size=0x%x) " , fd , ptr , size ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_lsn_write ( ppu_thread & ppu , u32 fd , vm : : cptr < void > ptr , u64 size )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_lsn_write(fd=%d, ptr=*0x%x, size=0x%x) " , fd , ptr , size ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_mapped_allocate ( ppu_thread & ppu , u32 fd , u64 size , vm : : pptr < void > out_ptr )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_mapped_allocate(fd=%d, arg2=0x%x, out_ptr=**0x%x) " , fd , size , out_ptr ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_mapped_free ( ppu_thread & ppu , u32 fd , vm : : ptr < void > ptr )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_mapped_free(fd=%d, ptr=0x%#x) " , fd , ptr ) ;
return CELL_OK ;
}
2019-06-08 18:34:55 +02:00
error_code sys_fs_truncate2 ( ppu_thread & ppu , u32 fd , u64 size )
2017-05-10 16:43:04 +02:00
{
sys_fs . todo ( " sys_fs_truncate2(fd=%d, size=0x%x) " , fd , size ) ;
return CELL_OK ;
}