CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/FileSystems/VirtualDiscFileSystem.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "ppsspp_config.h"18#ifdef __MINGW32__19#include <unistd.h>20#ifndef _POSIX_THREAD_SAFE_FUNCTIONS21#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L22#endif23#endif24#include <ctime>2526#include "Common/File/FileUtil.h"27#include "Common/File/DirListing.h"28#include "Common/StringUtils.h"29#include "Common/Serialize/Serializer.h"30#include "Common/Serialize/SerializeFuncs.h"31#include "Common/SysError.h"32#include "Core/FileSystems/VirtualDiscFileSystem.h"33#include "Core/FileSystems/ISOFileSystem.h"34#include "Core/HLE/sceKernel.h"35#include "Core/Reporting.h"36#include "Common/Data/Encoding/Utf8.h"3738#ifdef _WIN3239#include "Common/CommonWindows.h"40#include <sys/stat.h>41#if PPSSPP_PLATFORM(UWP)42#include <fileapifromapp.h>43#endif44#else45#include <dirent.h>46#include <unistd.h>47#include <sys/stat.h>48#include <ctype.h>49#if !PPSSPP_PLATFORM(SWITCH)50#include <dlfcn.h>51#endif52#endif5354const std::string INDEX_FILENAME = ".ppsspp-index.lst";5556VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, const Path &_basePath)57: basePath(_basePath), currentBlockIndex(0) {58hAlloc = _hAlloc;59LoadFileListIndex();60}6162VirtualDiscFileSystem::~VirtualDiscFileSystem() {63for (auto iter = entries.begin(), end = entries.end(); iter != end; ++iter) {64if (iter->second.type != VFILETYPE_ISO) {65iter->second.Close();66}67}68for (auto iter = handlers.begin(), end = handlers.end(); iter != end; ++iter) {69delete iter->second;70}71}7273void VirtualDiscFileSystem::LoadFileListIndex() {74const Path filename = basePath / INDEX_FILENAME;75if (!File::Exists(filename)) {76return;77}7879FILE *f = File::OpenCFile(filename, "r");80if (!f) {81return;82}8384static const int MAX_LINE_SIZE = 2048;85char linebuf[MAX_LINE_SIZE]{};86while (fgets(linebuf, MAX_LINE_SIZE, f)) {87std::string line = linebuf;88// Strip newline from fgets.89if (!line.empty() && line.back() == '\n')90line.resize(line.size() - 1);9192// Ignore any UTF-8 BOM.93if (line.substr(0, 3) == "\xEF\xBB\xBF") {94line = line.substr(3);95}9697if (line.empty() || line[0] == ';') {98continue;99}100101FileListEntry entry = {""};102103// Syntax: HEXPOS filename or HEXPOS filename:handler104size_t filename_pos = line.find(' ');105if (filename_pos == line.npos) {106ERROR_LOG(Log::FileSystem, "Unexpected line in %s: %s", INDEX_FILENAME.c_str(), line.c_str());107continue;108}109110filename_pos++;111// Strip any slash prefix.112while (filename_pos < line.length() && line[filename_pos] == '/') {113filename_pos++;114}115116// Check if there's a handler specified.117size_t handler_pos = line.find(':', filename_pos);118if (handler_pos != line.npos) {119entry.fileName = line.substr(filename_pos, handler_pos - filename_pos);120121std::string handler = line.substr(handler_pos + 1);122size_t trunc = handler.find_last_not_of("\r\n");123if (trunc != handler.npos && trunc != handler.size())124handler.resize(trunc + 1);125126if (handlers.find(handler) == handlers.end())127handlers[handler] = new Handler(handler.c_str(), this);128if (handlers[handler]->IsValid())129entry.handler = handlers[handler];130} else {131entry.fileName = line.substr(filename_pos);132}133size_t trunc = entry.fileName.find_last_not_of("\r\n");134if (trunc != entry.fileName.npos && trunc != entry.fileName.size())135entry.fileName.resize(trunc + 1);136137entry.firstBlock = (u32)strtol(line.c_str(), NULL, 16);138if (entry.handler != NULL && entry.handler->IsValid()) {139HandlerFileHandle temp = entry.handler;140if (temp.Open(basePath.ToString(), entry.fileName, FILEACCESS_READ)) {141entry.totalSize = (u32)temp.Seek(0, FILEMOVE_END);142temp.Close();143} else {144ERROR_LOG(Log::FileSystem, "Unable to open virtual file: %s", entry.fileName.c_str());145}146} else {147entry.totalSize = File::GetFileSize(GetLocalPath(entry.fileName));148}149150// Try to keep currentBlockIndex sane, in case there are other files.151u32 nextBlock = entry.firstBlock + (entry.totalSize + 2047) / 2048;152if (nextBlock > currentBlockIndex) {153currentBlockIndex = nextBlock;154}155156fileList.push_back(entry);157}158159fclose(f);160}161162void VirtualDiscFileSystem::DoState(PointerWrap &p)163{164auto s = p.Section("VirtualDiscFileSystem", 1, 2);165if (!s)166return;167168int fileListSize = (int)fileList.size();169int entryCount = (int)entries.size();170171Do(p, fileListSize);172Do(p, entryCount);173Do(p, currentBlockIndex);174175FileListEntry dummy = {""};176fileList.resize(fileListSize, dummy);177178for (int i = 0; i < fileListSize; i++)179{180Do(p, fileList[i].fileName);181Do(p, fileList[i].firstBlock);182Do(p, fileList[i].totalSize);183}184185if (p.mode == p.MODE_READ)186{187entries.clear();188189for (int i = 0; i < entryCount; i++)190{191u32 fd = 0;192OpenFileEntry of(Flags());193194Do(p, fd);195Do(p, of.fileIndex);196Do(p, of.type);197Do(p, of.curOffset);198Do(p, of.startOffset);199Do(p, of.size);200201// open file202if (of.type != VFILETYPE_ISO) {203if (fileList[of.fileIndex].handler != NULL) {204of.handler = fileList[of.fileIndex].handler;205}206207bool success = of.Open(basePath, fileList[of.fileIndex].fileName, FILEACCESS_READ);208if (!success) {209ERROR_LOG(Log::FileSystem, "Failed to create file handle for %s.", fileList[of.fileIndex].fileName.c_str());210} else {211if (of.type == VFILETYPE_LBN) {212of.Seek(of.curOffset + of.startOffset, FILEMOVE_BEGIN);213} else {214of.Seek(of.curOffset, FILEMOVE_BEGIN);215}216}217}218219// TODO: I think we only need to write to the map on load?220entries[fd] = of;221}222} else {223for (EntryMap::iterator it = entries.begin(), end = entries.end(); it != end; ++it)224{225OpenFileEntry &of = it->second;226227Do(p, it->first);228Do(p, of.fileIndex);229Do(p, of.type);230Do(p, of.curOffset);231Do(p, of.startOffset);232Do(p, of.size);233}234}235236if (s >= 2) {237Do(p, lastReadBlock_);238} else {239lastReadBlock_ = 0;240}241242// We don't savestate handlers (loaded on fs load), but if they change, it may not load properly.243}244245Path VirtualDiscFileSystem::GetLocalPath(std::string localpath) {246if (localpath.empty())247return basePath;248249if (localpath[0] == '/')250localpath.erase(0,1);251//Convert slashes252#ifdef _WIN32253for (size_t i = 0; i < localpath.size(); i++) {254if (localpath[i] == '/')255localpath[i] = '\\';256}257#endif258return basePath / localpath;259}260261int VirtualDiscFileSystem::getFileListIndex(std::string &fileName)262{263std::string normalized;264if (fileName.length() >= 1 && fileName[0] == '/') {265normalized = fileName.substr(1);266} else {267normalized = fileName;268}269270for (size_t i = 0; i < fileList.size(); i++)271{272if (fileList[i].fileName == normalized)273return (int)i;274}275276// unknown file - add it277Path fullName = GetLocalPath(fileName);278if (! File::Exists(fullName)) {279#if HOST_IS_CASE_SENSITIVE280if (! FixPathCase(basePath, fileName, FPC_FILE_MUST_EXIST))281return -1;282fullName = GetLocalPath(fileName);283284if (! File::Exists(fullName))285return -1;286#else287return -1;288#endif289}290291if (File::IsDirectory(fullName))292return -1;293294FileListEntry entry = {""};295entry.fileName = normalized;296entry.totalSize = File::GetFileSize(fullName);297entry.firstBlock = currentBlockIndex;298currentBlockIndex += (entry.totalSize+2047)/2048;299300fileList.push_back(entry);301302return (int)fileList.size()-1;303}304305int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize, bool blockMode)306{307for (size_t i = 0; i < fileList.size(); i++)308{309if (fileList[i].firstBlock <= accessBlock)310{311u32 sectorOffset = (accessBlock-fileList[i].firstBlock)*2048;312u32 totalFileSize = blockMode ? (fileList[i].totalSize+2047) & ~2047 : fileList[i].totalSize;313314u32 endOffset = sectorOffset+accessSize;315if (endOffset <= totalFileSize)316{317return (int)i;318}319}320}321322return -1;323}324325int VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)326{327OpenFileEntry entry(Flags());328entry.curOffset = 0;329entry.size = 0;330entry.startOffset = 0;331332if (filename.empty())333{334entry.type = VFILETYPE_ISO;335entry.fileIndex = -1;336337u32 newHandle = hAlloc->GetNewHandle();338entries[newHandle] = entry;339340return newHandle;341}342343if (filename.compare(0, 8, "/sce_lbn") == 0)344{345u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF;346parseLBN(filename, §orStart, &readSize);347348entry.type = VFILETYPE_LBN;349entry.size = readSize;350351int fileIndex = getFileListIndex(sectorStart,readSize);352if (fileIndex == -1)353{354ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo.");355return 0;356}357entry.fileIndex = (u32)fileIndex;358359entry.startOffset = (sectorStart-fileList[entry.fileIndex].firstBlock)*2048;360361// now we just need an actual file handle362if (fileList[entry.fileIndex].handler != NULL) {363entry.handler = fileList[entry.fileIndex].handler;364}365bool success = entry.Open(basePath, fileList[entry.fileIndex].fileName, FILEACCESS_READ);366367if (!success) {368if (!(access & FILEACCESS_PPSSPP_QUIET)) {369#ifdef _WIN32370ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, %i", (int)GetLastError());371#else372ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED");373#endif374}375return 0;376}377378// seek to start379entry.Seek(entry.startOffset, FILEMOVE_BEGIN);380381u32 newHandle = hAlloc->GetNewHandle();382entries[newHandle] = entry;383384return newHandle;385}386387entry.type = VFILETYPE_NORMAL;388entry.fileIndex = getFileListIndex(filename);389390if (entry.fileIndex != (u32)-1 && fileList[entry.fileIndex].handler != NULL) {391entry.handler = fileList[entry.fileIndex].handler;392}393bool success = entry.Open(basePath, filename, (FileAccess)(access & FILEACCESS_PSP_FLAGS));394395if (!success) {396if (!(access & FILEACCESS_PPSSPP_QUIET)) {397#ifdef _WIN32398ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", (int)GetLastError(), (int)access);399#else400ERROR_LOG(Log::FileSystem, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access);401#endif402}403return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;404} else {405u32 newHandle = hAlloc->GetNewHandle();406entries[newHandle] = entry;407408return newHandle;409}410}411412size_t VirtualDiscFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {413EntryMap::iterator iter = entries.find(handle);414if (iter != entries.end()) {415auto &entry = iter->second;416switch (entry.type)417{418case VFILETYPE_NORMAL:419{420return entry.Seek(position, type);421}422case VFILETYPE_LBN:423{424switch (type)425{426case FILEMOVE_BEGIN: entry.curOffset = position; break;427case FILEMOVE_CURRENT: entry.curOffset += position; break;428case FILEMOVE_END: entry.curOffset = entry.size + position; break;429}430431u32 off = entry.startOffset + entry.curOffset;432entry.Seek(off, FILEMOVE_BEGIN);433return entry.curOffset;434}435case VFILETYPE_ISO:436{437switch (type)438{439case FILEMOVE_BEGIN: entry.curOffset = position; break;440case FILEMOVE_CURRENT: entry.curOffset += position; break;441case FILEMOVE_END: entry.curOffset = currentBlockIndex + position; break;442}443444return entry.curOffset;445}446}447return 0;448} else {449//This shouldn't happen...450ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot seek in file that hasn't been opened: %08x", handle);451return 0;452}453}454455size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {456int ignored;457return ReadFile(handle, pointer, size, ignored);458}459460size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {461EntryMap::iterator iter = entries.find(handle);462if (iter != entries.end()) {463if (size < 0) {464ERROR_LOG_REPORT(Log::FileSystem, "Invalid read for %lld bytes from virtual umd", size);465return 0;466}467468// it's the whole iso... it could reference any of the files on the disc.469// For now let's just open and close the files on demand. Can certainly be done470// better though471if (iter->second.type == VFILETYPE_ISO)472{473int fileIndex = getFileListIndex(iter->second.curOffset,size*2048,true);474if (fileIndex == -1)475{476ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Reading from unknown address in %08x at %08llx", handle, iter->second.curOffset);477return 0;478}479480OpenFileEntry temp(Flags());481if (fileList[fileIndex].handler != NULL) {482temp.handler = fileList[fileIndex].handler;483}484bool success = temp.Open(basePath, fileList[fileIndex].fileName, FILEACCESS_READ);485486if (!success)487{488ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str());489return 0;490}491492u32 startOffset = (iter->second.curOffset-fileList[fileIndex].firstBlock)*2048;493size_t bytesRead;494495temp.Seek(startOffset, FILEMOVE_BEGIN);496497u32 remainingSize = fileList[fileIndex].totalSize-startOffset;498if (remainingSize < size * 2048)499{500// the file doesn't fill the whole last sector501// read what's there and zero fill the rest like on a real disc502bytesRead = temp.Read(pointer, remainingSize);503memset(&pointer[bytesRead], 0, size * 2048 - bytesRead);504} else {505bytesRead = temp.Read(pointer, size * 2048);506}507508temp.Close();509510iter->second.curOffset += size;511// TODO: This probably isn't enough...512if (abs((int)lastReadBlock_ - (int)iter->second.curOffset) > 100) {513// This is an estimate, sometimes it takes 1+ seconds, but it definitely takes time.514usec = 100000;515}516lastReadBlock_ = iter->second.curOffset;517return size;518}519520if (iter->second.type == VFILETYPE_LBN && iter->second.curOffset + size > iter->second.size) {521// Clamp to the remaining size, but read what we can.522const s64 newSize = iter->second.size - iter->second.curOffset;523WARN_LOG(Log::FileSystem, "VirtualDiscFileSystem: Reading beyond end of file, clamping size %lld to %lld", size, newSize);524size = newSize;525}526527size_t bytesRead = iter->second.Read(pointer, size);528iter->second.curOffset += bytesRead;529return bytesRead;530} else {531//This shouldn't happen...532ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle);533return 0;534}535}536537void VirtualDiscFileSystem::CloseFile(u32 handle) {538EntryMap::iterator iter = entries.find(handle);539if (iter != entries.end()) {540hAlloc->FreeHandle(handle);541iter->second.Close();542entries.erase(iter);543} else {544//This shouldn't happen...545ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot close file that hasn't been opened: %08x", handle);546}547}548549bool VirtualDiscFileSystem::OwnsHandle(u32 handle) {550EntryMap::iterator iter = entries.find(handle);551return (iter != entries.end());552}553554int VirtualDiscFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) {555// TODO: How to support these?556return SCE_KERNEL_ERROR_ERRNO_FUNCTION_NOT_SUPPORTED;557}558559PSPDevType VirtualDiscFileSystem::DevType(u32 handle) {560EntryMap::iterator iter = entries.find(handle);561if (iter == entries.end())562return PSPDevType::FILE;563PSPDevType type = iter->second.type == VFILETYPE_ISO ? PSPDevType::BLOCK : PSPDevType::FILE;564if (iter->second.type == VFILETYPE_LBN)565type |= PSPDevType::EMU_LBN;566return type;567}568569PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) {570PSPFileInfo x;571x.name = filename;572x.access = FILEACCESS_READ;573574if (filename.compare(0,8,"/sce_lbn") == 0) {575u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF;576parseLBN(filename, §orStart, &readSize);577578PSPFileInfo fileInfo;579fileInfo.name = filename;580fileInfo.exists = true;581fileInfo.type = FILETYPE_NORMAL;582fileInfo.size = readSize;583fileInfo.access = 0444;584fileInfo.startSector = sectorStart;585fileInfo.isOnSectorSystem = true;586fileInfo.numSectors = (readSize + 2047) / 2048;587return fileInfo;588}589590int fileIndex = getFileListIndex(filename);591if (fileIndex != -1 && fileList[fileIndex].handler != NULL) {592x.type = FILETYPE_NORMAL;593x.isOnSectorSystem = true;594x.startSector = fileList[fileIndex].firstBlock;595x.access = 0555;596597HandlerFileHandle temp = fileList[fileIndex].handler;598if (temp.Open(basePath.ToString(), filename, FILEACCESS_READ)) {599x.exists = true;600x.size = temp.Seek(0, FILEMOVE_END);601temp.Close();602}603604// TODO: Probably should include dates or something...605return x;606}607608Path fullName = GetLocalPath(filename);609if (!File::Exists(fullName)) {610#if HOST_IS_CASE_SENSITIVE611if (! FixPathCase(basePath, filename, FPC_FILE_MUST_EXIST))612return x;613fullName = GetLocalPath(filename);614615if (! File::Exists(fullName))616return x;617#else618return x;619#endif620}621622x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;623x.exists = true;624x.access = 0555;625if (fileIndex != -1) {626x.isOnSectorSystem = true;627x.startSector = fileList[fileIndex].firstBlock;628}629630if (x.type != FILETYPE_DIRECTORY) {631File::FileInfo details;632if (!File::GetFileInfo(fullName, &details)) {633ERROR_LOG(Log::FileSystem, "DirectoryFileSystem::GetFileInfo: GetFileInfo failed: %s", fullName.c_str());634x.size = 0;635x.access = 0;636} else {637x.size = details.size;638time_t atime = details.atime;639time_t ctime = details.ctime;640time_t mtime = details.mtime;641642localtime_r((time_t*)&atime, &x.atime);643localtime_r((time_t*)&ctime, &x.ctime);644localtime_r((time_t*)&mtime, &x.mtime);645}646647// x.startSector was set above in "if (fileIndex != -1)".648x.numSectors = (x.size+2047)/2048;649}650651return x;652}653654#ifdef _WIN32655#define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL656657static void tmFromFiletime(tm &dest, const FILETIME &src)658{659u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL;660u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US;661662time_t t = (time_t) (from_1970_us / 1000000UL);663localtime_r(&t, &dest);664}665#endif666667std::vector<PSPFileInfo> VirtualDiscFileSystem::GetDirListing(const std::string &path, bool *exists) {668std::vector<PSPFileInfo> myVector;669670// TODO(scoped): Switch this over to GetFilesInDir!671672#ifdef _WIN32673WIN32_FIND_DATA findData;674HANDLE hFind;675676// TODO: Handler files that are virtual might not be listed.677678std::wstring w32path = GetLocalPath(path).ToWString() + L"\\*.*";679680#if PPSSPP_PLATFORM(UWP)681hFind = FindFirstFileExFromAppW(w32path.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0);682#else683hFind = FindFirstFileEx(w32path.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0);684#endif685if (hFind == INVALID_HANDLE_VALUE) {686if (exists)687*exists = false;688return myVector; //the empty list689}690691if (exists)692*exists = true;693694for (BOOL retval = 1; retval; retval = FindNextFile(hFind, &findData)) {695if (!wcscmp(findData.cFileName, L"..") || !wcscmp(findData.cFileName, L".")) {696continue;697}698699PSPFileInfo entry;700if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {701entry.type = FILETYPE_DIRECTORY;702} else {703entry.type = FILETYPE_NORMAL;704}705706entry.access = 0555;707entry.exists = true;708entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);709entry.name = ConvertWStringToUTF8(findData.cFileName);710tmFromFiletime(entry.atime, findData.ftLastAccessTime);711tmFromFiletime(entry.ctime, findData.ftCreationTime);712tmFromFiletime(entry.mtime, findData.ftLastWriteTime);713entry.isOnSectorSystem = true;714715std::string fullRelativePath = path + "/" + entry.name;716int fileIndex = getFileListIndex(fullRelativePath);717if (fileIndex != -1)718entry.startSector = fileList[fileIndex].firstBlock;719myVector.push_back(entry);720}721FindClose(hFind);722#else723dirent *dirp;724Path localPath = GetLocalPath(path);725DIR *dp = opendir(localPath.c_str());726727#if HOST_IS_CASE_SENSITIVE728std::string fixedPath = path;729if(dp == NULL && FixPathCase(basePath, fixedPath, FPC_FILE_MUST_EXIST)) {730// May have failed due to case sensitivity, try again731localPath = GetLocalPath(fixedPath);732dp = opendir(localPath.c_str());733}734#endif735736if (dp == NULL) {737ERROR_LOG(Log::FileSystem,"Error opening directory %s\n", path.c_str());738if (exists)739*exists = false;740return myVector;741}742743if (exists)744*exists = true;745746while ((dirp = readdir(dp)) != NULL) {747if (!strcmp(dirp->d_name, "..") || !strcmp(dirp->d_name, ".")) {748continue;749}750751PSPFileInfo entry;752struct stat s;753std::string fullName = (localPath / std::string(dirp->d_name)).ToString();754stat(fullName.c_str(), &s);755if (S_ISDIR(s.st_mode))756entry.type = FILETYPE_DIRECTORY;757else758entry.type = FILETYPE_NORMAL;759entry.access = 0555;760entry.exists = true;761entry.name = dirp->d_name;762entry.size = s.st_size;763localtime_r((time_t*)&s.st_atime,&entry.atime);764localtime_r((time_t*)&s.st_ctime,&entry.ctime);765localtime_r((time_t*)&s.st_mtime,&entry.mtime);766entry.isOnSectorSystem = true;767768std::string fullRelativePath = path + "/" + entry.name;769int fileIndex = getFileListIndex(fullRelativePath);770if (fileIndex != -1)771entry.startSector = fileList[fileIndex].firstBlock;772myVector.push_back(entry);773}774closedir(dp);775#endif776return myVector;777}778779size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)780{781ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot write to file on virtual disc");782return 0;783}784785size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec)786{787ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot write to file on virtual disc");788return 0;789}790791bool VirtualDiscFileSystem::MkDir(const std::string &dirname)792{793ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot create directory on virtual disc");794return false;795}796797bool VirtualDiscFileSystem::RmDir(const std::string &dirname)798{799ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot remove directory on virtual disc");800return false;801}802803int VirtualDiscFileSystem::RenameFile(const std::string &from, const std::string &to)804{805ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot rename file on virtual disc");806return -1;807}808809bool VirtualDiscFileSystem::RemoveFile(const std::string &filename)810{811ERROR_LOG(Log::FileSystem,"VirtualDiscFileSystem: Cannot remove file on virtual disc");812return false;813}814815void VirtualDiscFileSystem::HandlerLogger(void *arg, HandlerHandle handle, LogLevel level, const char *msg) {816VirtualDiscFileSystem *sys = static_cast<VirtualDiscFileSystem *>(arg);817818// TODO: Probably could do this smarter / use a lookup.819const char *filename = NULL;820for (auto it = sys->entries.begin(), end = sys->entries.end(); it != end; ++it) {821if (it->second.fileIndex != (u32)-1 && it->second.handler.handle == handle) {822filename = sys->fileList[it->second.fileIndex].fileName.c_str();823break;824}825}826827if (filename != NULL) {828GENERIC_LOG(Log::FileSystem, level, "%s: %s", filename, msg);829} else {830GENERIC_LOG(Log::FileSystem, level, "%s", msg);831}832}833834VirtualDiscFileSystem::Handler::Handler(const char *filename, VirtualDiscFileSystem *const sys)835: sys_(sys) {836#if !PPSSPP_PLATFORM(SWITCH)837#ifdef _WIN32838#if PPSSPP_PLATFORM(UWP)839#define dlopen(name, ignore) (void *)LoadPackagedLibrary(ConvertUTF8ToWString(name).c_str(), 0)840#define dlsym(mod, name) GetProcAddress((HMODULE)mod, name)841#define dlclose(mod) FreeLibrary((HMODULE)mod)842#else843#define dlopen(name, ignore) (void *)LoadLibrary(ConvertUTF8ToWString(name).c_str())844#define dlsym(mod, name) GetProcAddress((HMODULE)mod, name)845#define dlclose(mod) FreeLibrary((HMODULE)mod)846#endif847#endif848849library = dlopen(filename, RTLD_LOCAL | RTLD_NOW);850if (library != NULL) {851Init = (InitFunc)dlsym(library, "Init");852Shutdown = (ShutdownFunc)dlsym(library, "Shutdown");853Open = (OpenFunc)dlsym(library, "Open");854Seek = (SeekFunc)dlsym(library, "Seek");855Read = (ReadFunc)dlsym(library, "Read");856Close = (CloseFunc)dlsym(library, "Close");857858VersionFunc Version = (VersionFunc)dlsym(library, "Version");859if (Version && Version() >= 2) {860ShutdownV2 = (ShutdownV2Func)Shutdown;861}862863if (!Init || !Shutdown || !Open || !Seek || !Read || !Close) {864ERROR_LOG(Log::FileSystem, "Unable to find all handler functions: %s", filename);865dlclose(library);866library = NULL;867} else if (!Init(&HandlerLogger, sys)) {868ERROR_LOG(Log::FileSystem, "Unable to initialize handler: %s", filename);869dlclose(library);870library = NULL;871}872} else {873ERROR_LOG(Log::FileSystem, "Unable to load handler '%s': %s", filename, GetLastErrorMsg().c_str());874}875#ifdef _WIN32876#undef dlopen877#undef dlsym878#undef dlclose879#endif880#endif881}882883VirtualDiscFileSystem::Handler::~Handler() {884if (library != NULL) {885if (ShutdownV2)886ShutdownV2(sys_);887else888Shutdown();889890#if !PPSSPP_PLATFORM(UWP) && !PPSSPP_PLATFORM(SWITCH)891#ifdef _WIN32892FreeLibrary((HMODULE)library);893#else894dlclose(library);895#endif896#endif897}898}899900901902