/*---------------------------------------------------------------------------* Copyright (C) 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. *---------------------------------------------------------------------------*/ ////=========================================================================== /// DEMO_Fs.c /// /// This is file system code for the DEMO library. /// ////=========================================================================== #include #include static u32 _DEMOFSInitRefCount = 0; static FSClient _DEMOFSClient; /*---------------------------------------------------------------------------* Name: stateChangeCallback Description: Handler of state change notification. Never invoked in this demo. *---------------------------------------------------------------------------*/ static void stateChangeCallback( FSClient* pClient, FSVolumeState state, void* pContext) { // Report volume state and last error FSError lastError = FSGetLastError(pClient); OSReport("Volume state of client 0x%08x changed to %d\n", pClient, state); OSReport("Last error: %d\n", lastError); } // ------------------------------------------------------- // "Safe" string concat function // Like strncat, but len = size of dst buffer static inline char *strlcat(char *dst, const char *src, size_t len) { int n=strlen(dst); if (n>len-1) n=len-1; return strncat(dst, src, len-1-n); } // ------------------------------------------------------- // Startup the FS subsystem if it isn't already up and running. // Note that demo libraries only initialize this once, but never release it. static s32 _DemoInitFS(void) { if (!_DEMOFSInitRefCount) { FSInit(); FSStatus result = FSAddClient(&_DEMOFSClient, FS_RET_ALL_ERROR); if (result != FS_STATUS_OK) { DEMOPrintf("DEMOFS Error: FSAddClient() returned: %d!\n", result); return DEMO_FS_RESULT_FATAL_ERROR; } FSStateChangeParams stateChangeParams = { .userCallback = stateChangeCallback, .userContext = NULL, .ioMsgQueue = NULL }; FSSetStateChangeNotification(&_DEMOFSClient, &stateChangeParams); // Do not call SAVEInit() every time. // Application should call SAVEInit(). // Do not call SAVEInitSaveDir() every time. // Application should call SAVEInitSaveDir() if the save directory does not exist. } _DEMOFSInitRefCount++; return DEMO_FS_RESULT_OK; } s32 DEMOFSOpenFile(const char* path, DEMOFSFileInfo* info) { return DEMOFSOpenFileMode(path, info, "r"); } s32 DEMOFSOpenFileMode(const char* path, DEMOFSFileInfo* info, const char* mode) { FSStatus result = FS_STATUS_OK; char openPath[256]; FSCmdBlock* pCmd; if (path==NULL) { DEMOPrintf("DEMOFS Error: NULL path!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } result = _DemoInitFS(); if (DEMO_FS_RESULT_OK != result) { DEMOPrintf("DEMOFS Error: _DemoInitFS failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } if (path[0]!='/') { strncpy(openPath, "/vol/content/", 256); } else { openPath[0]=0; } strlcat(openPath, path, 256); pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSOpenFile(&_DEMOFSClient, pCmd, openPath, mode, info, FS_RET_ALL_ERROR); DEMOFree(pCmd); if (FS_STATUS_OK != result) { DEMOPrintf("DEMOFS Error: FSOpenFile(%s) returned %d!\n", path, result); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFSGetLength( const DEMOFSFileInfo* fileInfo, u32* length ) { u32 sLength; FSStat stat; FSStatus result; FSCmdBlock* pCmd; pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSGetStatFile(&_DEMOFSClient, pCmd, *fileInfo, &stat, FS_RET_ALL_ERROR); DEMOFree(pCmd); if(result != FS_STATUS_OK) { DEMOPrintf("DEMOFS Error: FSStatFile returned %d\n", result); return DEMO_FS_RESULT_FATAL_ERROR; } sLength = stat.size; *length = sLength; return DEMO_FS_RESULT_OK; } s32 DEMOFSRead( DEMOFSFileInfo* fileInfo, void* addr, s32 length, s32 offset ) { FSStatus result; FSCmdBlock* pCmd; pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSReadFileWithPos(&_DEMOFSClient, pCmd, addr, (u32)length, 1, (u32)offset, *fileInfo, 0, FS_RET_ALL_ERROR); DEMOFree(pCmd); if( 0 > result ) { DEMOPrintf("DEMOFS Error: FSReadFile returned: %d\n", result); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFSWrite(DEMOFSFileInfo* fileInfo, const void* addr, s32 length) { FSStatus result; FSCmdBlock* pCmd; pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSWriteFile(&_DEMOFSClient, pCmd, (void *)addr, 1, (u32)length, *fileInfo, 0, FS_RET_ALL_ERROR); DEMOFree(pCmd); if( 0 > result ) { DEMOPrintf("DEMOFS Error: FSWriteFile returned: %d\n", result); return DEMO_FS_RESULT_FATAL_ERROR; } else if (result != length) { DEMOPrintf("DEMOFS Error: FSWriteFile actual write count %d != requested write count %d.\n", result, length); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFSCloseFile( DEMOFSFileInfo* fileInfo ) { FSStatus result; FSCmdBlock* pCmd; pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSCloseFile(&_DEMOFSClient, pCmd, *fileInfo, FS_RET_ALL_ERROR); DEMOFree(pCmd); if(FS_STATUS_OK != result ) { DEMOPrintf("DEMOFS Error: FSCloseFile returned %d\n", result); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } void * DEMOFSSimpleRead(const char * filename, u32 * len) { DEMOFSFileInfo file; u32 fileLen; u32 fileAllocLen; s32 fileRet; void *fileBuf = NULL; fileRet = DEMOFSOpenFile(filename, &file); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't open file"); fileRet = DEMOFSGetLength(&file, &fileLen); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't get file length"); fileAllocLen = DEMORoundUpForIO(fileLen); fileBuf = DEMOAllocEx(fileAllocLen, PPC_IO_BUFFER_ALIGN); DEMOAssert(fileBuf && "couldn't alloc memory"); fileRet = DEMOFSRead(&file, fileBuf, (s32)fileAllocLen, 0); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't read file"); fileRet = DEMOFSCloseFile(&file); if (fileRet != DEMO_FS_RESULT_OK) { DEMOAssert(!"couldn't close file"); } *len = fileLen; return fileBuf; } void * DEMOFSSimpleReadAlign(const char * filename, u32 * len, u32 alignSize) { DEMOFSFileInfo file; u32 fileLen; u32 fileAllocLen; s32 fileRet; void *fileBuf = NULL; fileRet = DEMOFSOpenFile(filename, &file); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't open file"); fileRet = DEMOFSGetLength(&file, &fileLen); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't get file length"); fileAllocLen = DEMORoundUpForIO(fileLen); fileBuf = DEMOAllocEx(fileAllocLen, alignSize); DEMOAssert(fileBuf && "couldn't alloc memory"); fileRet = DEMOFSRead(&file, fileBuf, (s32)fileAllocLen, 0); DEMOAssert(fileRet == DEMO_FS_RESULT_OK && "couldn't read file"); fileRet = DEMOFSCloseFile(&file); if (fileRet != DEMO_FS_RESULT_OK) { DEMOAssert(!"couldn't close file"); } *len = fileLen; return fileBuf; } s32 DEMOFSScanDir(const char *pSearchPath, const char *pPrefixPath, u32 *pFileCount, u32 MaxFiles, char** ppFileNames ) { FSStatus result; FSDirHandle dh; FSDirEntry dirent; u32 fileCount = 0; u32 dirCount = 0; char dirPath[256] = {0}; FSCmdBlock* pCmd; if (pSearchPath==NULL) { DEMOPrintf("DEMOFS Error: NULL path!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } result = _DemoInitFS(); if (DEMO_FS_RESULT_OK != result) { DEMOPrintf("DEMOFS Error: _DemoInitFS failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } // is pathname too long? if(strlen(pSearchPath) >= sizeof(dirPath) - (pSearchPath[0]=='/' ? 0 : sizeof("/vol/content/"))) { DEMOPrintf("DEMO Error: pathname is too long: %s!\n", pSearchPath); return DEMO_FS_RESULT_FATAL_ERROR; } if (pSearchPath[0]!='/') { strncpy(dirPath, "/vol/content/", 256); } else { dirPath[0]=0; } strlcat(dirPath, pSearchPath, 256); pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); // open directory (include the volume) result = FSOpenDir(&_DEMOFSClient, pCmd, dirPath, &dh, FS_RET_ALL_ERROR); if(result != FS_STATUS_OK) { DEMOFree(pCmd); DEMOPrintf("DEMO Error: FSOpenDir(%s) returned: %d!\n", dirPath, result); return DEMO_FS_RESULT_NOT_FOUND; } // how many files in directory? What are their names? // (may be able to get this from parent directory via the // dirent.stat.size, but that means we need to open the parent up) while( FS_STATUS_END != (result = FSReadDir(&_DEMOFSClient, pCmd, dh, &dirent, FS_RET_ALL_ERROR)) ) { if (FS_STATUS_OK != result) { DEMOFree(pCmd); DEMOPrintf("DEMO Error: FSReadDir(%s) returned: %d!\n", dirPath, result); return DEMO_FS_RESULT_FATAL_ERROR; } if (dirent.stat.flag & FS_STAT_FLAG_IS_DIRECTORY) { dirCount++; } else /* this is file */ { if(fileCount < MaxFiles) { // get file name (not including the volume, DemoSimpleRead puts it back on) const u32 MaxNameLen = 256; u32 nameLen = strlen(dirPath) + 1 + strlen(dirent.name); // be safe, if file name too long, don't return it. (Assert)! if(nameLen < MaxNameLen) { char *pBuff = DEMOAlloc(nameLen+1); // allocate new space for this string DEMOAssert(pBuff && "couldn't alloc memory"); strncpy(pBuff, pPrefixPath, nameLen+1); if(pBuff[0] && pBuff[strlen(pBuff)-1] != '/') strlcat(pBuff, "/", nameLen+1); strlcat(pBuff, dirent.name, nameLen+1); ppFileNames[fileCount] = pBuff; fileCount++; } else { DEMOFree(pCmd); DEMOPrintf("DEMO Error: filename found in dir that is too long\n"); return DEMO_FS_RESULT_FATAL_ERROR; } } } } *pFileCount = fileCount; // now, reached to the end of directory. close directory result = FSCloseDir(&_DEMOFSClient, pCmd, dh, FS_RET_ALL_ERROR); DEMOFree(pCmd); if(result != FS_STATUS_OK) { DEMOPrintf("DEMO Error: Failed to close dir %s!\n", dirPath); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFSSimpleScanDir(const char *pPath, u32 *pFileCount, u32 MaxFiles, char** ppFileNames ) { return DEMOFSScanDir(pPath, pPath, pFileCount, MaxFiles, ppFileNames); } s32 DEMOFSRename(const char *oldpath, const char *newpath) { FSStatus result = FS_STATUS_OK; char prefixedOldPath[256]; char prefixedNewPath[256]; FSCmdBlock* pCmd; if (oldpath==NULL || newpath==NULL) { DEMOPrintf("DEMOFS Error: NULL path!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } result = _DemoInitFS(); if (DEMO_FS_RESULT_OK != result) { DEMOPrintf("DEMOFS Error: _DemoInitFS failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } if (oldpath[0]!='/') { strncpy(prefixedOldPath, "/vol/content/", 256); } else { prefixedOldPath[0]=0; } strlcat(prefixedOldPath, oldpath, 256); if (newpath[0]!='/') { strncpy(prefixedNewPath, "/vol/content/", 256); } else { prefixedNewPath[0]=0; } strlcat(prefixedNewPath, newpath, 256); pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSRename(&_DEMOFSClient, pCmd, prefixedOldPath, prefixedNewPath, FS_RET_ALL_ERROR); DEMOFree(pCmd); if (FS_STATUS_OK != result) { DEMOPrintf("DEMOFS Error: FSRename(%s,%s) returned %d!\n", oldpath, newpath, result); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFSRemove(const char *path, BOOL ignoreError) { FSStatus result = FS_STATUS_OK; char prefixedPath[256]; FSCmdBlock* pCmd; if (path==NULL) { DEMOPrintf("DEMOFS Error: NULL path!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } result = _DemoInitFS(); if (DEMO_FS_RESULT_OK != result) { DEMOPrintf("DEMOFS Error: _DemoInitFS failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } if (path[0]!='/') { strncpy(prefixedPath, "/vol/content/", 256); } else { prefixedPath[0]=0; } strlcat(prefixedPath, path, 256); pCmd = DEMOAlloc(sizeof(FSCmdBlock)); if( pCmd == NULL ) { DEMOPrintf("DEMOFS Error: DEMOAlloc failed!\n"); return DEMO_FS_RESULT_FATAL_ERROR; } FSInitCmdBlock(pCmd); result = FSRemove(&_DEMOFSClient, pCmd, prefixedPath, FS_RET_ALL_ERROR); DEMOFree(pCmd); if (FS_STATUS_OK != result && !ignoreError) { DEMOPrintf("DEMOFS Error: FSRemove(%s) returned %d!\n", path, result); return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } BOOL DEMOFSFileExists(const char *path) { DEMOFSFileInfo file; if (DEMOFSOpenFile(path, &file) != DEMO_FS_RESULT_OK) return FALSE; s32 result = DEMOFSCloseFile(&file); DEMOAssert(result == DEMO_FS_RESULT_OK && "couldn't close file!"); return TRUE; } // --------------------------------------------------------