2020-12-05 13:08:24 +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"
2017-03-07 01:59:05 +01:00
# include "Emu/Cell/PPUThread.h"
# include "Crypto/unedat.h"
2020-10-30 21:26:22 +01:00
# include "Emu/System.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
2020-10-01 21:07:38 +02:00
lv2_fs_mount_point g_mp_sys_dev_root ;
2020-10-03 18:05:09 +02:00
lv2_fs_mount_point g_mp_sys_no_device ;
2020-10-02 13:37:58 +02:00
lv2_fs_mount_point g_mp_sys_dev_hdd0 { " /dev_hdd0 " } ;
lv2_fs_mount_point g_mp_sys_dev_hdd1 { " /dev_hdd1 " , 512 , 32768 , lv2_mp_flag : : no_uid_gid } ;
lv2_fs_mount_point g_mp_sys_dev_usb { " " , 512 , 4096 , lv2_mp_flag : : no_uid_gid } ;
lv2_fs_mount_point g_mp_sys_dev_bdvd { " " , 2048 , 65536 , lv2_mp_flag : : read_only + lv2_mp_flag : : no_uid_gid } ;
lv2_fs_mount_point g_mp_sys_host_root { " " , 512 , 512 , lv2_mp_flag : : strict_get_block_size + lv2_mp_flag : : no_uid_gid } ;
lv2_fs_mount_point g_mp_sys_dev_flash { " " , 512 , 8192 , lv2_mp_flag : : read_only + lv2_mp_flag : : no_uid_gid } ;
2016-06-02 17:16:01 +02:00
2020-03-06 13:47:24 +01:00
bool verify_mself ( const fs : : file & mself_file )
2017-03-07 01:59:05 +01:00
{
FsMselfHeader mself_header ;
if ( ! mself_file . read < FsMselfHeader > ( mself_header ) )
{
sys_fs . error ( " verify_mself: Didn't read expected bytes for header. " ) ;
return false ;
}
2020-02-19 16:26:41 +01:00
if ( mself_header . m_magic ! = 0x4D534600u )
2017-03-07 01:59:05 +01:00
{
sys_fs . error ( " verify_mself: Header magic is incorrect. " ) ;
return false ;
}
2020-02-19 16:26:41 +01:00
if ( mself_header . m_format_version ! = 1u )
2017-03-07 01:59:05 +01:00
{
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 ;
}
2020-01-04 21:12:46 +01:00
lv2_fs_mount_point * lv2_fs_object : : get_mp ( std : : string_view filename )
2016-06-02 17:16:01 +02:00
{
2020-10-01 21:07:38 +02:00
std : : string_view mp_name , vpath = filename ;
2020-01-04 21:12:46 +01:00
2020-12-18 08:39:54 +01:00
for ( usz depth = 0 ; ; )
2020-01-04 21:12:46 +01:00
{
2020-10-01 21:07:38 +02:00
// Skip one or more '/'
const auto pos = vpath . find_first_not_of ( ' / ' ) ;
2020-01-04 21:12:46 +01:00
2020-10-01 21:07:38 +02:00
if ( pos = = 0 )
{
// Relative path (TODO)
2020-10-03 18:05:09 +02:00
return & g_mp_sys_no_device ;
2020-10-01 21:07:38 +02:00
}
if ( pos = = umax )
{
break ;
}
// Get fragment name
const auto name = vpath . substr ( pos , vpath . find_first_of ( ' / ' , pos ) - pos ) ;
vpath . remove_prefix ( name . size ( ) + pos ) ;
// Process special directories
if ( name = = " . " sv )
{
// Keep current
continue ;
}
if ( name = = " .. " sv )
{
// Root parent is root
if ( depth = = 0 )
{
continue ;
}
depth - - ;
continue ;
}
if ( depth + + = = 0 )
{
// Save mountpoint name
mp_name = name ;
}
}
if ( ! mp_name . empty ( ) )
{
if ( mp_name = = " dev_hdd0 " sv )
return & g_mp_sys_dev_hdd0 ;
2020-01-04 21:12:46 +01:00
if ( mp_name = = " dev_hdd1 " sv )
return & g_mp_sys_dev_hdd1 ;
2020-02-17 22:43:23 +01:00
if ( mp_name . starts_with ( " dev_usb " sv ) )
2020-01-04 21:12:46 +01:00
return & g_mp_sys_dev_usb ;
if ( mp_name = = " dev_bdvd " sv )
return & g_mp_sys_dev_bdvd ;
2020-10-01 21:07:38 +02:00
if ( mp_name = = " app_home " sv & & filename . data ( ) ! = Emu . argv [ 0 ] . data ( ) )
return lv2_fs_object : : get_mp ( Emu . argv [ 0 ] ) ;
2020-01-04 21:12:46 +01:00
if ( mp_name = = " host_root " sv )
return & g_mp_sys_host_root ;
2020-01-18 21:41:58 +01:00
if ( mp_name = = " dev_flash " sv )
return & g_mp_sys_dev_flash ;
2020-10-01 21:07:38 +02:00
// Default
return & g_mp_sys_dev_hdd0 ;
2020-01-04 21:12:46 +01:00
}
2020-10-01 21:07:38 +02:00
// Default fallback
return & g_mp_sys_dev_root ;
2016-06-02 17:16:01 +02:00
}
2020-02-27 16:24:47 +01:00
u64 lv2_file : : op_read ( const fs : : file & file , 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)
2020-01-19 02:25:50 +01:00
uchar local_buf [ 65536 ] ;
u64 result = 0 ;
while ( result < size )
{
const u64 block = std : : min < u64 > ( size - result , sizeof ( local_buf ) ) ;
const u64 nread = file . read ( + local_buf , block ) ;
std : : memcpy ( static_cast < uchar * > ( buf . get_ptr ( ) ) + result , local_buf , nread ) ;
result + = nread ;
if ( nread < block )
{
break ;
}
}
2016-06-02 17:16:01 +02:00
return result ;
}
2020-02-27 16:24:47 +01:00
u64 lv2_file : : op_write ( const fs : : file & file , 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)
2020-01-19 02:25:50 +01:00
uchar local_buf [ 65536 ] ;
u64 result = 0 ;
while ( result < size )
{
const u64 block = std : : min < u64 > ( size - result , sizeof ( local_buf ) ) ;
2020-01-21 13:52:13 +01:00
std : : memcpy ( local_buf , static_cast < const uchar * > ( buf . get_ptr ( ) ) + result , block ) ;
2020-01-19 02:25:50 +01:00
const u64 nwrite = file . write ( + local_buf , block ) ;
result + = nwrite ;
if ( nwrite < block )
{
break ;
}
}
return result ;
2016-06-02 17:16:01 +02:00
}
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 ) ;
2020-12-09 08:47:45 +01:00
ensure ( old_pos = = m_file - > file . seek ( old_pos ) ) ;
2017-03-04 12:54:53 +01:00
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 :
2020-03-07 09:52:54 +01:00
whence = = fs : : seek_end ? offset + size ( ) : - 1 ;
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 ;
}
2020-09-11 13:06:46 +02:00
lv2_file : : open_raw_result_t lv2_file : : open_raw ( const std : : string & local_path , s32 flags , s32 mode , lv2_file_type type , const lv2_fs_mount_point * mp )
2015-03-12 20:02:02 +01: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
{
2020-09-11 13:06:46 +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
2020-01-11 02:48:42 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
if ( flags & CELL_FS_O_ACCMODE | | flags & ( CELL_FS_O_CREAT | CELL_FS_O_TRUNC ) )
{
2020-09-11 13:06:46 +02:00
return { CELL_EPERM } ;
2020-01-11 02:48:42 +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
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
{
2020-03-06 13:47:24 +01:00
sys_fs . warning ( " lv2_file::open() called with CELL_FS_O_UNK flag enabled. FLAGS: %#o " , flags ) ;
2018-02-14 18:06:46 +01:00
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
// Deactivate mutating flags on read-only FS
open_mode = fs : : read ;
}
2018-02-14 18:06:46 +01:00
// 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
{
2020-12-09 16:04:52 +01:00
fmt : : throw_exception ( " lv2_file::open_raw(): Invalid or unimplemented flags: %#o " , flags ) ;
2015-03-13 16:06:27 +01:00
}
2015-04-19 15:19:24 +02:00
2020-09-11 13:06:46 +02:00
std : : lock_guard lock ( mp - > mutex ) ;
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
{
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
// Failed to create file on read-only FS (file doesn't exist)
if ( flags & CELL_FS_O_CREAT )
{
2020-09-11 13:06:46 +02:00
return { CELL_EROFS } ;
2020-01-04 22:55:15 +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
{
2020-03-06 13:47:24 +01:00
return { 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 )
{
2020-09-11 13:06:46 +02:00
case fs : : error : : noent : return { CELL_ENOENT } ;
2020-03-06 13:47:24 +01:00
default : sys_fs . error ( " lv2_file::open(): unknown error %s " , error ) ;
2017-09-08 16:17:03 +02:00
}
2020-09-11 13:06:46 +02:00
return { CELL_EIO } ;
2015-03-12 20:02:02 +01:00
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
// Failed to create file on read-only FS (file exists)
if ( flags & CELL_FS_O_CREAT & & flags & CELL_FS_O_EXCL )
{
2020-09-11 13:06:46 +02:00
return { CELL_EEXIST } ;
2020-01-04 22:55:15 +01:00
}
// Failed to truncate file on read-only FS
if ( flags & CELL_FS_O_TRUNC )
{
2020-09-11 13:06:46 +02:00
return { CELL_EROFS } ;
2020-01-04 22:55:15 +01:00
}
}
2020-03-06 13:47:24 +01:00
if ( flags & CELL_FS_O_MSELF & & ! verify_mself ( file ) )
2017-08-08 21:13:48 +02:00
{
2020-09-11 13:06:46 +02:00
return { CELL_ENOTMSELF } ;
2017-08-08 21:13:48 +02:00
}
2020-09-11 13:06:46 +02:00
if ( type > = lv2_file_type : : sdata )
2017-03-07 01:59:05 +01:00
{
2017-12-16 01:03:49 +01:00
// check for sdata
2020-09-11 13:06:46 +02:00
switch ( type )
2020-03-06 13:47:24 +01:00
{
2020-09-11 13:06:46 +02:00
case lv2_file_type : : sdata :
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 ( ) )
{
2020-09-11 13:06:46 +02:00
return { CELL_EFSSPECIFIC } ;
2017-03-10 10:06:36 +01:00
}
file . reset ( std : : move ( sdata_file ) ) ;
}
2020-03-06 13:47:24 +01:00
break ;
2017-03-10 10:06:36 +01:00
}
2017-12-16 01:03:49 +01:00
// edata
2020-09-11 13:06:46 +02:00
case lv2_file_type : : edata :
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 )
{
2019-08-21 19:33:49 +02:00
auto edatkeys = g_fxo - > get < loaded_npdrm_keys > ( ) ;
2020-06-20 13:12:19 +02:00
auto sdata_file = std : : make_unique < EDATADecrypter > ( std : : move ( file ) , edatkeys - > devKlic . load ( ) , edatkeys - > rifKey . load ( ) ) ;
2017-03-10 10:06:36 +01:00
if ( ! sdata_file - > ReadHeader ( ) )
{
2020-09-11 13:06:46 +02:00
return { CELL_EFSSPECIFIC } ;
2017-03-10 10:06:36 +01:00
}
file . reset ( std : : move ( sdata_file ) ) ;
2017-03-07 01:59:05 +01:00
}
2020-03-06 13:47:24 +01:00
break ;
2017-03-07 01:59:05 +01:00
}
2020-03-06 13:47:24 +01:00
default : break ;
}
}
2020-09-11 13:06:46 +02:00
return { . error = { } , . file = std : : move ( file ) } ;
}
lv2_file : : open_result_t lv2_file : : open ( std : : string_view vpath , s32 flags , s32 mode , const void * arg , u64 size )
{
if ( vpath . empty ( ) )
{
return { CELL_ENOENT } ;
}
std : : string path ;
const std : : string local_path = vfs : : get ( vpath , nullptr , & path ) ;
const auto mp = lv2_fs_object : : get_mp ( path ) ;
2020-10-12 20:23:17 +02:00
if ( mp = = & g_mp_sys_dev_root )
2020-09-11 13:06:46 +02:00
{
return { CELL_EISDIR , path } ;
}
if ( local_path . empty ( ) )
{
return { CELL_ENOTMOUNTED , path } ;
}
lv2_file_type type = lv2_file_type : : regular ;
if ( size = = 8 )
{
// see lv2_file::open_raw
switch ( * static_cast < const be_t < u64 > * > ( arg ) )
{
case 0x18000000010 : type = lv2_file_type : : sdata ; break ;
case 0x2 : type = lv2_file_type : : edata ; break ;
default :
break ;
}
}
auto [ error , file ] = open_raw ( local_path , flags , mode , type , mp ) ;
return { . error = error , . ppath = std : : move ( path ) , . real_path = std : : move ( local_path ) , . file = std : : move ( file ) , . type = type } ;
2020-03-06 13:47:24 +01: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 )
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
2020-03-06 13:47:24 +01:00
lv2_obj : : sleep ( ppu ) ;
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 ) ;
if ( ! path )
return CELL_EFAULT ;
2020-09-11 13:06:46 +02:00
auto [ error , ppath , real , file , type ] = lv2_file : : open ( path . get_ptr ( ) , flags , mode , arg . get_ptr ( ) , size ) ;
2020-03-06 13:47:24 +01:00
if ( error )
{
if ( error = = CELL_EEXIST )
{
return not_an_error ( CELL_EEXIST ) ;
}
return { error , path } ;
2017-03-07 01:59:05 +01:00
}
2017-08-08 21:13:48 +02:00
2020-09-11 13:06:46 +02:00
if ( type > = lv2_file_type : : sdata )
2020-04-04 16:11:21 +02:00
{
2020-09-11 13:06:46 +02:00
sys_fs . warning ( " sys_fs_open(): NPDRM detected " ) ;
2020-04-04 16:11:21 +02:00
2020-09-11 13:06:46 +02:00
if ( const u32 id = idm : : import < lv2_fs_object , lv2_file > ( [ & ppath = ppath , & file = file , mode , flags , & real = real , & type = type ] ( ) - > std : : shared_ptr < lv2_file >
2020-04-04 16:11:21 +02:00
{
if ( ! g_fxo - > get < loaded_npdrm_keys > ( ) - > npdrm_fds . try_inc ( 16 ) )
{
return nullptr ;
}
2020-09-11 13:06:46 +02:00
return std : : make_shared < lv2_file > ( ppath , std : : move ( file ) , mode , flags , real , type ) ;
2020-04-04 16:11:21 +02:00
} ) )
{
* fd = id ;
return CELL_OK ;
}
}
2020-09-11 13:06:46 +02:00
else if ( const u32 id = idm : : make < lv2_fs_object , lv2_file > ( ppath , std : : move ( file ) , mode , flags , real ) )
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ) ;
2020-01-18 13:01:30 +01:00
if ( ! nread )
{
return CELL_EFAULT ;
}
2016-04-09 11:45:45 +02:00
if ( ! buf )
{
2020-01-18 13:01:30 +01:00
nread . try_write ( 0 ) ;
2016-04-09 11:45:45 +02:00
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
{
2020-01-18 13:01:30 +01:00
nread . try_write ( 0 ) ; // nread writing is allowed to fail, error code is unchanged
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
2019-11-09 12:35:41 +01:00
if ( file - > lock = = 2 )
{
2020-01-18 13:01:30 +01:00
nread . try_write ( 0 ) ;
2019-11-09 12:35:41 +01:00
return CELL_EIO ;
}
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-01-18 13:01:30 +01:00
if ( ! nwrite )
{
return CELL_EFAULT ;
}
if ( ! buf )
{
nwrite . try_write ( 0 ) ;
return CELL_EFAULT ;
}
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
{
2020-01-18 13:01:30 +01:00
nwrite . try_write ( 0 ) ; // nwrite writing is allowed to fail, error code is unchanged
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
2020-01-04 22:55:15 +01:00
if ( file - > mp - > flags & lv2_mp_flag : : read_only )
{
2020-01-18 13:01:30 +01:00
nwrite . try_write ( 0 ) ;
2020-01-04 22:55:15 +01:00
return CELL_EROFS ;
}
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 )
{
2019-11-09 12:35:41 +01:00
if ( file - > lock = = 2 )
{
2020-01-18 13:01:30 +01:00
nwrite . try_write ( 0 ) ;
2019-11-09 12:35:41 +01:00
return CELL_EIO ;
}
2020-01-18 13:01:30 +01:00
nwrite . try_write ( 0 ) ;
2017-04-24 22:30:15 +02:00
return CELL_EBUSY ;
}
2020-01-05 16:14:07 +01:00
if ( file - > flags & CELL_FS_O_APPEND )
{
file - > file . seek ( 0 , fs : : seek_end ) ;
}
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-04-04 16:11:21 +02:00
const auto file = idm : : withdraw < lv2_fs_object , lv2_file > ( fd , [ ] ( lv2_file & file )
{
2020-09-11 13:06:46 +02:00
if ( file . type > = lv2_file_type : : sdata )
2020-04-04 16:11:21 +02:00
{
g_fxo - > get < loaded_npdrm_keys > ( ) - > npdrm_fds - - ;
}
} ) ;
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
}
2020-01-16 20:10:08 +01:00
if ( file - > lock = = 1 )
2017-04-24 22:30:15 +02:00
{
2020-01-16 20:10:08 +01:00
return CELL_EBUSY ;
2017-04-24 22:30:15 +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_opendir ( ppu_thread & ppu , vm : : cptr < char > path , vm : : ptr < u32 > fd )
2015-03-12 20:02:02 +01:00
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ;
2020-01-04 18:10:37 +01:00
std : : string processed_path ;
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 ( ) ;
2020-01-04 18:10:37 +01:00
const std : : string local_path = vfs : : get ( vpath , & ext , & processed_path ) ;
processed_path + = " / " ;
2018-09-11 18:02:19 +02:00
2020-01-04 22:55:15 +01:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
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
}
2020-09-11 13:06:46 +02:00
std : : lock_guard lock ( mp - > mutex ) ;
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)
2020-02-17 22:43:23 +01:00
while ( data . back ( ) . name . ends_with ( " .66600 " ) )
2018-09-15 16:04:35 +02:00
{
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 ( ) ) ;
2020-01-04 21:12:46 +01:00
if ( const u32 id = idm : : make < lv2_fs_object , lv2_dir > ( processed_path , 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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ;
2020-12-18 08:39:54 +01:00
dir - > d_namlen = u8 ( std : : min < usz > ( info - > name . size ( ) , CELL_FS_MAX_FS_FILE_NAME_LENGTH ) ) ;
2018-09-15 16:04:35 +02:00
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2019-04-10 16:32:48 +02:00
if ( ! idm : : remove < lv2_fs_object , lv2_dir > ( fd ) )
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
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ) ;
2020-01-04 22:55:15 +01:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
2020-01-03 21:29:39 +01:00
2020-10-02 13:37:58 +02:00
if ( mp = = & g_mp_sys_dev_root )
2018-09-11 18:02:19 +02:00
{
2020-08-29 20:29:19 +02:00
sb - > mode = CELL_FS_S_IFDIR | 0711 ;
sb - > uid = - 1 ;
sb - > gid = - 1 ;
sb - > atime = - 1 ;
sb - > mtime = - 1 ;
sb - > ctime = - 1 ;
sb - > size = 258 ;
sb - > blksize = 512 ;
2018-09-11 18:02:19 +02:00
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
2020-01-04 22:55:15 +01:00
std : : lock_guard lock ( mp - > mutex ) ;
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 ;
2017-09-08 16:17:03 +02:00
2020-01-05 15:31:34 +01:00
for ( u32 i = 66601 ; i < = 66699 ; i + + )
2018-08-26 23:38:21 +02:00
{
if ( fs : : stat ( fmt : : format ( " %s.%u " , local_path , i ) , info ) & & ! info . is_directory )
{
total_size + = info . size ;
}
else
{
break ;
}
}
// Use attributes from the first fragment (consistently with sys_fs_open+fstat)
2020-01-05 15:31:34 +01:00
if ( fs : : stat ( local_path + " .66600 " , info ) & & ! info . is_directory )
2018-08-26 23:38:21 +02:00
{
// Success
2020-01-05 15:31:34 +01:00
info . size + = total_size ;
2018-08-26 23:38:21 +02:00
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 ;
2020-01-04 21:12:46 +01:00
sb - > uid = mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 0 ;
sb - > gid = mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 0 ;
2015-04-19 18:02:35 +02:00
sb - > atime = info . atime ;
sb - > mtime = info . mtime ;
sb - > ctime = info . ctime ;
2020-08-29 20:29:19 +02:00
sb - > size = info . is_directory ? mp - > block_size : info . size ;
2020-01-07 20:14:01 +01:00
sb - > blksize = mp - > block_size ;
2015-03-12 20:02:02 +01:00
2020-01-11 02:48:42 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
// Remove write permissions
sb - > mode & = ~ 0222 ;
}
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2019-11-09 12:35:41 +01:00
if ( file - > lock = = 2 )
{
return CELL_EIO ;
}
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 ;
2020-01-04 21:12:46 +01:00
sb - > uid = file - > mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 0 ;
sb - > gid = file - > mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 0 ;
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 ;
2020-01-07 20:14:01 +01:00
sb - > blksize = file - > mp - > block_size ;
2015-03-12 20:02:02 +01:00
2020-01-11 02:48:42 +01:00
if ( file - > mp - > flags & lv2_mp_flag : : read_only )
{
// Remove write permissions
sb - > mode & = ~ 0222 ;
}
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
if ( mp = = & g_mp_sys_dev_root )
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
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return { CELL_EROFS , path } ;
}
std : : lock_guard lock ( mp - > mutex ) ;
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ) ;
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vfrom ) ;
const auto mp_to = lv2_fs_object : : get_mp ( vto ) ;
if ( mp = = & g_mp_sys_dev_root | | mp_to = = & g_mp_sys_dev_root )
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
}
2020-10-02 13:37:58 +02:00
if ( mp ! = mp_to )
2020-01-04 22:55:15 +01:00
{
return CELL_EXDEV ;
}
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return CELL_EROFS ;
}
2020-09-11 13:06:46 +02:00
// Done in vfs::host::rename
//std::lock_guard lock(mp->mutex);
2020-01-04 22:55:15 +01:00
2020-09-11 13:06:46 +02:00
if ( ! vfs : : host : : rename ( local_from , local_to , mp , 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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
if ( mp = = & g_mp_sys_dev_root )
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
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return { CELL_EROFS , path } ;
}
std : : lock_guard lock ( mp - > mutex ) ;
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
2019-09-25 03:57:56 +02:00
2020-10-02 13:37:58 +02:00
if ( mp = = & g_mp_sys_dev_root )
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 } ;
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return { CELL_EROFS , path } ;
}
std : : lock_guard lock ( mp - > mutex ) ;
2020-10-02 13:37:58 +02:00
// Provide default mp root or use parent directory if not available (such as host_root)
if ( ! vfs : : host : : unlink ( local_path , vfs : : get ( mp - > root . empty ( ) ? vpath . substr ( 0 , vpath . find_last_of ( ' / ' ) ) : mp - > root ) ) )
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ;
}
2020-01-05 16:14:07 +01:00
if ( op = = 0x8000000b & & file - > flags & CELL_FS_O_APPEND )
{
return CELL_EBADF ;
}
2020-01-04 22:55:15 +01:00
if ( op = = 0x8000000b & & file - > mp - > flags & lv2_mp_flag : : read_only )
{
return CELL_EROFS ;
}
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2016-06-02 17:16:01 +02:00
2020-01-18 21:23:16 +01:00
if ( file - > lock = = 2 )
2017-04-24 22:30:15 +02:00
{
2020-01-18 21:23:16 +01:00
return CELL_EIO ;
}
2019-11-09 12:35:41 +01:00
2020-01-18 21:23:16 +01: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 ) ;
2020-12-09 08:47:45 +01:00
ensure ( 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 ;
}
2020-09-11 13:06:46 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
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 ) ) ;
2020-04-04 19:06:36 +02:00
if ( const u32 id = idm : : import < lv2_fs_object , lv2_file > ( [ & file = * file , & stream = stream ] ( ) - > std : : shared_ptr < lv2_file >
2020-04-04 16:11:21 +02:00
{
if ( ! g_fxo - > get < loaded_npdrm_keys > ( ) - > npdrm_fds . try_inc ( 16 ) )
{
return nullptr ;
}
2020-09-11 13:06:46 +02:00
return std : : make_shared < lv2_file > ( file , std : : move ( stream ) , file . mode , file . flags , file . real_path , lv2_file_type : : sdata ) ;
2020-04-04 16:11:21 +02:00
} ) )
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 ) ;
2020-01-10 23:09:30 +01:00
const auto mp = lv2_fs_object : : get_mp ( " /dev_hdd0 " ) ;
2017-09-18 23:03:26 +02:00
2020-01-07 20:14:01 +01:00
arg - > out_block_size = mp - > block_size ;
2020-09-18 21:34:42 +02:00
arg - > out_block_count = ( 40ull * 1024 * 1024 * 1024 - 1 ) / mp - > block_size ; // Read explanation in cellHddGameCheck
2017-04-25 02:13:45 +02:00
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 ) ;
2020-02-19 16:26:41 +01:00
if ( arg - > size ! = 0x20u )
2020-01-18 23:20:31 +01:00
{
sys_fs . error ( " sys_fs_fcntl(0xc0000006): invalid size (0x%x) " , arg - > size ) ;
break ;
}
2020-02-19 16:26:41 +01:00
if ( arg - > _x4 ! = 0x10u | | arg - > _x8 ! = 0x18u )
2020-01-18 23:20:31 +01:00
{
sys_fs . error ( " sys_fs_fcntl(0xc0000006): invalid args (0x%x, 0x%x) " , arg - > _x4 , arg - > _x8 ) ;
break ;
}
// Load mountpoint (doesn't support multiple // at the start)
std : : string_view vpath { arg - > name . get_ptr ( ) , arg - > name_size } ;
sys_fs . notice ( " sys_fs_fcntl(0xc0000006): %s " , vpath ) ;
// Check only mountpoint
vpath = vpath . substr ( 0 , vpath . find_first_of ( " / " , 1 ) ) ;
// Some mountpoints seem to be handled specially
if ( false )
{
// TODO: /dev_hdd1, /dev_usb000, /dev_flash
//arg->out_code = CELL_OK;
//arg->out_id = 0x1b5;
}
2020-01-09 01:57:44 +01:00
2020-01-18 23:20:31 +01:00
arg - > out_code = CELL_ENOTSUP ;
arg - > out_id = 0 ;
2017-04-22 15:01:24 +02:00
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 ;
}
2020-01-03 21:29:39 +01:00
arg - > _size = 0 ; // This write is not really useful for cellFs but do it anyways
// NOTE: This function is actually capable of reading only one entry at a time
if ( arg - > max )
2017-04-22 14:29:20 +02:00
{
2020-01-03 21:29:39 +01:00
std : : memset ( arg - > ptr . get_ptr ( ) , 0 , arg - > max * arg - > ptr . size ( ) ) ;
2018-09-15 16:04:35 +02:00
if ( auto * info = directory - > dir_read ( ) )
2017-04-22 14:29:20 +02:00
{
2020-01-03 21:29:39 +01:00
auto & entry = arg - > ptr [ arg - > _size + + ] ;
2017-04-22 14:29:20 +02:00
2018-09-15 16:04:35 +02:00
entry . attribute . mode = info - > is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666 ;
2020-01-04 21:12:46 +01:00
entry . attribute . uid = directory - > mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 0 ;
entry . attribute . gid = directory - > mp - > flags & lv2_mp_flag : : no_uid_gid ? - 1 : 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 ;
2020-01-07 20:14:01 +01:00
entry . attribute . blksize = directory - > mp - > block_size ;
2017-04-22 14:29:20 +02:00
2020-01-11 02:48:42 +01:00
if ( directory - > mp - > flags & lv2_mp_flag : : read_only )
{
// Remove write permissions
entry . attribute . mode & = ~ 0222 ;
}
2018-09-15 16:04:35 +02:00
entry . entry_name . d_type = info - > is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR ;
2020-12-18 08:39:54 +01:00
entry . entry_name . d_namlen = u8 ( std : : min < usz > ( info - > name . size ( ) , CELL_FS_MAX_FS_FILE_NAME_LENGTH ) ) ;
2018-09-15 16:04:35 +02:00
strcpy_trunc ( entry . entry_name . d_name , info - > name ) ;
2017-04-22 14:29:20 +02:00
}
}
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 ) ;
2020-02-19 16:26:41 +01:00
if ( _size < arg - > size | | arg - > _x4 ! = 0x10u | | arg - > _x8 ! = 0x20u )
2017-05-07 00:08:44 +02:00
{
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
2020-03-08 20:00:05 +01:00
sys_fs . error ( " 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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
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
2020-01-03 21:32:17 +01:00
if ( whence + 0u > = 3 )
{
return { CELL_EINVAL , whence } ;
}
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 ) ) ;
2020-02-19 18:03:59 +01:00
if ( result = = umax )
2017-03-23 19:32:59 +01:00
{
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ;
}
2020-01-04 22:55:15 +01:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2017-04-24 17:43:27 +02:00
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ;
}
2020-01-04 22:55:15 +01:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2017-04-24 17:43:27 +02:00
file - > file . sync ( ) ;
return CELL_OK ;
}
2020-01-07 19:54:21 +01: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 > out_flags )
2015-03-12 20:02:02 +01:00
{
2020-01-07 19:54:21 +01:00
sys_fs . warning ( " sys_fs_fget_block_size(fd=%d, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, out_flags=*0x%x) " , fd , sector_size , block_size , arg4 , out_flags ) ;
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
2020-01-07 20:14:01 +01:00
* sector_size = file - > mp - > sector_size ;
* block_size = file - > mp - > block_size ;
* arg4 = file - > mp - > sector_size ;
2020-01-07 19:54:21 +01:00
* out_flags = file - > flags ;
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
{
2020-01-09 01:26:03 +01:00
sys_fs . warning ( " sys_fs_get_block_size(path=%s, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x) " , path , sector_size , block_size , arg4 ) ;
2015-03-12 20:02:02 +01:00
2020-01-07 20:14:01 +01:00
if ( ! path )
return CELL_EFAULT ;
if ( ! path [ 0 ] )
return CELL_ENOENT ;
const std : : string_view vpath = path . get_ptr ( ) ;
const std : : string local_path = vfs : : get ( vpath ) ;
2020-02-19 18:03:59 +01:00
if ( vpath . find_first_not_of ( ' / ' ) = = umax )
2020-01-07 20:14:01 +01:00
{
return { CELL_EISDIR , path } ;
}
if ( local_path . empty ( ) )
{
return { CELL_ENOTMOUNTED , path } ;
}
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
2020-01-10 01:17:35 +01:00
// It appears that /dev_hdd0 mount point is special in this function
if ( mp ! = & g_mp_sys_dev_hdd0 & & ( mp - > flags & lv2_mp_flag : : strict_get_block_size ? ! fs : : is_file ( local_path ) : ! fs : : exists ( local_path ) ) )
2020-01-07 20:14:01 +01:00
{
switch ( auto error = fs : : g_tls_error )
{
2020-01-10 01:17:35 +01:00
case fs : : error : : exist : return { CELL_EISDIR , path } ;
2020-01-07 20:14:01 +01:00
case fs : : error : : noent : return { CELL_ENOENT , path } ;
default : sys_fs . error ( " sys_fs_get_block_size(): unknown error %s " , error ) ;
}
return { CELL_EIO , path } ; // ???
}
2017-04-26 19:31:39 +02:00
// TODO
2020-01-07 20:14:01 +01:00
* sector_size = mp - > sector_size ;
* block_size = mp - > block_size ;
* arg4 = mp - > sector_size ;
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
if ( mp = = & g_mp_sys_dev_root )
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
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return { CELL_EROFS , path } ;
}
std : : lock_guard lock ( mp - > mutex ) ;
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-01-04 22:55:15 +01:00
if ( file - > mp - > flags & lv2_mp_flag : : read_only )
{
return CELL_EROFS ;
}
2018-09-03 21:28:33 +02:00
std : : lock_guard lock ( file - > mp - > mutex ) ;
2015-04-12 03:36:25 +02:00
2019-11-09 12:35:41 +01:00
if ( file - > lock = = 2 )
{
return CELL_EIO ;
}
2017-09-04 01:09:22 +02:00
if ( file - > lock )
{
return CELL_EBUSY ;
}
2020-01-05 16:14:07 +01:00
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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 ( ) ;
2017-09-18 23:03:26 +02:00
2020-01-10 23:10:50 +01:00
if ( vpath = = " / " sv )
2017-09-18 23:03:26 +02:00
{
2020-01-10 23:10:50 +01:00
return CELL_ENOTSUP ;
}
// It seems max length is 31, and multiple / at the start aren't supported
2020-01-15 23:10:48 +01:00
if ( vpath . size ( ) > CELL_FS_MAX_MP_LENGTH )
2020-01-10 23:10:50 +01:00
{
return { CELL_ENAMETOOLONG , path } ;
2017-09-18 23:03:26 +02:00
}
2020-01-10 23:10:50 +01:00
if ( vpath . find_first_not_of ( ' / ' ) ! = 1 )
{
return { CELL_EINVAL , path } ;
}
// Get only device path
const std : : string local_path = vfs : : get ( vpath . substr ( 0 , vpath . find_first_of ( ' / ' , 1 ) ) ) ;
2018-09-11 18:02:19 +02:00
if ( local_path . empty ( ) )
2017-09-18 23:03:26 +02:00
{
2020-01-10 23:10:50 +01:00
return { CELL_EINVAL , path } ;
}
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
if ( mp - > flags & lv2_mp_flag : : strict_get_block_size )
{
// TODO:
return { CELL_ENOTSUP , path } ;
}
if ( mp - > flags & lv2_mp_flag : : read_only )
{
// TODO: check /dev_bdvd
* total_free = 0 ;
* avail_free = 0 ;
return CELL_OK ;
2017-09-18 23:03:26 +02:00
}
2020-09-18 21:52:04 +02:00
// avail_free is the only value used by cellFsGetFreeSize
if ( mp = = & g_mp_sys_dev_hdd1 )
2017-06-25 11:31:50 +02:00
{
2020-09-18 21:52:04 +02:00
* avail_free = ( 1u < < 31 ) - mp - > sector_size ; // 2GB (TODO: Should be the total size)
}
else //if (mp == &g_mp_sys_dev_hdd0)
{
* avail_free = ( 40ull * 1024 * 1024 * 1024 - mp - > sector_size ) ; // Read explanation in cellHddGameCheck
2017-06-25 11:31:50 +02:00
}
2020-09-18 21:52:04 +02:00
// HACK: Hopefully nothing uses this value or once at max because its hacked here:
2020-10-01 21:07:38 +02:00
// The total size can change based on the size of the directory
2020-09-18 21:52:04 +02:00
* total_free = * avail_free + fs : : get_dir_size ( local_path , mp - > sector_size ) ;
2017-06-25 11:31:50 +02:00
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
{
2020-10-30 18:14:32 +01:00
ppu . state + = cpu_flag : : wait ;
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
2020-10-02 13:37:58 +02:00
const auto mp = lv2_fs_object : : get_mp ( vpath ) ;
if ( mp = = & g_mp_sys_dev_root )
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
}
2020-01-04 22:55:15 +01:00
if ( mp - > flags & lv2_mp_flag : : read_only )
{
return { CELL_EROFS , path } ;
}
std : : lock_guard lock ( mp - > mutex ) ;
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 ;
}
2020-01-11 01:44:52 +01:00
// TODO: seems to do nothing on /dev_hdd0 or /host_root
if ( file - > mp = = & g_mp_sys_dev_hdd0 | | file - > mp - > flags & lv2_mp_flag : : strict_get_block_size )
{
return CELL_OK ;
}
file - > lock . compare_and_swap ( 0 , 1 ) ;
2017-04-24 22:30:15 +02:00
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 ;
}
2020-01-11 01:44:52 +01:00
// Unlock unconditionally
file - > lock . compare_and_swap ( 1 , 0 ) ;
2017-04-24 22:30:15 +02:00
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 ;
}
2020-02-07 10:31:33 +01:00
error_code sys_fs_get_mount_info_size ( ppu_thread & ppu , vm : : ptr < u64 > len )
{
sys_fs . todo ( " sys_fs_get_mount_info_size(len=*0x%x) " , len ) ;
return CELL_OK ;
}
error_code sys_fs_get_mount_info ( ppu_thread & ppu , vm : : ptr < CellFsMountInfo > info , u32 len , vm : : ptr < u64 > out_len )
{
sys_fs . todo ( " sys_fs_get_mount_info(info=*0x%x, len=0x%x, out_len=*0x%x) " , info , len , out_len ) ;
return CELL_OK ;
}
error_code sys_fs_mount ( ppu_thread & ppu , vm : : cptr < char > dev_name , vm : : cptr < char > file_system , vm : : cptr < char > path , s32 unk1 , s32 prot , s32 unk3 , vm : : cptr < char > str1 , u32 str_len )
{
sys_fs . todo ( " sys_fs_mount(dev_name=%s, file_system=%s, path=%s, unk1=0x%x, prot=0x%x, unk3=0x%x, str1=%s, str_len=%d) " , dev_name , file_system , path , unk1 , prot , unk3 , str1 , str_len ) ;
return CELL_OK ;
}