2022-04-14 22:41:41 +02:00
# include "FSWrapperMergeDirsWithParent.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 <coreinit/cache.h>
# include <coreinit/debug.h>
# include <coreinit/filesystem.h>
# include <filesystem>
2022-08-07 19:22:20 +02:00
FSError FSWrapperMergeDirsWithParent : : FSOpenDirWrapper ( const char * path ,
2022-09-10 21:24:58 +02:00
FSADirectoryHandle * handle ) {
2022-08-07 19:22:20 +02:00
if ( handle = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] handle was NULL " , getName ( ) . c_str ( ) ) ;
return FS_ERROR_INVALID_PARAM ;
}
2022-04-14 22:41:41 +02:00
auto res = FSWrapper : : FSOpenDirWrapper ( path , handle ) ;
2022-08-07 19:22:20 +02:00
if ( res = = FS_ERROR_OK ) {
if ( ! isValidDirHandle ( * handle ) ) {
FSWrapper : : FSCloseDirWrapper ( * handle ) ;
2022-04-14 22:41:41 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] No valid dir handle %08X " , getName ( ) . c_str ( ) , * handle ) ;
2022-08-07 19:22:20 +02:00
return FS_ERROR_INVALID_DIRHANDLE ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirExFromHandle ( * handle ) ;
2022-04-14 22:41:41 +02:00
if ( dirHandle ! = nullptr ) {
dirHandle - > readResultCapacity = 0 ;
dirHandle - > readResultNumberOfEntries = 0 ;
dirHandle - > realDirHandle = 0 ;
2022-09-10 21:24:58 +02:00
if ( clientHandle ) {
FSADirectoryHandle realHandle = 0 ;
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call FSAOpenDir with %s for parent layer " , getName ( ) . c_str ( ) , path ) ;
FSError err ;
if ( ( err = FSAOpenDir ( clientHandle , path , & realHandle ) ) = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
dirHandle - > realDirHandle = realHandle ;
} else {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to open real dir %s. %s (%d) " , getName ( ) . c_str ( ) , path , FSAGetStatusStr ( err ) , err ) ;
2022-04-14 22:41:41 +02:00
}
} else {
2022-09-10 21:24:58 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] clientHandle was null " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
OSMemoryBarrier ( ) ;
}
}
return res ;
}
bool FSWrapperMergeDirsWithParent : : SkipDeletedFilesInReadDir ( ) {
return false ;
}
2022-09-10 21:24:58 +02:00
FSError FSWrapperMergeDirsWithParent : : FSReadDirWrapper ( FSADirectoryHandle handle , FSADirectoryEntry * entry ) {
2022-04-14 22:41:41 +02:00
do {
auto res = FSWrapper : : FSReadDirWrapper ( handle , entry ) ;
2022-08-07 19:22:20 +02:00
if ( res = = FS_ERROR_OK | | res = = FS_ERROR_END_OF_DIR ) {
2022-04-14 22:41:41 +02:00
if ( ! isValidDirHandle ( handle ) ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] No valid dir handle %08X " , getName ( ) . c_str ( ) , handle ) ;
2022-08-07 19:22:20 +02:00
return FS_ERROR_INVALID_DIRHANDLE ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirExFromHandle ( handle ) ;
2022-08-07 19:22:20 +02:00
if ( res = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
if ( dirHandle - > readResultCapacity = = 0 ) {
dirHandle - > readResult = ( FSDirectoryEntryEx * ) malloc ( sizeof ( FSDirectoryEntryEx ) ) ;
if ( dirHandle - > readResult = = nullptr ) {
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to alloc memory for %08X (handle %08X) " , getName ( ) . c_str ( ) , dirHandle . get ( ) , handle ) ;
2022-09-10 21:24:58 +02:00
OSFatal ( " ContentRedirectionModule: Failed to alloc memory for read result " ) ;
2022-04-14 22:41:41 +02:00
}
dirHandle - > readResultCapacity = 1 ;
}
if ( dirHandle - > readResultNumberOfEntries > = dirHandle - > readResultCapacity ) {
auto newCapacity = dirHandle - > readResultCapacity * 2 ;
dirHandle - > readResult = ( FSDirectoryEntryEx * ) realloc ( dirHandle - > readResult , newCapacity * sizeof ( FSDirectoryEntryEx ) ) ;
dirHandle - > readResultCapacity = newCapacity ;
if ( dirHandle - > readResult = = nullptr ) {
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to realloc memory for %08X (handle %08X) " , getName ( ) . c_str ( ) , dirHandle . get ( ) , handle ) ;
2022-09-10 21:24:58 +02:00
OSFatal ( " ContentRedirectionModule: Failed to alloc memory for read result " ) ;
2022-04-14 22:41:41 +02:00
}
}
2022-09-10 21:24:58 +02:00
memcpy ( & dirHandle - > readResult [ dirHandle - > readResultNumberOfEntries ] . realEntry , entry , sizeof ( FSADirectoryEntry ) ) ;
2022-04-14 22:41:41 +02:00
dirHandle - > readResultNumberOfEntries + + ;
/**
2022-08-07 19:22:20 +02:00
* Read the next entry if this entry starts with deletePrefix . We keep the entry but mark it as deleted .
2022-04-14 22:41:41 +02:00
*/
if ( std : : string_view ( entry - > name ) . starts_with ( deletePrefix ) ) {
dirHandle - > readResult [ dirHandle - > readResultNumberOfEntries ] . isMarkedAsDeleted = true ;
OSMemoryBarrier ( ) ;
continue ;
}
OSMemoryBarrier ( ) ;
2022-08-07 19:22:20 +02:00
} else if ( res = = FS_ERROR_END_OF_DIR ) {
2022-04-14 22:41:41 +02:00
// Read the real directory.
if ( dirHandle - > realDirHandle ! = 0 ) {
2022-09-10 21:24:58 +02:00
if ( clientHandle ) {
FSADirectoryEntry realDirEntry ;
FSError readDirResult ;
2022-04-14 22:41:41 +02:00
while ( true ) {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call FSReadDir with %08X for parent layer " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle ) ;
2022-09-10 21:24:58 +02:00
readDirResult = FSAReadDir ( clientHandle , dirHandle - > realDirHandle , & realDirEntry ) ;
if ( readDirResult = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
bool found = false ;
auto nameDeleted = deletePrefix + realDirEntry . name ;
for ( int i = 0 ; i < dirHandle - > readResultNumberOfEntries ; i + + ) {
auto curResult = & dirHandle - > readResult [ i ] ;
2022-09-10 21:24:58 +02:00
// Don't return files that are "deleted"
2022-04-14 22:41:41 +02:00
if ( strcmp ( curResult - > realEntry . name , nameDeleted . c_str ( ) ) = = 0 ) {
found = true ;
break ;
}
// Check if this is a new result
if ( strcmp ( curResult - > realEntry . name , realDirEntry . name ) = = 0 & & ! curResult - > isMarkedAsDeleted ) {
found = true ;
break ;
}
}
// If it's new we can use it :)
if ( ! found ) {
2022-09-10 21:24:58 +02:00
memcpy ( entry , & realDirEntry , sizeof ( FSADirectoryEntry ) ) ;
2022-08-07 19:22:20 +02:00
res = FS_ERROR_OK ;
2022-04-14 22:41:41 +02:00
break ;
}
2022-09-10 21:24:58 +02:00
} else if ( readDirResult = = FS_ERROR_END_OF_DIR ) {
2022-08-07 19:22:20 +02:00
res = FS_ERROR_END_OF_DIR ;
2022-04-14 22:41:41 +02:00
break ;
} else {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] real_FSReadDir returned an unexpected error: %s (%d) " , getName ( ) . c_str ( ) , FSAGetStatusStr ( readDirResult ) , readDirResult ) ;
2022-08-07 19:22:20 +02:00
res = FS_ERROR_END_OF_DIR ;
2022-04-14 22:41:41 +02:00
break ;
}
}
} else {
2022-09-10 21:24:58 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] clientHandle was null " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Unexpected result %d " , getName ( ) . c_str ( ) , res ) ;
}
}
return res ;
} while ( true ) ;
}
2022-09-10 21:24:58 +02:00
FSError FSWrapperMergeDirsWithParent : : FSCloseDirWrapper ( FSADirectoryHandle handle ) {
2022-04-14 22:41:41 +02:00
auto res = FSWrapper : : FSCloseDirWrapper ( handle ) ;
2022-08-07 19:22:20 +02:00
if ( res = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
if ( ! isValidDirHandle ( handle ) ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] No valid dir handle %08X " , getName ( ) . c_str ( ) , handle ) ;
2022-08-07 19:22:20 +02:00
return FS_ERROR_INVALID_DIRHANDLE ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirExFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
if ( dirHandle - > realDirHandle ! = 0 ) {
2022-09-10 21:24:58 +02:00
if ( clientHandle ) {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call FSCloseDir with %08X for parent layer " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle ) ;
2022-09-10 21:24:58 +02:00
auto realResult = FSACloseDir ( clientHandle , dirHandle - > realDirHandle ) ;
if ( realResult = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
dirHandle - > realDirHandle = 0 ;
} else {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to close realDirHandle %d: res %s (%d) " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , FSAGetStatusStr ( realResult ) , realResult ) ;
2022-09-10 21:24:58 +02:00
return realResult = = FS_ERROR_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR ;
2022-04-14 22:41:41 +02:00
}
} else {
2022-09-10 21:24:58 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] clientHandle was null " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
2022-10-10 19:27:49 +02:00
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] dirHandle->realDirHandle was 0 " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
if ( dirHandle - > readResult ! = nullptr ) {
free ( dirHandle - > readResult ) ;
dirHandle - > readResult = nullptr ;
dirHandle - > readResultCapacity = 0 ;
dirHandle - > readResultNumberOfEntries = 0 ;
}
OSMemoryBarrier ( ) ;
}
return res ;
}
2022-09-10 21:24:58 +02:00
FSError FSWrapperMergeDirsWithParent : : FSRewindDirWrapper ( FSADirectoryHandle handle ) {
2022-04-14 22:41:41 +02:00
auto res = FSWrapper : : FSRewindDirWrapper ( handle ) ;
2022-08-07 19:22:20 +02:00
if ( res = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
if ( ! isValidDirHandle ( handle ) ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] No valid dir handle %08X " , getName ( ) . c_str ( ) , handle ) ;
2022-08-07 19:22:20 +02:00
return FS_ERROR_INVALID_DIRHANDLE ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
auto dirHandle = getDirExFromHandle ( handle ) ;
2022-04-14 22:41:41 +02:00
if ( dirHandle - > readResult ! = nullptr ) {
dirHandle - > readResultNumberOfEntries = 0 ;
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wclass-memaccess"
memset ( dirHandle - > readResult , 0 , sizeof ( FSDirectoryEntryEx ) * dirHandle - > readResultCapacity ) ;
# pragma GCC diagnostic pop
}
if ( dirHandle - > realDirHandle ! = 0 ) {
2022-09-10 21:24:58 +02:00
if ( clientHandle ) {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call FSARewindDir with %08X for parent layer " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle ) ;
FSError err ;
if ( ( err = FSARewindDir ( clientHandle , dirHandle - > realDirHandle ) ) = = FS_ERROR_OK ) {
2022-04-14 22:41:41 +02:00
dirHandle - > realDirHandle = 0 ;
} else {
2022-10-10 19:27:49 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to rewind dir for realDirHandle %08X. %s (%d) " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , FSAGetStatusStr ( err ) , err ) ;
2022-04-14 22:41:41 +02:00
}
} else {
2022-09-10 21:24:58 +02:00
DEBUG_FUNCTION_LINE_ERR ( " [%s] clientHandle was null " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
2022-10-10 19:27:49 +02:00
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] dirHandle->realDirHandle was 0 " , getName ( ) . c_str ( ) ) ;
2022-04-14 22:41:41 +02:00
}
OSMemoryBarrier ( ) ;
}
return res ;
}
FSWrapperMergeDirsWithParent : : FSWrapperMergeDirsWithParent ( const std : : string & name ,
const std : : string & pathToReplace ,
const std : : string & replaceWithPath ,
bool fallbackOnError ) : FSWrapper ( name ,
pathToReplace ,
replaceWithPath ,
fallbackOnError ,
false ) {
2022-10-10 19:22:31 +02:00
FSAInit ( ) ;
2022-09-10 21:24:58 +02:00
this - > clientHandle = FSAAddClient ( nullptr ) ;
if ( clientHandle < 0 ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] FSAClientHandle failed: %s (%d) " , name . c_str ( ) , FSAGetStatusStr ( static_cast < FSError > ( clientHandle ) ) , clientHandle ) ;
clientHandle = 0 ;
2022-04-14 22:41:41 +02:00
}
}
FSWrapperMergeDirsWithParent : : ~ FSWrapperMergeDirsWithParent ( ) {
2022-09-10 21:24:58 +02:00
if ( clientHandle ) {
FSError res ;
if ( ( res = FSADelClient ( clientHandle ) ) ! = FS_ERROR_OK ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] FSADelClient failed: %s (%d) " , FSAGetStatusStr ( res ) , res ) ;
}
clientHandle = 0 ;
2022-04-14 22:41:41 +02:00
}
}
2022-09-10 21:24:58 +02:00
std : : shared_ptr < DirInfoEx > FSWrapperMergeDirsWithParent : : getDirExFromHandle ( FSADirectoryHandle handle ) {
2022-04-29 13:34:04 +02:00
auto dir = std : : dynamic_pointer_cast < DirInfoEx > ( getDirFromHandle ( handle ) ) ;
if ( ! dir ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] dynamic_pointer_cast<DirInfoEx *>(%08X) failed " , getName ( ) . c_str ( ) , handle ) ;
2022-09-10 21:24:58 +02:00
OSFatal ( " ContentRedirectionModule: dynamic_pointer_cast<DirInfoEx *> failed " ) ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
return dir ;
2022-04-14 22:41:41 +02:00
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < DirInfo > FSWrapperMergeDirsWithParent : : getNewDirHandle ( ) {
return make_shared_nothrow < DirInfoEx > ( ) ;
2022-04-14 22:41:41 +02:00
}