/*---------------------------------------------------------------------------* Project: TwlSDK - FS - libraries File: fs_archive_fatfs.c Copyright 2007-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2009-02-02#$ $Rev: 9950 $ $Author: nakayasu_toshiko $ *---------------------------------------------------------------------------*/ #ifdef SDK_TWL #include #include #include #include #include #include #include #include #include #include "../include/util.h" #include "../include/command.h" #include "../include/rom.h" #if defined(FS_IMPLEMENT) #include /*---------------------------------------------------------------------------*/ /* Constants */ // Characters that cannot be used in entry names of paths extern const u16 *FSiPathInvalidCharactersW; const u16 *FSiPathInvalidCharactersW = L":*?\"<>|"; /*---------------------------------------------------------------------------*/ /* Variables */ static int FSiSwitchableWramSlots = 0; static FSFATFSArchiveContext FSiFATFSDriveDefault[FS_MOUNTDRIVE_MAX] ATTRIBUTE_ALIGN(32); static FATFSRequestBuffer FSiFATFSAsyncRequestDefault[FS_MOUNTDRIVE_MAX] ATTRIBUTE_ALIGN(32); static u8 FSiTemporaryBufferDefault[FS_TEMPORARY_BUFFER_MAX] ATTRIBUTE_ALIGN(32); /*---------------------------------------------------------------------------*/ /* Functions */ /*---------------------------------------------------------------------------* * Implementation related to customize *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: FSiFATFSDrive Description: Context array that manages the archive of a FAT base Ordinarily, an array size for the quantity of FS_MOUNTDRIVE_MAX is required, and in default, static variables in the LTDMAIN segment are used. With applications built using a special memory arrangment, it is possible to set the proper buffer by changing this variable internally by calling the FSi_SetupFATBuffers function that was over-ridden. Arguments: None. Returns: Buffer for the amount of the FS_MOUNTDRIVE_MAX of the FSFATFSArchiveContext structure *---------------------------------------------------------------------------*/ FSFATFSArchiveContext *FSiFATFSDrive = NULL; /*---------------------------------------------------------------------------* Name: FSiFATFSAsyncRequest Description: Command buffer that is used in asynchronous processing by the FAT base archive. Ordinarily, an array size for the quantity of FS_MOUNTDRIVE_MAX is required, and in default, static variables in the LTDMAIN segment are used. With applications built using a special memory arrangment, it is possible to set the proper buffer by changing this variable internally by calling the FSi_SetupFATBuffers function that was over-ridden. Arguments: None. Returns: Static command buffer of the FS_TEMPORARY_BUFFER_MAX byte *---------------------------------------------------------------------------*/ FATFSRequestBuffer *FSiFATFSAsyncRequest = NULL; /*---------------------------------------------------------------------------* Name: FSiTemporaryBuffer Description: Pointer to the static temporary buffer for issuing read/write commands. It must be memory that can be referenced by both ARM9/ARM7, and by default a static variable in the LTDMAIN segment is used. For applications constructed using a special memory layout, you can change these variables to set the appropriate buffer before calling the FS_Init function. Arguments: None. Returns: Static command buffer of the FS_TEMPORARY_BUFFER_MAX byte *---------------------------------------------------------------------------*/ u8 *FSiTemporaryBuffer = NULL; /*---------------------------------------------------------------------------* Name: FSi_SetupFATBuffers Description: Initializes various buffers needed by the FAT base archive. With applications built using a special memory arrangment, it is possible to independently set the various buffers by over-riding this variable and suppressing the required memory size. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL void FSi_SetupFATBuffers(void) { FSiFATFSDrive = FSiFATFSDriveDefault; FSiFATFSAsyncRequest = FSiFATFSAsyncRequestDefault; FSiTemporaryBuffer = FSiTemporaryBufferDefault; } /*---------------------------------------------------------------------------* Name: FSi_IsValidAddressForARM7 Description: Determines whether this is a buffer accessible from ARM7. With applications built using a special memory layout, it is possible to redefine the proper determination routine by overriding this function. Arguments: buffer: Buffer to be determined length: Buffer length Returns: TRUE if it is a buffer accessible from ARM7. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL BOOL FSi_IsValidAddressForARM7(const void *buffer, u32 length) __attribute__((never_inline)) { u32 addr = (u32)buffer; u32 dtcm = OS_GetDTCMAddress(); if ((addr + length > dtcm) && (addr < dtcm + HW_DTCM_SIZE)) { return FALSE; } if ((addr >= HW_TWL_MAIN_MEM) && (addr + length <= HW_TWL_MAIN_MEM_END)) { return TRUE; } if ((addr >= HW_EXT_WRAM_ARM7) && (addr + length <= GX_GetSizeOfARM7())) { return TRUE; } // Allow if it is a switchable WRAM not overlapping the slot boundary. if ((addr >= HW_WRAM_AREA) && (addr <= HW_WRAM_AREA_END) && (MATH_ROUNDDOWN(addr, MI_WRAM_B_SLOT_SIZE) + MI_WRAM_B_SLOT_SIZE == MATH_ROUNDUP(addr + length, MI_WRAM_B_SLOT_SIZE))) { MIWramPos type; int slot = MIi_AddressToWramSlot(buffer, &type); if (slot >= 0) { if ((((FSiSwitchableWramSlots >> ((type == MI_WRAM_B) ? 0 : 8)) & (1 << slot)) != 0) && // If success is not always possible by switching, the application guarantees it. ((MI_GetWramBankMaster(type, slot) == MI_WRAM_ARM7) || (MI_SwitchWramSlot(type, slot, MI_WRAM_SIZE_32KB, MI_GetWramBankMaster(type, slot), MI_WRAM_ARM7) >= 0))) { return TRUE; } } } return FALSE; } /*---------------------------------------------------------------------------* Name: FSi_SetSwitchableWramSlots Description: Specifies WRAM slot that the FS library can switch to ARM7 depending on the circumstances. Arguments: bitsB: WRAM-B slot bit collection bitsC: WRAM-C slot bit collection Returns: None. *---------------------------------------------------------------------------*/ void FSi_SetSwitchableWramSlots(int bitsB, int bitsC) { FSiSwitchableWramSlots = (bitsB << 0) | (bitsC << 8); } /*---------------------------------------------------------------------------* Name: FSi_AllocUnicodeFullPath Description: Gets full path linking the archive name and relative path. Arguments: context: FSFATFSArchiveContext structure relpath: Relative path under the archive Returns: Buffer that stores the full Unicode path that begins from the archive name. *---------------------------------------------------------------------------*/ static u16* FSi_AllocUnicodeFullPath(FSFATFSArchiveContext *context, const char *relpath) { u16 *dst = FSi_GetUnicodeBuffer(NULL); { int pos = 0; int dstlen; // First link the archive name and the relative path dstlen = FS_ARCHIVE_FULLPATH_MAX - pos - 2; (void)FSi_ConvertStringSjisToUnicode(&dst[pos], &dstlen, FS_GetArchiveName(context->arc), NULL, NULL); pos += dstlen; dst[pos++] = L':'; dst[pos++] = L'/'; dstlen = FS_ARCHIVE_FULLPATH_MAX - pos; (void)FSi_ConvertStringSjisToUnicode(&dst[pos], &dstlen, relpath, NULL, NULL); pos += dstlen; // Remove trailing forward slashes ('/') if ((pos > 0) && ((dst[pos - 1] == L'\\') || (dst[pos - 1] == L'/'))) { --pos; } dst[pos] = L'\0'; } return dst; } /*---------------------------------------------------------------------------* Name: FSi_DostimeToFstime Description: Converts FAT DOS time stamp to an FSDateTime format Arguments: dst: FSDateTime structure that stores the conversion results src: DOS time stamp that is the conversion source Returns: None. *---------------------------------------------------------------------------*/ static void FSi_DostimeToFstime(FSDateTime *dst, u32 src) { dst->year = FATFS_DOSTIME_TO_YEAR(src); dst->month = FATFS_DOSTIME_TO_MON(src); dst->day = FATFS_DOSTIME_TO_MDAY(src); dst->hour = FATFS_DOSTIME_TO_HOUR(src); dst->minute = FATFS_DOSTIME_TO_MIN(src); dst->second = FATFS_DOSTIME_TO_SEC(src); } /*---------------------------------------------------------------------------* Name: FSi_FstimeToDostime Description: Converts FSDateTime to a FAT DOS time stamp format Arguments: dst: DOS time stamp that stores the conversion results src: FSDateTime structure that is the conversion source Returns: None. *---------------------------------------------------------------------------*/ static void FSi_FstimeToDostime(u32 *dst, const FSDateTime *src) { *dst = FATFS_DATETIME_TO_DOSTIME(src->year, src->month, src->day, src->hour, src->minute, src->second); } /*---------------------------------------------------------------------------* Name: FSi_CheckFstime Description: Checks the FSDateTime Arguments: src: FSDateTime structure Returns: TRUE or FALSE. *---------------------------------------------------------------------------*/ static BOOL FSi_CheckFstime( const FSDateTime *fstime) { if( fstime->month / 13 != 0) { return FALSE;} // if( fstime->day / 32 != 0) { return FALSE;} if( fstime->hour / 24 != 0) { return FALSE;} if( fstime->minute/ 60 != 0) { return FALSE;} if( fstime->second/ 61 != 0) { return FALSE;} return( TRUE); } /*---------------------------------------------------------------------------* Name: FSi_GetUnicodeSpanExcluding Description: Gets the string length not including specified characters. Arguments: src: Scanning target string pattern: Characters to be searched for Returns: String length, not including specified characters. *---------------------------------------------------------------------------*/ static int FSi_GetUnicodeSpanExcluding(const u16 *src, const u16 *pattern) { int pos = 0; BOOL found = FALSE; for (; src[pos]; ++pos) { int i; for (i = 0; pattern[i]; ++i) { if (src[pos] == pattern[i]) { found = TRUE; break; } } if (found) { break; } } return pos; } /*---------------------------------------------------------------------------* Name: FSi_UsingInvalidCharacterW Description: Determines whether an inappropriate character is being used as the path name. However, the "arcname:/<***>" is allowed as a special path. Arguments: path: Full path string targeted for scanning Returns: TRUE if using an inappropriate character. *---------------------------------------------------------------------------*/ static BOOL FSi_UsingInvalidCharacterW(const u16 *path) { BOOL retval = FALSE; const u16 *list = FSiPathInvalidCharactersW; if (list && *list) { BOOL foundLT = FALSE; int pos = 0; // Skip archive name while (path[pos] && (path[pos] != L':')) { ++pos; } // Skip archive separation pos += (path[pos] == L':'); pos += (path[pos] == L'/'); // Search for prohibited characters considering special paths if (path[pos] == L'<') { foundLT = TRUE; ++pos; } // Confirm whether prohibited characters are being used while (path[pos]) { pos += FSi_GetUnicodeSpanExcluding(&path[pos], list); if (path[pos]) { if (foundLT && (path[pos] == L'>') && (path[pos + 1] == L'\0')) { foundLT = FALSE; pos += 1; } else { retval = TRUE; break; } } } retval |= foundLT; // Warn if using prohibited characters if (retval) { static BOOL logOnce = FALSE; if (!logOnce) { OS_TWarning("specified path includes invalid character '%c'\n", (char)path[pos]); logOnce = TRUE; } } } return retval; } /*---------------------------------------------------------------------------* Name: FSi_ConvertError Description: Converts FATFS library error codes to FS library error codes. Arguments: error: FATFS library error codes Returns: FS library error codes. *---------------------------------------------------------------------------*/ FSResult FSi_ConvertError(u32 error) { if (error == FATFS_RESULT_SUCCESS) { return FS_RESULT_SUCCESS; } else if (error == FATFS_RESULT_BUSY) { return FS_RESULT_BUSY; } else if (error == FATFS_RESULT_FAILURE) { return FS_RESULT_FAILURE; } else if (error == FATFS_RESULT_UNSUPPORTED) { return FS_RESULT_UNSUPPORTED; } else if (error == FATFS_RESULT_INVALIDPARAM) { return FS_RESULT_INVALID_PARAMETER; } else if (error == FATFS_RESULT_ALREADYDONE) { return FS_RESULT_ALREADY_DONE; } else if (error == FATFS_RESULT_PERMISSIONDENIDED) { return FS_RESULT_PERMISSION_DENIED; } else if (error == FATFS_RESULT_NOMORERESOURCE) { return FS_RESULT_NO_MORE_RESOURCE; } else if (error == FATFS_RESULT_MEDIAFATAL) { return FS_RESULT_MEDIA_FATAL; } else if (error == FATFS_RESULT_NOENTRY) { return FS_RESULT_NO_ENTRY; } else if (error == FATFS_RESULT_MEDIANOTHING) { return FS_RESULT_MEDIA_NOTHING; } else if (error == FATFS_RESULT_MEDIAUNKNOWN) { return FS_RESULT_MEDIA_UNKNOWN; } else if (error == FATFS_RESULT_BADFORMAT) { return FS_RESULT_BAD_FORMAT; } else if (error == FATFS_RESULT_CANCELED) { return FS_RESULT_CANCELED; } else { return FS_RESULT_ERROR; } } /*---------------------------------------------------------------------------* Name: FSi_FATFSAsyncDone Description: Notifies completion of FATFS asynchronous process Arguments: buffer: Request structure Returns: None. *---------------------------------------------------------------------------*/ static void FSi_FATFSAsyncDone(FATFSRequestBuffer *buffer) { FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)buffer->userdata; FS_NotifyArchiveAsyncEnd(context->arc, FSi_ConvertError(buffer->header.result)); } /*---------------------------------------------------------------------------* Name: FSi_FATFS_GetArchiveCaps Description: The FS_COMMAND_GETARCHIVECAPS command. Arguments: arc: The calling archive caps: Location to save the device capability flag Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_GetArchiveCaps(FSArchive *arc, u32 *caps) { (void)arc; *caps = FS_ARCHIVE_CAPS_UNICODE; return FS_RESULT_SUCCESS; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_GetPathInfo Description: The FS_COMMAND_GETPATHINFO command. Arguments: arc: The calling archive baseid: The base directory ID (0 for the root) relpath: The path info: Location to save file information Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_GetPathInfo(FSArchive *arc, u32 baseid, const char *relpath, FSPathInfo *info) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); FATFSFileInfoW stat[1]; u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); (void)baseid; if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_GetFileInfoW(path, stat)) { info->attributes = stat->attributes; if ((stat->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0) { info->attributes |= FS_ATTRIBUTE_IS_DIRECTORY; } info->filesize = stat->length; FSi_DostimeToFstime(&info->atime, stat->dos_atime); FSi_DostimeToFstime(&info->mtime, stat->dos_mtime); FSi_DostimeToFstime(&info->ctime, stat->dos_ctime); info->id = FS_INVALID_FILE_ID; result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_SetPathInfo Description: The FS_COMMAND_SETPATHINFO command. Arguments: arc: The calling archive baseid: The base directory ID (0 for the root) relpath: The path info: Storage source of file information Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_SetPathInfo(FSArchive *arc, u32 baseid, const char *relpath, FSPathInfo *info) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); FATFSFileInfoW stat[1]; u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); (void)baseid; FSi_FstimeToDostime(&stat->dos_atime, &info->atime); FSi_FstimeToDostime(&stat->dos_mtime, &info->mtime); FSi_FstimeToDostime(&stat->dos_ctime, &info->ctime); stat->attributes = (info->attributes & (FATFS_ATTRIBUTE_DOS_MASK | FATFS_PROPERTY_CTRL_MASK)); info->attributes &= ~FATFS_PROPERTY_CTRL_MASK; if (((stat->attributes & FATFS_PROPERTY_CTRL_MASK) != 0) && !FSi_CheckFstime(&info->mtime)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_SetFileInfoW(path, stat)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_CreateFile Description: The FATFS_COMMAND_CREATE_FILE command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_CreateFile(FSArchive *arc, u32 baseid, const char *relpath, u32 permit) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); char permitstring[16]; char *s = permitstring; BOOL tranc = TRUE; u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if ((permit & FS_PERMIT_R) != 0) { *s++ = 'r'; } if ((permit & FS_PERMIT_W) != 0) { *s++ = 'w'; } *s++ = '\0'; if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_CreateFileW(path, tranc, permitstring)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_DeleteFile Description: The FATFS_COMMAND_DELETE_FILE command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_DeleteFile(FSArchive *arc, u32 baseid, const char *relpath) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_DeleteFileW(path)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_RenameFile Description: The FATFS_COMMAND_RENAME_FILE command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_RenameFile(FSArchive *arc, u32 baseid_src, const char *relpath_src, u32 baseid_dst, const char *relpath_dst) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); u16 *src = FSi_AllocUnicodeFullPath(context, relpath_src); u16 *dst = FSi_AllocUnicodeFullPath(context, relpath_dst); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FSi_UsingInvalidCharacterW(src)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FSi_UsingInvalidCharacterW(dst)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_RenameFileW(src, dst)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(src); FSi_ReleaseUnicodeBuffer(dst); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid_src; (void)baseid_dst; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_CreateDirectory Description: The FATFS_COMMAND_CREATE_DIRECTORY command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_CreateDirectory(FSArchive *arc, u32 baseid, const char *relpath, u32 permit) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); char permitstring[16]; char *s = permitstring; u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if ((permit & FS_PERMIT_R) != 0) { *s++ = 'r'; } if ((permit & FS_PERMIT_W) != 0) { *s++ = 'w'; } *s++ = '\0'; if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_CreateDirectoryW(path, permitstring)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_DeleteDirectory Description: The FATFS_COMMAND_DELETE_DIRECTORY command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_DeleteDirectory(FSArchive *arc, u32 baseid, const char *relpath) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); u16 *path = FSi_AllocUnicodeFullPath(context, relpath); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_DeleteDirectoryW(path)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_RenameDirectory Description: The FATFS_COMMAND_RENAME_DIRECTORY command. Arguments: Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_RenameDirectory(FSArchive *arc, u32 baseid_src, const char *relpath_src, u32 baseid_dst, const char *relpath_dst) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); u16 *src = FSi_AllocUnicodeFullPath(context, relpath_src); u16 *dst = FSi_AllocUnicodeFullPath(context, relpath_dst); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FSi_UsingInvalidCharacterW(src)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FSi_UsingInvalidCharacterW(dst)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_RenameDirectoryW(src, dst)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(src); FSi_ReleaseUnicodeBuffer(dst); FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid_src; (void)baseid_dst; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_GetArchiveResource Description: The FATFS_COMMAND_GETARCHIVERESOURCE command. Arguments: arc: The calling archive resource: Storage destination of resource information Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_GetArchiveResource(FSArchive *arc, FSArchiveResource *resource) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); u16 *path = FSi_AllocUnicodeFullPath(context, "/"); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FSi_UsingInvalidCharacterW(path)) { result = FS_RESULT_INVALID_PARAMETER; } else if (FATFS_GetDriveResourceW(path, context->resource)) { resource->totalSize = context->resource->totalSize; resource->availableSize = context->resource->availableSize; resource->maxFileHandles = context->resource->maxFileHandles; resource->currentFileHandles = context->resource->currentFileHandles; resource->maxDirectoryHandles = context->resource->maxDirectoryHandles; resource->currentDirectoryHandles = context->resource->currentDirectoryHandles; // For FAT archives resource->bytesPerSector = context->resource->bytesPerSector; resource->sectorsPerCluster = context->resource->sectorsPerCluster; resource->totalClusters = context->resource->totalClusters; resource->availableClusters = context->resource->availableClusters; result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(path); FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_OpenFile Description: The FS_COMMAND_OPENFILE command. Arguments: arc: The calling archive file: The target file baseid: The base directory (0 for the root) path : File path mode: Access mode Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_OpenFile(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = FATFS_INVALID_HANDLE; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); char modestring[16]; char *s = modestring; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if ((mode & FS_FILEMODE_R) != 0) { *s++ = 'r'; if ((mode & FS_FILEMODE_W) != 0) { *s++ = '+'; } } else if ((mode & FS_FILEMODE_W) != 0) { *s++ = 'w'; } if ((mode & FS_FILEMODE_L) != 0) { *s++ = 'l'; } *s++ = '\0'; { const u16 *unipath = NULL; u16 *fpath = NULL; // Store Unicode as it is if the Unicode version structure was passsed. if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0) { unipath = (const u16 *)path; } // If not, store as Shift_JIS version // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.) // else { fpath = FSi_AllocUnicodeFullPath(context, path); unipath = fpath; } if (FSi_UsingInvalidCharacterW(unipath)) { result = FS_RESULT_INVALID_PARAMETER; } else { handle = FATFS_OpenFileW(unipath, modestring); if (handle != FATFS_INVALID_HANDLE) { FS_SetFileHandle(file, arc, (void*)handle); result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } } FSi_ReleaseUnicodeBuffer(fpath); } FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_CloseFile Description: The FS_COMMAND_CLOSEFILE command. Arguments: arc: The calling archive file: The target file Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_CloseFile(FSArchive *arc, FSFile *file) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FATFS_CloseFile(handle)) { FS_DetachHandle(file); result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_ReadFile Description: The FS_COMMAND_READFILE command. Arguments: arc: The calling archive file: The target file buffer: The memory to transfer to length: Transfer size Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_ReadFile(FSArchive *arc, FSFile *file, void *buffer, u32 *length) { FSResult result = FS_RESULT_SUCCESS; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); u32 rest = *length; BOOL async = ((file->stat & FS_FILE_STATUS_BLOCKING) == 0); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); while (rest > 0) { // Switch with a temporary buffer for any of the following // (1) Memory was specified that cannot directly be accessed from ARM7 // (2) Specified memory that cannot be 32-bit aligned void *dst = buffer; u32 len = rest; int read; if (!FSi_IsValidAddressForARM7(buffer, rest) || (((u32)buffer & 31) != 0)) { dst = context->tmpbuf; len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH); } // Even if not so, just in case, write back if it is the content of the main memory // (Protect other variables that are together in a cache aligned, 32-bit range) else if (((u32)dst >= HW_TWL_MAIN_MEM) && ((u32)dst + len <= HW_TWL_MAIN_MEM_END)) { DC_FlushRange(dst, len); } // If asynchronous processing was requested and is actually possible configure a request buffer here. // async &= ((dst == buffer) && (len == rest)); if (async) { FATFSi_SetRequestBuffer(&FSiFATFSAsyncRequest[context - FSiFATFSDrive], FSi_FATFSAsyncDone, context); } // Actually call read = FATFS_ReadFile(handle, dst, (int)len); if (async) { rest -= len; result = FS_RESULT_PROC_ASYNC; break; } // If switched with the temporary buffer, copy here if( (dst != buffer)&&(read > 0)) { DC_InvalidateRange(dst, (u32)read); MI_CpuCopy8(dst, buffer, (u32)read); } buffer = (u8 *)buffer + read; rest -= read; if( read != len) { result = FSi_ConvertError(tls->result); break; } } *length -= rest; FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_WriteFile Description: The FS_COMMAND_WRITEFILE command. Arguments: arc: The calling archive file: The target file buffer: The memory to transfer from length: Transfer size Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_WriteFile(FSArchive *arc, FSFile *file, const void *buffer, u32 *length) { FSResult result = FS_RESULT_SUCCESS; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); u32 rest = *length; BOOL async = ((file->stat & FS_FILE_STATUS_BLOCKING) == 0); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); while (rest > 0) { // Switch with a temporary buffer for any of the following // (1) Memory was specified that cannot directly be accessed from ARM7 // (2) Specified memory that cannot be 32-bit aligned const void *dst = buffer; u32 len = rest; int written; if (!FSi_IsValidAddressForARM7(buffer, rest) || (((u32)buffer & 31) != 0)) { dst = context->tmpbuf; len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH); MI_CpuCopy8(buffer, context->tmpbuf, len); DC_StoreRange(context->tmpbuf, len); } // Even if not so, just in case, write back if it is the content of the main memory // (Protect other variables that are together in a cache aligned, 32-bit range) else if (((u32)dst >= HW_TWL_MAIN_MEM) && ((u32)dst + len <= HW_TWL_MAIN_MEM_END)) { DC_StoreRange(dst, len); } // If asynchronous processing was requested and is actually possible configure a request buffer here. // async &= ((dst == buffer) && (len == rest)); if (async) { FATFSi_SetRequestBuffer(&FSiFATFSAsyncRequest[context - FSiFATFSDrive], FSi_FATFSAsyncDone, context); } // Actually call written = FATFS_WriteFile(handle, dst, (int)len); if (async) { rest -= len; result = FS_RESULT_PROC_ASYNC; break; } buffer = (u8 *)buffer + written; rest -= written; if( written != len) { result = FSi_ConvertError(tls->result); break; } } *length -= rest; FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_SetSeekCache Description: The FS_COMMAND_SETSEEKCACHE command. Arguments: arc: The calling archive file: The target file buf: Cache buffer buf_size: Cache buffer size Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_SetSeekCache(FSArchive *arc, FSFile *file, void* buf, u32 buf_size) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if ((buf != NULL) && (((u32)buf < HW_TWL_MAIN_MEM) || (((u32)buf + buf_size) > HW_TWL_MAIN_MEM_END))) { // A buffer that is not in main memory causes a parameter error result = FS_RESULT_INVALID_PARAMETER; } else if ((buf != NULL) && (buf_size < 32)) { // Fail if memory size is inssuficient to share with the ARM7. result = FS_RESULT_FAILURE; } else if ((((u32)buf & 31) != 0) && ((buf_size - (32 - ((u32)buf & 31))) < 32)) { // Also fail if it is too small after being 32-byte aligned result = FS_RESULT_FAILURE; } else { void *cache; u32 cache_size; if (buf != NULL) { // Flush this because it may have existed in the cache before being used by this function DC_FlushRange(buf, buf_size); } // Extract a region that is 32-byte aligned to allow sharing with the ARM7 if (((u32)buf & 31) != 0) { cache = (void *)((u32)buf + (32 - ((u32)buf & 31))); // 32-byte boundary cache_size = buf_size - (32 - ((u32)buf & 31)); } else { cache = buf; cache_size = buf_size; } cache_size = cache_size & ~31; // Reduce to 32 bytes if( FATFS_SetSeekCache(handle, cache, cache_size) != FALSE) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } } (void)arc; FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_SeekFile Description: The FS_COMMAND_SEEKFILE command. Arguments: arc: The calling archive file: The target file offset: The displacement and moved-to position from: The starting point to seek from Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_SeekFile(FSArchive *arc, FSFile *file, int *offset, FSSeekFileMode from) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); FATFSSeekMode mode = FATFS_SEEK_CUR; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (from == FS_SEEK_SET) { mode = FATFS_SEEK_SET; } else if (from == FS_SEEK_CUR) { mode = FATFS_SEEK_CUR; } else if (from == FS_SEEK_END) { mode = FATFS_SEEK_END; } *offset = FATFS_SeekFile(handle, *offset, mode); if (*offset >= 0) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_GetFileLength Description: The FS_COMMAND_GETFILELENGTH command. Arguments: arc: The calling archive file: The target file length: Location to save the obtained size Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_GetFileLength(FSArchive *arc, FSFile *file, u32 *length) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); int n = FATFS_GetFileLength(handle); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (n >= 0) { *length = (u32)n; result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_SetFileLength Description: The FS_COMMAND_SETFILELENGTH command. Arguments: arc: The calling archive file: The target file length: File size to be set Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_SetFileLength(FSArchive *arc, FSFile *file, u32 length) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FATFS_SetFileLength(handle, (int)length)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_GetFilePosition Description: The FS_COMMAND_GETFILEPOSITION command. Arguments: arc: The calling archive file: The target file position: Location to store the obtained position Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_GetFilePosition(FSArchive *arc, FSFile *file, u32 *position) { *position = 0; return FSi_FATFS_SeekFile(arc, file, (int*)position, FS_SEEK_CUR); } /*---------------------------------------------------------------------------* Name: FSi_FATFS_FlushFile Description: The FS_COMMAND_FLUSHFILE command. Arguments: arc: The calling archive file: The target file Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_FlushFile(FSArchive *arc, FSFile *file) { FSResult result = FS_RESULT_ERROR; FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FATFS_FlushFile(handle)) { result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_OpenDirectory Description: The FS_COMMAND_OPENDIRECTORY command. Arguments: arc: The calling archive file: The target file baseid: The base directory ID (0 for the root) path: The path mode: Access mode Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_OpenDirectory(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode) { FSResult result = FS_RESULT_ERROR; FSFATFSArchiveContext *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc); FATFSDirectoryHandle handle = FATFS_INVALID_HANDLE; char modestring[16]; char *s = modestring; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if ((mode & FS_FILEMODE_R) != 0) { *s++ = 'r'; } if ((mode & FS_FILEMODE_W) != 0) { *s++ = 'w'; } if ((mode & FS_DIRMODE_SHORTNAME_ONLY) != 0) { *s++ = 's'; } *s++ = '\0'; { u16 *unipath = NULL; u16 *fpath = NULL; // Store Unicode as it is if the Unicode version structure was passsed. if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0) { unipath = (u16 *)path; } // If not, store as Shift_JIS version // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.) // else { fpath = FSi_AllocUnicodeFullPath(context, path); unipath = fpath; } // Disable last special wildcard specifications // Because the path always normalizes and passes the FS library, the possibility of changes to the buffer content is guaranteed. // if (*unipath) { int pos; for (pos = 0; unipath[pos]; ++pos) { } for (--pos; (pos > 0) && (unipath[pos] == L'*'); --pos) { } if (unipath[pos] != L'/') { unipath[++pos] = L'/'; } unipath[++pos] = L'*'; unipath[++pos] = L'\0'; } handle = FATFS_OpenDirectoryW(unipath, modestring); if (handle != FATFS_INVALID_HANDLE) { FS_SetDirectoryHandle(file, arc, (void*)handle); result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FSi_ReleaseUnicodeBuffer(fpath); } FATFS_RegisterResultBuffer(tls, FALSE); (void)baseid; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_CloseDirectory Description: The FS_COMMAND_CLOSEDIRECTORY command. Arguments: arc: The calling archive file: The target file Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_CloseDirectory(FSArchive *arc, FSFile *file) { FSResult result = FS_RESULT_ERROR; FATFSDirectoryHandle handle = (FATFSDirectoryHandle)FS_GetFileUserData(file); FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FATFS_CloseDirectory(handle)) { FS_DetachHandle(file); result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } /*---------------------------------------------------------------------------* Name: FSi_FATFS_ReadDirectory Description: The FS_COMMAND_READDIR command. Arguments: arc: The calling archive file: The target file info: Location to store the information Returns: The processing result for the command. *---------------------------------------------------------------------------*/ static FSResult FSi_FATFS_ReadDirectory(FSArchive *arc, FSFile *file, FSDirectoryEntryInfo *info) { FSResult result = FS_RESULT_ERROR; FATFSDirectoryHandle handle = (FATFSDirectoryHandle)FS_GetFileUserData(file); FATFSFileInfoW tmp[1]; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (FATFS_ReadDirectoryW(handle, tmp)) { // Store Unicode as it is if the Unicode version structure was passsed. if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0) { FSDirectoryEntryInfoW *infow = (FSDirectoryEntryInfoW *)info; infow->shortname_length = (u32)STD_GetStringLength(tmp->shortname); (void)STD_CopyLString(infow->shortname, tmp->shortname, sizeof(infow->shortname)); { int n; for (n = 0; (n < FS_ENTRY_LONGNAME_MAX - 1) && tmp->longname[n]; ++n) { infow->longname[n] = tmp->longname[n]; } infow->longname[n] = L'\0'; infow->longname_length = (u32)n; } infow->attributes = tmp->attributes; if ((tmp->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0) { infow->attributes |= FS_ATTRIBUTE_IS_DIRECTORY; } infow->filesize = tmp->length; FSi_DostimeToFstime(&infow->atime, tmp->dos_atime); FSi_DostimeToFstime(&infow->mtime, tmp->dos_mtime); FSi_DostimeToFstime(&infow->ctime, tmp->dos_ctime); } // If not, store as Shift_JIS version // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.) // else { FSDirectoryEntryInfo *infoa = (FSDirectoryEntryInfo *)info; infoa->shortname_length = (u32)STD_GetStringLength(tmp->shortname); (void)STD_CopyLString(infoa->shortname, tmp->shortname, sizeof(infoa->shortname)); { int dstlen = sizeof(infoa->longname) - 1; int srclen = 0; (void)FSi_ConvertStringUnicodeToSjis(infoa->longname, &dstlen, tmp->longname, NULL, NULL); infoa->longname[dstlen] = L'\0'; infoa->longname_length = (u32)dstlen; } infoa->attributes = tmp->attributes; if ((tmp->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0) { infoa->attributes |= FS_ATTRIBUTE_IS_DIRECTORY; } infoa->filesize = tmp->length; FSi_DostimeToFstime(&infoa->atime, tmp->dos_atime); FSi_DostimeToFstime(&infoa->mtime, tmp->dos_mtime); FSi_DostimeToFstime(&infoa->ctime, tmp->dos_ctime); } result = FS_RESULT_SUCCESS; } else { result = FSi_ConvertError(tls->result); } FATFS_RegisterResultBuffer(tls, FALSE); (void)arc; return result; } static PMSleepCallbackInfo FSiPreSleepInfo; static PMExitCallbackInfo FSiPostExitInfo; static void FSi_SleepProcedure(void *arg) { (void)arg; (void)FATFS_FlushAll(); } static void FSi_ShutdownProcedure(void *arg) { (void)arg; (void)FATFS_UnmountAll(); } /*---------------------------------------------------------------------------* Name: FSi_MountFATFSArchive Description: Mounts the FATFS archive. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void FSi_MountFATFSArchive(FSFATFSArchiveContext *context, const char *arcname, u8 *tmpbuf) { static const FSArchiveInterface FSiArchiveFATFSInterface = { // Commands that are compatible with the old specifications FSi_FATFS_ReadFile, FSi_FATFS_WriteFile, NULL, // SeekDirectory FSi_FATFS_ReadDirectory, NULL, // FindPath NULL, // GetPath NULL, // OpenFileFast NULL, // OpenFileDirect FSi_FATFS_CloseFile, NULL, // Activate NULL, // Idle NULL, // Suspend NULL, // Resume // New commands that are compatible with the old specifications FSi_FATFS_OpenFile, FSi_FATFS_SeekFile, FSi_FATFS_GetFileLength, FSi_FATFS_GetFilePosition, // Command extended by the new specifications (UNSUPPORTED if NULL) NULL, // Mount NULL, // Unmount FSi_FATFS_GetArchiveCaps, FSi_FATFS_CreateFile, FSi_FATFS_DeleteFile, FSi_FATFS_RenameFile, FSi_FATFS_GetPathInfo, FSi_FATFS_SetPathInfo, FSi_FATFS_CreateDirectory, FSi_FATFS_DeleteDirectory, FSi_FATFS_RenameDirectory, FSi_FATFS_GetArchiveResource, NULL, // 29UL FSi_FATFS_FlushFile, FSi_FATFS_SetFileLength, FSi_FATFS_OpenDirectory, FSi_FATFS_CloseDirectory, FSi_FATFS_SetSeekCache, }; u32 arcnamelen = (u32)STD_GetStringLength(arcname); context->tmpbuf = tmpbuf; FS_InitArchive(context->arc); if (FS_RegisterArchiveName(context->arc, arcname, arcnamelen)) { (void)FS_MountArchive(context->arc, context, &FSiArchiveFATFSInterface, 0); } } /*---------------------------------------------------------------------------* Name: FSi_MountDefaultArchives Description: Mounts the default archive by referencing a startup argument given to IPL. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void FSi_MountDefaultArchives(void) { // Wait until FATFS mounts various physical media FATFS_Init(); FSi_SetupFATBuffers(); // Set the callback to set flash before sleep and before shutdown FSiPreSleepInfo.callback = FSi_SleepProcedure; FSiPostExitInfo.callback = FSi_ShutdownProcedure; PMi_InsertPreSleepCallbackEx(&FSiPreSleepInfo, PM_CALLBACK_PRIORITY_FS); PMi_InsertPostExitCallbackEx(&FSiPostExitInfo, PM_CALLBACK_PRIORITY_FS); // Mount to FS only the physical drive that actually has access rights if (FSiFATFSDrive && FSiTemporaryBuffer) { int index = 0; static const int max = FS_MOUNTDRIVE_MAX; const char *arcname = FATFSi_GetArcnameList(); while ((index < max) && *arcname) { FSi_MountFATFSArchive(&FSiFATFSDrive[index], arcname, &FSiTemporaryBuffer[FS_TMPBUF_LENGTH * index]); arcname += STD_GetStringLength(arcname) + 1; ++index; } } } /*---------------------------------------------------------------------------* Name: FSi_MountSpecialArchive Description: Directly mounts a special archive. Arguments: param: Parameter that specifies the mounting target arcname: Archive name to mount "otherPub" or "otherPrv" can be specified; when NULL is specified, unmount the previous archive pWork: Work region that is used for mounting It is necessary to retain while mounted Returns: FS_RESULT_SUCCESS if the processing was successful. *---------------------------------------------------------------------------*/ FSResult FSi_MountSpecialArchive(u64 param, const char *arcname, FSFATFSArchiveWork* pWork) { FSResult result = FS_RESULT_ERROR; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (!FATFS_MountSpecial(param, arcname, &pWork->slot)) { result = FSi_ConvertError(tls->result); } else { if (arcname && *arcname) { FSi_MountFATFSArchive(&pWork->context, arcname, pWork->tmpbuf); } else { (void)FS_UnmountArchive(pWork->context.arc); (void)FS_ReleaseArchiveName(pWork->context.arc); } result = FS_RESULT_SUCCESS; } FATFS_RegisterResultBuffer(tls, FALSE); return result; } /*---------------------------------------------------------------------------* Name: FSi_FormatSpecialArchive Description: Formats content of special archive that satisfies the following conditions. - Currently mounted - Hold your own ownership rights (dataPub, dataPrv, share*) Arguments: path: Path name that includes the archive name Returns: FS_RESULT_SUCCESS if the processing was successful. *---------------------------------------------------------------------------*/ FSResult FSi_FormatSpecialArchive(const char *path) { FSResult result = FS_RESULT_ERROR; FATFSResultBuffer tls[1]; FATFS_RegisterResultBuffer(tls, TRUE); if (!FATFS_FormatSpecial(path)) { result = FSi_ConvertError(tls->result); } else { result = FS_RESULT_SUCCESS; } FATFS_RegisterResultBuffer(tls, FALSE); return result; } #include #endif /* FS_IMPLEMENT */ #endif /* SDK_TWL */ /*---------------------------------------------------------------------------* Name: FS_ForceToEnableLatencyEmulation Description: Uses a driver to emulate the random wait times that occur when accessing a degraded NAND device. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void FS_ForceToEnableLatencyEmulation(void) { #if defined(SDK_TWL) if (OS_IsRunOnTwl()) { (void)FATFS_SetLatencyEmulation(TRUE); } #endif }