2022-04-14 22:41:41 +02:00
# include "FSWrapper.h"
# include "FileUtils.h"
# include "utils/StringTools.h"
# include "utils/logger.h"
2022-04-29 13:34:04 +02:00
# include "utils/utils.h"
2022-04-14 22:41:41 +02:00
# include <algorithm>
# include <coreinit/cache.h>
# include <coreinit/debug.h>
# include <cstdio>
# include <filesystem>
# include <sys/dirent.h>
# include <sys/fcntl.h>
# include <sys/unistd.h>
FSStatus FSWrapper : : FSOpenDirWrapper ( const char * path , FSDirectoryHandle * handle ) {
if ( ! IsPathToReplace ( path ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( handle = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] handle was nullptr " , getName ( ) . c_str ( ) ) ;
return FS_STATUS_FATAL_ERROR ;
}
FSStatus result = FS_STATUS_OK ;
2022-04-29 13:34:04 +02:00
auto dirHandle = getNewDirHandle ( ) ;
if ( dirHandle ) {
2022-04-14 22:41:41 +02:00
DIR * dir ;
auto newPath = GetNewPath ( path ) ;
if ( ( dir = opendir ( newPath . c_str ( ) ) ) ) {
dirHandle - > dir = dir ;
2022-04-29 13:34:04 +02:00
dirHandle - > handle = ( ( ( uint32_t ) dirHandle . get ( ) ) & 0x0FFFFFFF ) | 0x30000000 ;
2022-04-14 22:41:41 +02:00
* handle = dirHandle - > handle ;
dirHandle - > path [ 0 ] = ' \0 ' ;
strncat ( dirHandle - > path , newPath . c_str ( ) , sizeof ( dirHandle - > path ) - 1 ) ;
{
std : : lock_guard < std : : mutex > lock ( openDirsMutex ) ;
openDirs . push_back ( dirHandle ) ;
OSMemoryBarrier ( ) ;
}
} else {
result = FS_STATUS_NOT_FOUND ;
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to alloc dir handle " , getName ( ) . c_str ( ) ) ;
result = FS_STATUS_MAX ;
}
return result ;
}
FSStatus FSWrapper : : FSReadDirWrapper ( FSDirectoryHandle handle , FSDirectoryEntry * entry ) {
if ( ! isValidDirHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
DIR * dir = dirHandle - > dir ;
FSStatus result = FS_STATUS_END ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] readdir %08X (handle %08X) " , getName ( ) . c_str ( ) , dir , handle ) ;
do {
struct dirent * entry_ = readdir ( dir ) ;
if ( entry_ ) {
if ( SkipDeletedFilesInReadDir ( ) & & std : : string_view ( entry_ - > d_name ) . starts_with ( deletePrefix ) ) {
DEBUG_FUNCTION_LINE_ERR ( " Skip file file name %s because of the prefix " , entry_ - > d_name ) ;
continue ;
}
entry - > name [ 0 ] = ' \0 ' ;
strncat ( entry - > name , entry_ - > d_name , sizeof ( entry - > name ) - 1 ) ;
entry - > info . mode = ( FSMode ) FS_MODE_READ_OWNER ;
if ( entry_ - > d_type = = DT_DIR ) {
entry - > info . flags = ( FSStatFlags ) ( ( uint32_t ) FS_STAT_DIRECTORY ) ;
entry - > info . size = 0 ;
} else {
entry - > info . flags = ( FSStatFlags ) 0 ;
if ( strcmp ( entry_ - > d_name , " . " ) = = 0 | | strcmp ( entry_ - > d_name , " .. " ) = = 0 ) {
entry - > info . size = 0 ;
} else {
struct stat sb { } ;
auto strLen = strlen ( dirHandle - > path ) + 1 + strlen ( entry_ - > d_name ) + 1 ;
char path [ strLen ] ;
snprintf ( path , sizeof ( path ) , " %s/%s " , dirHandle - > path , entry_ - > d_name ) ;
if ( stat ( path , & sb ) > = 0 ) {
entry - > info . size = sb . st_size ;
entry - > info . flags = ( FSStatFlags ) 0 ;
entry - > info . owner = sb . st_uid ;
entry - > info . group = sb . st_gid ;
}
}
}
result = FS_STATUS_OK ;
}
break ;
} while ( true ) ;
return result ;
}
FSStatus FSWrapper : : FSCloseDirWrapper ( FSDirectoryHandle handle ) {
if ( ! isValidDirHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
DIR * dir = dirHandle - > dir ;
FSStatus result = FS_STATUS_OK ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] closedir %08X (handle %08X) " , getName ( ) . c_str ( ) , dir , handle ) ;
if ( closedir ( dir ) ! = 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to close dir %08X (handle %08X) " , getName ( ) . c_str ( ) , dir , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
}
dirHandle - > dir = nullptr ;
return result ;
}
FSStatus FSWrapper : : FSRewindDirWrapper ( FSDirectoryHandle handle ) {
if ( ! isValidDirHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
DIR * dir = dirHandle - > dir ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] rewindir %08X (handle %08X) " , getName ( ) . c_str ( ) , dir , handle ) ;
rewinddir ( dir ) ;
return FS_STATUS_OK ;
}
FSStatus FSWrapper : : FSMakeDirWrapper ( const char * path ) {
if ( ! IsPathToReplace ( path ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to create dir %s but layer is not writeable " , getName ( ) . c_str ( ) , path ) ;
return FS_STATUS_ACCESS_ERROR ;
}
DEBUG_FUNCTION_LINE_ERR ( " NOT IMPLEMENTED MAKE DIR " ) ;
return FS_STATUS_FATAL_ERROR ;
}
FSStatus FSWrapper : : FSOpenFileWrapper ( const char * path , const char * mode , FSFileHandle * handle ) {
if ( ! IsPathToReplace ( path ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( path = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] path was nullptr " , getName ( ) . c_str ( ) ) ;
return FS_STATUS_FATAL_ERROR ;
}
if ( mode = = nullptr | | handle = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] mode or handle was nullptr " , getName ( ) . c_str ( ) ) ;
return FS_STATUS_FATAL_ERROR ;
}
auto newPath = GetNewPath ( path ) ;
if ( pCheckIfDeleted & & CheckFileShouldBeIgnored ( newPath ) ) {
return static_cast < FSStatus > ( ( FS_STATUS_NOT_FOUND & 0x0000FFFF ) | FS_STATUS_FORCE_NO_FALLBACK ) ;
}
auto result = FS_STATUS_OK ;
int _mode ;
// Map flags to open modes
if ( ! IsFileModeAllowed ( mode ) ) {
OSReport ( " ## WARN ## [%s] Given mode is not allowed %s " , getName ( ) . c_str ( ) , mode ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Given mode is not allowed %s " , getName ( ) . c_str ( ) , mode ) ;
return FS_STATUS_ACCESS_ERROR ;
}
if ( strcmp ( mode , " r " ) = = 0 | | strcmp ( mode , " rb " ) = = 0 ) {
_mode = 0x000 ;
} else if ( strcmp ( mode , " r+ " ) = = 0 ) {
_mode = 0x002 ;
} else if ( strcmp ( mode , " w " ) = = 0 ) {
_mode = 0x601 ;
} else if ( strcmp ( mode , " w+ " ) = = 0 ) {
_mode = 0x602 ;
} else if ( strcmp ( mode , " a " ) = = 0 ) {
_mode = 0x209 ;
} else if ( strcmp ( mode , " a+ " ) = = 0 ) {
_mode = 0x20A ;
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] mode \" %s \" was allowed but is unsupported " , getName ( ) . c_str ( ) , mode ) ;
return FS_STATUS_ACCESS_ERROR ;
}
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Open %s (as %s) mode %s, " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) , mode ) ;
int32_t fd = open ( newPath . c_str ( ) , _mode ) ;
if ( fd > = 0 ) {
2022-04-29 13:34:04 +02:00
auto fileHandle = getNewFileHandle ( ) ;
2022-04-14 22:41:41 +02:00
if ( fileHandle ) {
std : : lock_guard < std : : mutex > lock ( openFilesMutex ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Opened %s (as %s) mode %s, fd %d (%08X) " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) , mode , fd , handle ) ;
2022-04-29 13:34:04 +02:00
fileHandle - > handle = ( ( ( uint32_t ) fileHandle . get ( ) ) & 0x0FFFFFFF ) | 0x30000000 ;
2022-04-14 22:41:41 +02:00
* handle = fileHandle - > handle ;
fileHandle - > fd = fd ;
openFiles . push_back ( fileHandle ) ;
OSMemoryBarrier ( ) ;
} else {
close ( fd ) ;
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to alloc new fileHandle " , getName ( ) . c_str ( ) ) ;
result = FS_STATUS_MAX ;
}
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] File not found %s (%s) " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) ) ;
result = FS_STATUS_NOT_FOUND ;
}
return result ;
}
FSStatus FSWrapper : : FSCloseFileWrapper ( FSFileHandle handle ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
int real_fd = fileHandle - > fd ;
FSStatus result = FS_STATUS_OK ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Close %d (handle %08X) " , getName ( ) . c_str ( ) , real_fd , handle ) ;
if ( close ( real_fd ) ! = 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to close %d (handle %08X) " , getName ( ) . c_str ( ) , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
}
fileHandle - > fd = - 1 ;
return result ;
}
bool FSWrapper : : CheckFileShouldBeIgnored ( std : : string & path ) {
auto asPath = std : : filesystem : : path ( path ) ;
if ( std : : string ( asPath . filename ( ) . c_str ( ) ) . starts_with ( deletePrefix ) ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " Ignore %s, filename starts with %s " , path . c_str ( ) , deletePrefix . c_str ( ) ) ;
return true ;
}
auto newDelPath = asPath . replace_filename ( deletePrefix + asPath . filename ( ) . c_str ( ) ) ;
struct stat buf { } ;
if ( stat ( newDelPath . c_str ( ) , & buf ) = = 0 ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " Ignore %s, file %s exists " , path . c_str ( ) , newDelPath . c_str ( ) ) ;
return true ;
}
return false ;
}
FSStatus FSWrapper : : FSGetStatWrapper ( const char * path , FSStat * stats ) {
if ( path = = nullptr | | stats = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] path was or stats nullptr " , getName ( ) . c_str ( ) ) ;
return FS_STATUS_FATAL_ERROR ;
}
if ( ! IsPathToReplace ( path ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
auto newPath = GetNewPath ( path ) ;
struct stat path_stat { } ;
if ( pCheckIfDeleted & & CheckFileShouldBeIgnored ( newPath ) ) {
return static_cast < FSStatus > ( ( FS_STATUS_NOT_FOUND & 0x0000FFFF ) | FS_STATUS_FORCE_NO_FALLBACK ) ;
}
FSStatus result = FS_STATUS_OK ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] stat of %s (%s) " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) ) ;
if ( stat ( newPath . c_str ( ) , & path_stat ) < 0 ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Path %s (%s) not found " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) ) ;
result = FS_STATUS_NOT_FOUND ;
} else {
memset ( & ( stats - > flags ) , 0 , sizeof ( stats - > flags ) ) ;
if ( S_ISDIR ( path_stat . st_mode ) ) {
stats - > flags = ( FSStatFlags ) ( ( uint32_t ) FS_STAT_DIRECTORY ) ;
} else {
stats - > size = path_stat . st_size ;
stats - > mode = ( FSMode ) FS_MODE_READ_OWNER ;
stats - > flags = ( FSStatFlags ) 0 ;
stats - > owner = path_stat . st_uid ;
stats - > group = path_stat . st_gid ;
}
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Stats file for %s (%s), size %016llX " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) , stats - > size ) ;
}
return result ;
}
FSStatus FSWrapper : : FSGetStatFileWrapper ( FSFileHandle handle , FSStat * stats ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
int real_fd = fileHandle - > fd ;
struct stat path_stat { } ;
FSStatus result = FS_STATUS_OK ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] fstat of fd %d (FSFileHandle %08X) " , getName ( ) . c_str ( ) , real_fd , handle ) ;
if ( fstat ( real_fd , & path_stat ) < 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] fstat of fd %d (FSFileHandle %08X) failed " , getName ( ) . c_str ( ) , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else {
memset ( & ( stats - > flags ) , 0 , sizeof ( stats - > flags ) ) ;
stats - > size = path_stat . st_size ;
stats - > mode = ( FSMode ) FS_MODE_READ_OWNER ;
stats - > flags = ( FSStatFlags ) 0 ;
stats - > owner = path_stat . st_uid ;
stats - > group = path_stat . st_gid ;
}
return result ;
}
FSStatus FSWrapper : : FSReadFileWrapper ( void * buffer , uint32_t size , uint32_t count , FSFileHandle handle , [[maybe_unused]] uint32_t unk1 ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( size * count = = 0 ) {
return FS_STATUS_OK ;
}
if ( buffer = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] buffer is null but size * count is not 0 (It's: %d) " , getName ( ) . c_str ( ) , size * count ) ;
return FS_STATUS_FATAL_ERROR ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
int real_fd = fileHandle - > fd ;
2022-04-14 22:41:41 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Read %u bytes of fd %08X (FSFileHandle %08X) to buffer %08X " , getName ( ) . c_str ( ) , size * count , real_fd , handle , buffer ) ;
int32_t read = readIntoBuffer ( real_fd , buffer , size , count ) ;
FSStatus result ;
if ( read < 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] read %u bytes of fd %d (FSFileHandle %08X) failed " , getName ( ) . c_str ( ) , size * count , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else {
result = static_cast < FSStatus > ( ( uint32_t ) ( read & 0xFFFFFFFF ) / size ) ;
}
return result ;
}
FSStatus FSWrapper : : FSReadFileWithPosWrapper ( void * buffer , uint32_t size , uint32_t count , uint32_t pos , FSFileHandle handle , int32_t unk1 ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Read from with position. " , getName ( ) . c_str ( ) ) ;
FSStatus result ;
if ( ( result = this - > FSSetPosFileWrapper ( handle , pos ) ) ! = FS_STATUS_OK ) {
return result ;
}
result = this - > FSReadFileWrapper ( buffer , size , count , handle , unk1 ) ;
return result ;
}
FSStatus FSWrapper : : FSSetPosFileWrapper ( FSFileHandle handle , uint32_t pos ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
FSStatus result = FS_STATUS_OK ;
int real_fd = fileHandle - > fd ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] lseek fd %d (FSFileHandle %08X) to get current position for truncation " , getName ( ) . c_str ( ) , real_fd , handle ) ;
if ( lseek ( real_fd , ( off_t ) pos , SEEK_SET ) ! = pos ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] lseek fd %d (FSFileHandle %08X) to position %u failed " , getName ( ) . c_str ( ) , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] pos set to %u for fd %d (FSFileHandle %08X) " , getName ( ) . c_str ( ) , pos , real_fd , handle ) ;
}
return result ;
}
FSStatus FSWrapper : : FSGetPosFileWrapper ( FSFileHandle handle , uint32_t * pos ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
FSStatus result = FS_STATUS_OK ;
int real_fd = fileHandle - > fd ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] lseek fd %08X (FSFileHandle %08X) to get current position for truncation " , getName ( ) . c_str ( ) , real_fd , handle ) ;
off_t currentPos = lseek ( real_fd , ( off_t ) 0 , SEEK_CUR ) ;
if ( currentPos = = - 1 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to get current position (res: %lld) of fd (handle %08X) to check EoF " , getName ( ) . c_str ( ) , currentPos , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else {
* pos = currentPos ;
}
return result ;
}
FSStatus FSWrapper : : FSIsEofWrapper ( FSFileHandle handle ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
FSStatus result ;
int real_fd = fileHandle - > fd ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] lseek fd %08X (FSFileHandle %08X) to get current position for truncation " , getName ( ) . c_str ( ) , real_fd , handle ) ;
off_t currentPos = lseek ( real_fd , ( off_t ) 0 , SEEK_CUR ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] lseek fd %08X (FSFileHandle %08X) to get end position for truncation " , getName ( ) . c_str ( ) , real_fd , handle ) ;
off_t endPos = lseek ( real_fd , ( off_t ) 0 , SEEK_END ) ;
if ( currentPos = = - 1 | | endPos = = - 1 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to get current position (res: %lld) or endPos (res: %lld) of fd (handle %08X) to check EoF " , getName ( ) . c_str ( ) , currentPos , endPos , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else if ( currentPos = = endPos ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] FSIsEof END for %d \n " , getName ( ) . c_str ( ) , real_fd ) ;
result = FS_STATUS_END ;
} else {
lseek ( real_fd , currentPos , SEEK_CUR ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] FSIsEof OK for %d \n " , getName ( ) . c_str ( ) , real_fd ) ;
result = FS_STATUS_OK ;
}
return result ;
}
FSStatus FSWrapper : : FSTruncateFileWrapper ( FSFileHandle handle ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to truncate fd %d (handle %08X) but layer is not writeable " , getName ( ) . c_str ( ) , getFileFromHandle ( handle ) - > fd , handle ) ;
return FS_STATUS_ACCESS_ERROR ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
FSStatus result = FS_STATUS_OK ;
int real_fd = fileHandle - > fd ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] lseek fd %08X (FSFileHandle %08X) to get current position for truncation " , getName ( ) . c_str ( ) , real_fd , handle ) ;
off_t currentPos = lseek ( real_fd , ( off_t ) 0 , SEEK_CUR ) ;
if ( currentPos = = - 1 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to get current position of fd (handle %08X) to truncate file " , getName ( ) . c_str ( ) , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Truncate fd %08X (FSFileHandle %08X) to %lld bytes " , getName ( ) . c_str ( ) , real_fd , handle , currentPos ) ;
if ( ftruncate ( real_fd , currentPos ) < 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] ftruncate failed for fd %08X (FSFileHandle %08X) errno %d " , getName ( ) . c_str ( ) , real_fd , handle , errno ) ;
result = FS_STATUS_MEDIA_ERROR ;
}
}
return result ;
}
FSStatus FSWrapper : : FSWriteFileWrapper ( uint8_t * buffer , uint32_t size , uint32_t count , FSFileHandle handle , [[maybe_unused]] uint32_t unk1 ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to write to fd %d (handle %08X) but layer is not writeable " , getName ( ) . c_str ( ) , getFileFromHandle ( handle ) - > fd , handle ) ;
return FS_STATUS_ACCESS_ERROR ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
FSStatus result ;
int real_fd = fileHandle - > fd ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Write %u bytes to fd %08X (FSFileHandle %08X) from buffer %08X " , getName ( ) . c_str ( ) , count * size , real_fd , handle , buffer ) ;
auto writeRes = writeFromBuffer ( real_fd , buffer , size , count ) ;
if ( writeRes < 0 ) {
auto err = errno ;
DEBUG_FUNCTION_LINE_ERR ( " [%s] Write failed %u bytes to fd %08X (FSFileHandle %08X) from buffer %08X errno %d " , getName ( ) . c_str ( ) , count * size , real_fd , handle , buffer , err ) ;
if ( err = = EFBIG ) {
result = FS_STATUS_FILE_TOO_BIG ;
} else if ( err = = EACCES ) {
result = FS_STATUS_ACCESS_ERROR ;
} else {
result = FS_STATUS_MEDIA_ERROR ;
}
} else {
result = static_cast < FSStatus > ( ( uint32_t ) ( writeRes & 0xFFFFFFFF ) / size ) ;
}
return result ;
}
FSStatus FSWrapper : : FSRemoveWrapper ( const char * path ) {
if ( ! IsPathToReplace ( path ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to remove %s but layer is not writeable " , getName ( ) . c_str ( ) , path ) ;
return FS_STATUS_ACCESS_ERROR ;
}
auto newPath = GetNewPath ( path ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Remove %s (%s) " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) ) ;
if ( remove ( newPath . c_str ( ) ) < 0 ) {
auto err = errno ;
DEBUG_FUNCTION_LINE_ERR ( " [%s] rename failed %s (%s) errno %d " , getName ( ) . c_str ( ) , path , newPath . c_str ( ) , err ) ;
if ( err = = ENOTDIR ) {
return FS_STATUS_NOT_DIR ;
} else if ( err = = EACCES ) {
return FS_STATUS_ACCESS_ERROR ;
} else if ( err = = EISDIR ) {
return FS_STATUS_NOT_FILE ;
} else if ( err = = EPERM ) {
return FS_STATUS_PERMISSION_ERROR ;
}
return FS_STATUS_MEDIA_ERROR ;
}
return FS_STATUS_OK ;
}
FSStatus FSWrapper : : FSRenameWrapper ( const char * oldPath , const char * newPath ) {
if ( ! IsPathToReplace ( oldPath ) | | ! IsPathToReplace ( newPath ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to rename %s to %s but layer is not writeable " , getName ( ) . c_str ( ) , oldPath , newPath ) ;
return FS_STATUS_ACCESS_ERROR ;
}
auto oldPathRedirect = GetNewPath ( oldPath ) ;
auto newPathRedirect = GetNewPath ( newPath ) ;
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Rename %s (%s) -> %s (%s) " , getName ( ) . c_str ( ) , oldPath , oldPathRedirect . c_str ( ) , newPath , newPathRedirect . c_str ( ) ) ;
if ( rename ( oldPathRedirect . c_str ( ) , newPathRedirect . c_str ( ) ) < 0 ) {
auto err = errno ;
DEBUG_FUNCTION_LINE_ERR ( " [%s] Rename failed %s (%s) -> %s (%s). errno %d " , getName ( ) . c_str ( ) , oldPath , oldPathRedirect . c_str ( ) , newPath , newPathRedirect . c_str ( ) , err ) ;
if ( err = = ENOTDIR ) {
return FS_STATUS_NOT_DIR ;
} else if ( err = = EACCES ) {
return FS_STATUS_ACCESS_ERROR ;
} else if ( err = = EISDIR ) {
return FS_STATUS_NOT_FILE ;
} else if ( err = = EPERM ) {
return FS_STATUS_PERMISSION_ERROR ;
}
return FS_STATUS_MEDIA_ERROR ;
}
return FS_STATUS_OK ;
}
FSStatus FSWrapper : : FSFlushFileWrapper ( FSFileHandle handle ) {
if ( ! isValidFileHandle ( handle ) ) {
return FS_STATUS_FORCE_PARENT_LAYER ;
}
if ( ! pIsWriteable ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Tried to fsync fd %d (handle %08X)) but layer is not writeable " , getName ( ) . c_str ( ) , getFileFromHandle ( handle ) - > fd , handle ) ;
return FS_STATUS_ACCESS_ERROR ;
}
2022-04-29 13:34:04 +02:00
auto fileHandle = getFileFromHandle ( handle ) ;
int real_fd = fileHandle - > fd ;
2022-04-14 22:41:41 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] fsync fd %08X (FSFileHandle %08X) " , real_fd , handle ) ;
FSStatus result = FS_STATUS_OK ;
if ( fsync ( real_fd ) < 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] fsync failed for fd %08X (FSFileHandle %08X) " , getName ( ) . c_str ( ) , real_fd , handle ) ;
result = FS_STATUS_MEDIA_ERROR ;
}
return result ;
}
bool FSWrapper : : IsFileModeAllowed ( const char * mode ) {
if ( strcmp ( mode , " r " ) = = 0 | | strcmp ( mode , " rb " ) = = 0 ) {
return true ;
}
if ( pIsWriteable & & ( strcmp ( mode , " r+ " ) = = 0 | |
strcmp ( mode , " w " ) = = 0 | |
strcmp ( mode , " w+ " ) = = 0 | |
strcmp ( mode , " a " ) = = 0 | |
strcmp ( mode , " a+ " ) = = 0 ) ) {
return true ;
}
return false ;
}
bool FSWrapper : : IsPathToReplace ( const std : : string_view & path ) {
return path . starts_with ( pPathToReplace ) ;
}
std : : string FSWrapper : : GetNewPath ( const std : : string_view & path ) {
auto subStr = path . substr ( this - > pPathToReplace . length ( ) ) ;
auto res = string_format ( " %s%.*s " , this - > pReplacePathWith . c_str ( ) , int ( subStr . length ( ) ) , subStr . data ( ) ) ;
2022-04-29 13:34:04 +02:00
std : : replace ( res . begin ( ) , res . end ( ) , ' \\ ' , ' / ' ) ;
2022-04-14 22:41:41 +02:00
uint32_t length = res . size ( ) ;
//! clear path of double slashes
for ( uint32_t i = 1 ; i < length ; + + i ) {
if ( res [ i - 1 ] = = ' / ' & & res [ i ] = = ' / ' ) {
res . erase ( i , 1 ) ;
i - - ;
length - - ;
}
}
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Redirect %.*s -> %s " , getName ( ) . c_str ( ) , int ( path . length ( ) ) , path . data ( ) , res . c_str ( ) ) ;
return res ;
}
bool FSWrapper : : isValidFileHandle ( FSFileHandle handle ) {
std : : lock_guard < std : : mutex > lock ( openFilesMutex ) ;
2022-04-29 13:34:04 +02:00
return std : : ranges : : any_of ( openFiles , [ handle ] ( auto & cur ) { return cur - > handle = = handle ; } ) ;
2022-04-14 22:41:41 +02:00
}
bool FSWrapper : : isValidDirHandle ( FSDirectoryHandle handle ) {
std : : lock_guard < std : : mutex > lock ( openDirsMutex ) ;
2022-04-29 13:34:04 +02:00
return std : : ranges : : any_of ( openDirs , [ handle ] ( auto & cur ) { return cur - > handle = = handle ; } ) ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < FileInfo > FSWrapper : : getNewFileHandle ( ) {
return make_shared_nothrow < FileInfo > ( ) ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < DirInfo > FSWrapper : : getNewDirHandle ( ) {
return make_shared_nothrow < DirInfo > ( ) ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < FileInfo > FSWrapper : : getFileFromHandle ( FSFileHandle handle ) {
2022-04-14 22:41:41 +02:00
std : : lock_guard < std : : mutex > lock ( openFilesMutex ) ;
for ( auto & file : openFiles ) {
if ( file - > handle = = handle ) {
return file ;
}
}
DEBUG_FUNCTION_LINE_ERR ( " [%s] FileInfo for handle %08X was not found. isValidFileHandle check missing? " , getName ( ) . c_str ( ) , handle ) ;
OSFatal ( " Failed to find file handle " ) ;
return nullptr ;
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < DirInfo > FSWrapper : : getDirFromHandle ( FSDirectoryHandle handle ) {
2022-04-14 22:41:41 +02:00
std : : lock_guard < std : : mutex > lock ( openDirsMutex ) ;
for ( auto & dir : openDirs ) {
if ( dir - > handle = = handle ) {
return dir ;
}
}
DEBUG_FUNCTION_LINE_ERR ( " [%s] DirInfo for handle %08X was not found. isValidDirHandle check missing? " , getName ( ) . c_str ( ) , handle ) ;
OSFatal ( " Failed to find dir handle " ) ;
return nullptr ;
}
void FSWrapper : : deleteDirHandle ( FSDirectoryHandle handle ) {
2022-04-29 13:34:04 +02:00
if ( ! remove_locked_first_if ( openDirsMutex , openDirs , [ handle ] ( auto & cur ) { return ( FSFileHandle ) cur - > handle = = handle ; } ) ) {
2022-04-14 22:41:41 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Delete failed because the handle %08X was not found " , getName ( ) . c_str ( ) , handle ) ;
}
}
void FSWrapper : : deleteFileHandle ( FSFileHandle handle ) {
2022-04-29 13:34:04 +02:00
if ( ! remove_locked_first_if ( openFilesMutex , openFiles , [ handle ] ( auto & cur ) { return ( FSFileHandle ) cur - > handle = = handle ; } ) ) {
2022-04-14 22:41:41 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Delete failed because the handle %08X was not found " , getName ( ) . c_str ( ) , handle ) ;
}
}
bool FSWrapper : : SkipDeletedFilesInReadDir ( ) {
return true ;
}