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 ,
FSDirectoryHandle * handle ) {
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 ;
if ( pFSClient & & pCmdBlock ) {
FSDirectoryHandle realHandle = 0 ;
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call real_FSOpenDir for %s with error_flag %08X " , getName ( ) . c_str ( ) , path , this - > getHandle ( ) ) ;
2022-04-14 22:41:41 +02:00
// Call FSOpen with "this" as errorFlag call FSOpen for "parent" layers only.
2022-04-29 13:34:04 +02:00
if ( FSOpenDir ( pFSClient , pCmdBlock , path , & realHandle , ( FSErrorFlag ) this - > getHandle ( ) ) = = FS_STATUS_OK ) {
2022-04-14 22:41:41 +02:00
dirHandle - > realDirHandle = realHandle ;
} else {
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Failed to open real dir %s " , getName ( ) . c_str ( ) , path ) ;
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Global FSClient or FSCmdBlock were null " , getName ( ) . c_str ( ) ) ;
}
OSMemoryBarrier ( ) ;
}
}
return res ;
}
bool FSWrapperMergeDirsWithParent : : SkipDeletedFilesInReadDir ( ) {
return false ;
}
2022-08-07 19:22:20 +02:00
FSError FSWrapperMergeDirsWithParent : : FSReadDirWrapper ( FSDirectoryHandle handle , FSDirectoryEntry * 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-04-14 22:41:41 +02:00
OSFatal ( " Failed to alloc memory for read result " ) ;
}
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-04-14 22:41:41 +02:00
OSFatal ( " Failed to alloc memory for read result " ) ;
}
}
memcpy ( & dirHandle - > readResult [ dirHandle - > readResultNumberOfEntries ] . realEntry , entry , sizeof ( FSDirectoryEntry ) ) ;
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 ) {
if ( pFSClient & & pCmdBlock ) {
FSDirectoryEntry realDirEntry ;
FSStatus readDirResult ;
while ( true ) {
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call real_FSReadDir for %08X with error_flag %08X " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , ( uint32_t ) this - > getHandle ( ) ) ;
readDirResult = FSReadDir ( pFSClient , pCmdBlock , dirHandle - > realDirHandle , & realDirEntry , ( FSErrorFlag ) ( uint32_t ) this - > getHandle ( ) ) ;
2022-04-14 22:41:41 +02:00
if ( readDirResult = = FS_STATUS_OK ) {
bool found = false ;
auto nameDeleted = deletePrefix + realDirEntry . name ;
for ( int i = 0 ; i < dirHandle - > readResultNumberOfEntries ; i + + ) {
auto curResult = & dirHandle - > readResult [ i ] ;
// Don't return file that are "deleted"
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 ) {
memcpy ( entry , & realDirEntry , sizeof ( FSDirectoryEntry ) ) ;
2022-08-07 19:22:20 +02:00
res = FS_ERROR_OK ;
2022-04-14 22:41:41 +02:00
break ;
}
} else if ( readDirResult = = FS_STATUS_END ) {
2022-08-07 19:22:20 +02:00
res = FS_ERROR_END_OF_DIR ;
2022-04-14 22:41:41 +02:00
break ;
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] real_FSReadDir returned an unexpected error: %08X " , getName ( ) . c_str ( ) , 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 {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Global FSClient or FSCmdBlock were null " , getName ( ) . c_str ( ) ) ;
}
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Unexpected result %d " , getName ( ) . c_str ( ) , res ) ;
}
}
return res ;
} while ( true ) ;
}
2022-08-07 19:22:20 +02:00
FSError FSWrapperMergeDirsWithParent : : FSCloseDirWrapper ( FSDirectoryHandle 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 ) {
if ( pFSClient & & pCmdBlock ) {
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call FSCloseDir for %08X with error_flag %08X (this) " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , ( uint32_t ) this - > getHandle ( ) ) ;
auto realResult = FSCloseDir ( pFSClient , pCmdBlock , dirHandle - > realDirHandle , ( FSErrorFlag ) ( uint32_t ) this - > getHandle ( ) ) ;
2022-04-14 22:41:41 +02:00
if ( realResult = = FS_STATUS_OK ) {
dirHandle - > realDirHandle = 0 ;
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to close realDirHandle %d: res %d " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , realResult ) ;
2022-08-07 19:22:20 +02:00
return realResult = = FS_STATUS_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR ;
2022-04-14 22:41:41 +02:00
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Global FSClient or FSCmdBlock were null " , getName ( ) . c_str ( ) ) ;
}
}
if ( dirHandle - > readResult ! = nullptr ) {
free ( dirHandle - > readResult ) ;
dirHandle - > readResult = nullptr ;
dirHandle - > readResultCapacity = 0 ;
dirHandle - > readResultNumberOfEntries = 0 ;
}
OSMemoryBarrier ( ) ;
}
return res ;
}
2022-08-07 19:22:20 +02:00
FSError FSWrapperMergeDirsWithParent : : FSRewindDirWrapper ( FSDirectoryHandle 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 ) {
if ( pFSClient & & pCmdBlock ) {
2022-04-29 13:34:04 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " [%s] Call real_FSRewindDir for %08X with error_flag %08X (this->getHandle()) " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle , ( uint32_t ) this - > getHandle ( ) ) ;
if ( FSRewindDir ( pFSClient , pCmdBlock , dirHandle - > realDirHandle , ( FSErrorFlag ) ( uint32_t ) this - > getHandle ( ) ) = = FS_STATUS_OK ) {
2022-04-14 22:41:41 +02:00
dirHandle - > realDirHandle = 0 ;
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to rewind dir for realDirHandle %08X " , getName ( ) . c_str ( ) , dirHandle - > realDirHandle ) ;
}
} else {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Global FSClient or FSCmdBlock were null " , getName ( ) . c_str ( ) ) ;
}
}
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 ) {
pFSClient = new ( std : : nothrow ) FSClient ;
pCmdBlock = new ( std : : nothrow ) FSCmdBlock ;
if ( pFSClient = = nullptr | | pCmdBlock = = nullptr ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to alloc client or cmdBlock " , name . c_str ( ) ) ;
freeFSClient ( ) ;
}
if ( FSAddClient ( pFSClient , FS_ERROR_FLAG_ALL ) ! = FS_STATUS_OK ) {
DEBUG_FUNCTION_LINE_ERR ( " [%s] Failed to addClient " ) ;
freeFSClient ( ) ;
}
FSInitCmdBlock ( pCmdBlock ) ;
}
FSWrapperMergeDirsWithParent : : ~ FSWrapperMergeDirsWithParent ( ) {
freeFSClient ( ) ;
}
void FSWrapperMergeDirsWithParent : : freeFSClient ( ) {
if ( pFSClient ) {
FSDelClient ( pFSClient , FS_ERROR_FLAG_ALL ) ;
}
delete pFSClient ;
delete pCmdBlock ;
pFSClient = nullptr ;
pCmdBlock = nullptr ;
}
2022-04-29 13:34:04 +02:00
std : : shared_ptr < DirInfoEx > FSWrapperMergeDirsWithParent : : getDirExFromHandle ( FSDirectoryHandle handle ) {
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 ) ;
OSFatal ( " 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
}