ppsspp file system module - currently unused
This commit is contained in:
		
							
								
								
									
										138
									
								
								src/core/src/file_sys/file_sys.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/core/src/file_sys/file_sys.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
// Copyright (c) 2012- PPSSPP Project.
 | 
			
		||||
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, version 2.0 or later versions.
 | 
			
		||||
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License 2.0 for more details.
 | 
			
		||||
 | 
			
		||||
// A copy of the GPL 2.0 should have been included with the program.
 | 
			
		||||
// If not, see http://www.gnu.org/licenses/
 | 
			
		||||
 | 
			
		||||
// Official git repository and contact information can be found at
 | 
			
		||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
#include "chunk_file.h"
 | 
			
		||||
 | 
			
		||||
enum FileAccess {
 | 
			
		||||
	FILEACCESS_NONE=0,
 | 
			
		||||
	FILEACCESS_READ=1,
 | 
			
		||||
	FILEACCESS_WRITE=2,
 | 
			
		||||
	FILEACCESS_APPEND=4,
 | 
			
		||||
	FILEACCESS_CREATE=8
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum FileMove {
 | 
			
		||||
	FILEMOVE_BEGIN=0,
 | 
			
		||||
	FILEMOVE_CURRENT=1,
 | 
			
		||||
	FILEMOVE_END=2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum FileType {
 | 
			
		||||
	FILETYPE_NORMAL=1,
 | 
			
		||||
	FILETYPE_DIRECTORY=2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IHandleAllocator {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~IHandleAllocator() {}
 | 
			
		||||
	virtual u32 GetNewHandle() = 0;
 | 
			
		||||
	virtual void FreeHandle(u32 handle) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SequentialHandleAllocator : public IHandleAllocator {
 | 
			
		||||
public:
 | 
			
		||||
	SequentialHandleAllocator() : handle_(1) {}
 | 
			
		||||
	virtual u32 GetNewHandle() { return handle_++; }
 | 
			
		||||
	virtual void FreeHandle(u32 handle) {}
 | 
			
		||||
private:
 | 
			
		||||
	int handle_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PSPFileInfo {
 | 
			
		||||
	PSPFileInfo() 
 | 
			
		||||
		: size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0) {}
 | 
			
		||||
 | 
			
		||||
	void DoState(PointerWrap &p) {
 | 
			
		||||
		auto s = p.Section("PSPFileInfo", 1);
 | 
			
		||||
		if (!s)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		p.Do(name);
 | 
			
		||||
		p.Do(size);
 | 
			
		||||
		p.Do(access);
 | 
			
		||||
		p.Do(exists);
 | 
			
		||||
		p.Do(type);
 | 
			
		||||
		p.Do(atime);
 | 
			
		||||
		p.Do(ctime);
 | 
			
		||||
		p.Do(mtime);
 | 
			
		||||
		p.Do(isOnSectorSystem);
 | 
			
		||||
		p.Do(startSector);
 | 
			
		||||
		p.Do(numSectors);
 | 
			
		||||
		p.Do(sectorSize);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string name;
 | 
			
		||||
	s64 size;
 | 
			
		||||
	u32 access; //unix 777
 | 
			
		||||
	bool exists;
 | 
			
		||||
	FileType type;
 | 
			
		||||
 | 
			
		||||
	tm atime;
 | 
			
		||||
	tm ctime;
 | 
			
		||||
	tm mtime;
 | 
			
		||||
 | 
			
		||||
	bool isOnSectorSystem;
 | 
			
		||||
	u32 startSector;
 | 
			
		||||
	u32 numSectors;
 | 
			
		||||
	u32 sectorSize;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IFileSystem {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~IFileSystem() {}
 | 
			
		||||
 | 
			
		||||
	virtual void DoState(PointerWrap &p) = 0;
 | 
			
		||||
	virtual std::vector<PSPFileInfo> GetDirListing(std::string path) = 0;
 | 
			
		||||
	virtual u32      OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) = 0;
 | 
			
		||||
	virtual void     CloseFile(u32 handle) = 0;
 | 
			
		||||
	virtual size_t   ReadFile(u32 handle, u8 *pointer, s64 size) = 0;
 | 
			
		||||
	virtual size_t   WriteFile(u32 handle, const u8 *pointer, s64 size) = 0;
 | 
			
		||||
	virtual size_t   SeekFile(u32 handle, s32 position, FileMove type) = 0;
 | 
			
		||||
	virtual PSPFileInfo GetFileInfo(std::string filename) = 0;
 | 
			
		||||
	virtual bool     OwnsHandle(u32 handle) = 0;
 | 
			
		||||
	virtual bool     MkDir(const std::string &dirname) = 0;
 | 
			
		||||
	virtual bool     RmDir(const std::string &dirname) = 0;
 | 
			
		||||
	virtual int      RenameFile(const std::string &from, const std::string &to) = 0;
 | 
			
		||||
	virtual bool     RemoveFile(const std::string &filename) = 0;
 | 
			
		||||
	virtual bool     GetHostPath(const std::string &inpath, std::string &outpath) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EmptyFileSystem : public IFileSystem {
 | 
			
		||||
public:
 | 
			
		||||
	virtual void DoState(PointerWrap &p) {}
 | 
			
		||||
	std::vector<PSPFileInfo> GetDirListing(std::string path) {std::vector<PSPFileInfo> vec; return vec;}
 | 
			
		||||
	u32      OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) {return 0;}
 | 
			
		||||
	void     CloseFile(u32 handle) {}
 | 
			
		||||
	size_t   ReadFile(u32 handle, u8 *pointer, s64 size) {return 0;}
 | 
			
		||||
	size_t   WriteFile(u32 handle, const u8 *pointer, s64 size) {return 0;}
 | 
			
		||||
	size_t   SeekFile(u32 handle, s32 position, FileMove type) {return 0;}
 | 
			
		||||
	PSPFileInfo GetFileInfo(std::string filename) {PSPFileInfo f; return f;}
 | 
			
		||||
	bool     OwnsHandle(u32 handle) {return false;}
 | 
			
		||||
	virtual bool MkDir(const std::string &dirname) {return false;}
 | 
			
		||||
	virtual bool RmDir(const std::string &dirname) {return false;}
 | 
			
		||||
	virtual int RenameFile(const std::string &from, const std::string &to) {return -1;}
 | 
			
		||||
	virtual bool RemoveFile(const std::string &filename) {return false;}
 | 
			
		||||
	virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										712
									
								
								src/core/src/file_sys/file_sys_directory.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										712
									
								
								src/core/src/file_sys/file_sys_directory.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,712 @@
 | 
			
		||||
// Copyright (c) 2012- PPSSPP Project.
 | 
			
		||||
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, version 2.0 or later versions.
 | 
			
		||||
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License 2.0 for more details.
 | 
			
		||||
 | 
			
		||||
// A copy of the GPL 2.0 should have been included with the program.
 | 
			
		||||
// If not, see http://www.gnu.org/licenses/
 | 
			
		||||
 | 
			
		||||
// Official git repository and contact information can be found at
 | 
			
		||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 | 
			
		||||
 | 
			
		||||
#include "chunk_file.h"
 | 
			
		||||
#include "file_util.h"
 | 
			
		||||
#include "file_sys_directory.h"
 | 
			
		||||
//#include "ISOFileSystem.h"
 | 
			
		||||
//#include "Core/HLE/sceKernel.h"
 | 
			
		||||
//#include "file/zip_read.h"
 | 
			
		||||
//#include "util/text/utf8.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
//#include "Common/CommonWindows.h"
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath)
 | 
			
		||||
{
 | 
			
		||||
	if (localpath.empty())
 | 
			
		||||
		return basePath;
 | 
			
		||||
 | 
			
		||||
	if (localpath[0] == '/')
 | 
			
		||||
		localpath.erase(0,1);
 | 
			
		||||
	//Convert slashes
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	for (size_t i = 0; i < localpath.size(); i++) {
 | 
			
		||||
		if (localpath[i] == '/')
 | 
			
		||||
			localpath[i] = '\\';
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return basePath + localpath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, FileAccess access) {
 | 
			
		||||
	std::string fullName = GetLocalPath(basePath,fileName);
 | 
			
		||||
	INFO_LOG(FILESYS, "Actually opening %s", fullName.c_str());
 | 
			
		||||
 | 
			
		||||
	//TODO: tests, should append seek to end of file? seeking in a file opened for append?
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	// Convert parameters to Windows permissions and access
 | 
			
		||||
	DWORD desired = 0;
 | 
			
		||||
	DWORD sharemode = 0;
 | 
			
		||||
	DWORD openmode = 0;
 | 
			
		||||
	if (access & FILEACCESS_READ) {
 | 
			
		||||
		desired   |= GENERIC_READ;
 | 
			
		||||
		sharemode |= FILE_SHARE_READ;
 | 
			
		||||
	}
 | 
			
		||||
	if (access & FILEACCESS_WRITE) {
 | 
			
		||||
		desired   |= GENERIC_WRITE;
 | 
			
		||||
		sharemode |= FILE_SHARE_WRITE;
 | 
			
		||||
	}
 | 
			
		||||
	if (access & FILEACCESS_CREATE) {
 | 
			
		||||
		openmode = OPEN_ALWAYS;
 | 
			
		||||
	} else {
 | 
			
		||||
		openmode = OPEN_EXISTING;
 | 
			
		||||
	}
 | 
			
		||||
	//Let's do it!
 | 
			
		||||
	hFile = CreateFile(fullName.c_str(), desired, sharemode, 0, openmode, 0, 0);
 | 
			
		||||
	bool success = hFile != INVALID_HANDLE_VALUE;
 | 
			
		||||
#else
 | 
			
		||||
	// Convert flags in access parameter to fopen access mode
 | 
			
		||||
	const char *mode = NULL;
 | 
			
		||||
	if (access & FILEACCESS_APPEND) {
 | 
			
		||||
		if (access & FILEACCESS_READ)
 | 
			
		||||
			mode = "ab+";  // append+read, create if needed
 | 
			
		||||
		else
 | 
			
		||||
			mode = "ab";  // append only, create if needed
 | 
			
		||||
	} else if (access & FILEACCESS_WRITE) {
 | 
			
		||||
		if (access & FILEACCESS_READ) {
 | 
			
		||||
			// FILEACCESS_CREATE is ignored for read only, write only, and append
 | 
			
		||||
			// because C++ standard fopen's nonexistant file creation can only be
 | 
			
		||||
			// customized for files opened read+write
 | 
			
		||||
			if (access & FILEACCESS_CREATE)
 | 
			
		||||
				mode = "wb+";  // read+write, create if needed
 | 
			
		||||
			else
 | 
			
		||||
				mode = "rb+";  // read+write, but don't create
 | 
			
		||||
		} else {
 | 
			
		||||
			mode = "wb";  // write only, create if needed
 | 
			
		||||
		}
 | 
			
		||||
	} else {  // neither write nor append, so default to read only
 | 
			
		||||
		mode = "rb";  // read only, don't create
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hFile = fopen(fullName.c_str(), mode);
 | 
			
		||||
	bool success = hFile != 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	if (!success &&
 | 
			
		||||
	    !(access & FILEACCESS_APPEND) &&
 | 
			
		||||
	    !(access & FILEACCESS_CREATE) &&
 | 
			
		||||
	    !(access & FILEACCESS_WRITE))
 | 
			
		||||
	{
 | 
			
		||||
		if ( ! FixPathCase(basePath,fileName, FPC_PATH_MUST_EXIST) )
 | 
			
		||||
			return 0;  // or go on and attempt (for a better error code than just 0?)
 | 
			
		||||
		fullName = GetLocalPath(basePath,fileName); 
 | 
			
		||||
		const char* fullNameC = fullName.c_str();
 | 
			
		||||
 | 
			
		||||
		DEBUG_LOG(FILESYS, "Case may have been incorrect, second try opening %s (%s)", fullNameC, fileName.c_str());
 | 
			
		||||
 | 
			
		||||
		// And try again with the correct case this time
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		hFile = CreateFile(fullNameC, desired, sharemode, 0, openmode, 0, 0);
 | 
			
		||||
		success = hFile != INVALID_HANDLE_VALUE;
 | 
			
		||||
#else
 | 
			
		||||
		hFile = fopen(fullNameC, mode);
 | 
			
		||||
		success = hFile != 0;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileHandle::Read(u8* pointer, s64 size)
 | 
			
		||||
{
 | 
			
		||||
	size_t bytesRead = 0;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0);
 | 
			
		||||
#else
 | 
			
		||||
	bytesRead = fread(pointer, 1, size, hFile);
 | 
			
		||||
#endif
 | 
			
		||||
	return bytesRead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
 | 
			
		||||
{
 | 
			
		||||
	size_t bytesWritten = 0;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0);
 | 
			
		||||
#else
 | 
			
		||||
	bytesWritten = fwrite(pointer, 1, size, hFile);
 | 
			
		||||
#endif
 | 
			
		||||
	return bytesWritten;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileHandle::Seek(s32 position, FileMove type)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	DWORD moveMethod = 0;
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case FILEMOVE_BEGIN:    moveMethod = FILE_BEGIN;    break;
 | 
			
		||||
	case FILEMOVE_CURRENT:  moveMethod = FILE_CURRENT;  break;
 | 
			
		||||
	case FILEMOVE_END:      moveMethod = FILE_END;      break;
 | 
			
		||||
	}
 | 
			
		||||
	DWORD newPos = SetFilePointer(hFile, (LONG)position, 0, moveMethod);
 | 
			
		||||
	return newPos;
 | 
			
		||||
#else
 | 
			
		||||
	int moveMethod = 0;
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case FILEMOVE_BEGIN:    moveMethod = SEEK_SET;  break;
 | 
			
		||||
	case FILEMOVE_CURRENT:  moveMethod = SEEK_CUR;  break;
 | 
			
		||||
	case FILEMOVE_END:      moveMethod = SEEK_END;  break;
 | 
			
		||||
	}
 | 
			
		||||
	fseek(hFile, position, moveMethod);
 | 
			
		||||
	return ftell(hFile);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DirectoryFileHandle::Close()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	if (hFile != (HANDLE)-1)
 | 
			
		||||
		CloseHandle(hFile);
 | 
			
		||||
#else
 | 
			
		||||
	if (hFile != 0)
 | 
			
		||||
		fclose(hFile);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
 | 
			
		||||
	File::CreateFullPath(basePath);
 | 
			
		||||
	hAlloc = _hAlloc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DirectoryFileSystem::~DirectoryFileSystem() {
 | 
			
		||||
	for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
 | 
			
		||||
		iter->second.hFile.Close();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string DirectoryFileSystem::GetLocalPath(std::string localpath) {
 | 
			
		||||
	if (localpath.empty())
 | 
			
		||||
		return basePath;
 | 
			
		||||
 | 
			
		||||
	if (localpath[0] == '/')
 | 
			
		||||
		localpath.erase(0,1);
 | 
			
		||||
	//Convert slashes
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	for (size_t i = 0; i < localpath.size(); i++) {
 | 
			
		||||
		if (localpath[i] == '/')
 | 
			
		||||
			localpath[i] = '\\';
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return basePath + localpath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileSystem::MkDir(const std::string &dirname) {
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	// Must fix case BEFORE attempting, because MkDir would create
 | 
			
		||||
	// duplicate (different case) directories
 | 
			
		||||
 | 
			
		||||
	std::string fixedCase = dirname;
 | 
			
		||||
	if ( ! FixPathCase(basePath,fixedCase, FPC_PARTIAL_ALLOWED) )
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	return File::CreateFullPath(GetLocalPath(fixedCase));
 | 
			
		||||
#else
 | 
			
		||||
	return File::CreateFullPath(GetLocalPath(dirname));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileSystem::RmDir(const std::string &dirname) {
 | 
			
		||||
	std::string fullName = GetLocalPath(dirname);
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	// Maybe we're lucky?
 | 
			
		||||
	if (File::DeleteDirRecursively(fullName))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	// Nope, fix case and try again
 | 
			
		||||
	fullName = dirname;
 | 
			
		||||
	if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) )
 | 
			
		||||
		return false;  // or go on and attempt (for a better error code than just false?)
 | 
			
		||||
 | 
			
		||||
	fullName = GetLocalPath(fullName);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*#ifdef _WIN32
 | 
			
		||||
	return RemoveDirectory(fullName.c_str()) == TRUE;
 | 
			
		||||
#else
 | 
			
		||||
	return 0 == rmdir(fullName.c_str());
 | 
			
		||||
#endif*/
 | 
			
		||||
	return File::DeleteDirRecursively(fullName);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DirectoryFileSystem::RenameFile(const std::string &from, const std::string &to) {
 | 
			
		||||
	std::string fullTo = to;
 | 
			
		||||
 | 
			
		||||
	// Rename ignores the path (even if specified) on to.
 | 
			
		||||
	size_t chop_at = to.find_last_of('/');
 | 
			
		||||
	if (chop_at != to.npos)
 | 
			
		||||
		fullTo = to.substr(chop_at + 1);
 | 
			
		||||
 | 
			
		||||
	// Now put it in the same directory as from.
 | 
			
		||||
	size_t dirname_end = from.find_last_of('/');
 | 
			
		||||
	if (dirname_end != from.npos)
 | 
			
		||||
		fullTo = from.substr(0, dirname_end + 1) + fullTo;
 | 
			
		||||
 | 
			
		||||
	// At this point, we should check if the paths match and give an already exists error.
 | 
			
		||||
	if (from == fullTo)
 | 
			
		||||
		return SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS;
 | 
			
		||||
 | 
			
		||||
	std::string fullFrom = GetLocalPath(from);
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	// In case TO should overwrite a file with different case
 | 
			
		||||
	if ( ! FixPathCase(basePath,fullTo, FPC_PATH_MUST_EXIST) )
 | 
			
		||||
		return -1;  // or go on and attempt (for a better error code than just false?)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	fullTo = GetLocalPath(fullTo);
 | 
			
		||||
	const char * fullToC = fullTo.c_str();
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	bool retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE);
 | 
			
		||||
#else
 | 
			
		||||
	bool retValue = (0 == rename(fullFrom.c_str(), fullToC));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	if (! retValue)
 | 
			
		||||
	{
 | 
			
		||||
		// May have failed due to case sensitivity on FROM, so try again
 | 
			
		||||
		fullFrom = from;
 | 
			
		||||
		if ( ! FixPathCase(basePath,fullFrom, FPC_FILE_MUST_EXIST) )
 | 
			
		||||
			return -1;  // or go on and attempt (for a better error code than just false?)
 | 
			
		||||
		fullFrom = GetLocalPath(fullFrom);
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE);
 | 
			
		||||
#else
 | 
			
		||||
		retValue = (0 == rename(fullFrom.c_str(), fullToC));
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// TODO: Better error codes.
 | 
			
		||||
	return retValue ? 0 : SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileSystem::RemoveFile(const std::string &filename) {
 | 
			
		||||
	std::string fullName = GetLocalPath(filename);
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
 | 
			
		||||
#else
 | 
			
		||||
	bool retValue = (0 == unlink(fullName.c_str()));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	if (! retValue)
 | 
			
		||||
	{
 | 
			
		||||
		// May have failed due to case sensitivity, so try again
 | 
			
		||||
		fullName = filename;
 | 
			
		||||
		if ( ! FixPathCase(basePath,fullName, FPC_FILE_MUST_EXIST) )
 | 
			
		||||
			return false;  // or go on and attempt (for a better error code than just false?)
 | 
			
		||||
		fullName = GetLocalPath(fullName);
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
 | 
			
		||||
#else
 | 
			
		||||
		retValue = (0 == unlink(fullName.c_str()));
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return retValue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
 | 
			
		||||
	OpenFileEntry entry;
 | 
			
		||||
	bool success = entry.hFile.Open(basePath,filename,access);
 | 
			
		||||
 | 
			
		||||
	if (!success) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access);
 | 
			
		||||
#else
 | 
			
		||||
		ERROR_LOG(FILESYS, "DirectoryFileSystem::OpenFile: FAILED, access = %i", (int)access);
 | 
			
		||||
#endif
 | 
			
		||||
		//wwwwaaaaahh!!
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		if (access & FILEACCESS_APPEND)
 | 
			
		||||
			entry.hFile.Seek(0,FILEMOVE_END);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		u32 newHandle = hAlloc->GetNewHandle();
 | 
			
		||||
		entries[newHandle] = entry;
 | 
			
		||||
 | 
			
		||||
		return newHandle;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DirectoryFileSystem::CloseFile(u32 handle) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end()) {
 | 
			
		||||
		hAlloc->FreeHandle(handle);
 | 
			
		||||
		iter->second.hFile.Close();
 | 
			
		||||
		entries.erase(iter);
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileSystem::OwnsHandle(u32 handle) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	return (iter != entries.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end())
 | 
			
		||||
	{
 | 
			
		||||
		size_t bytesRead = iter->second.hFile.Read(pointer,size);
 | 
			
		||||
		return bytesRead;
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end())
 | 
			
		||||
	{
 | 
			
		||||
		size_t bytesWritten = iter->second.hFile.Write(pointer,size);
 | 
			
		||||
		return bytesWritten;
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot write to file that hasn't been opened: %08x", handle);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end()) {
 | 
			
		||||
		return iter->second.hFile.Seek(position,type);
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
 | 
			
		||||
	PSPFileInfo x;
 | 
			
		||||
	x.name = filename;
 | 
			
		||||
 | 
			
		||||
	std::string fullName = GetLocalPath(filename);
 | 
			
		||||
	if (! File::Exists(fullName)) {
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
		if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST))
 | 
			
		||||
			return x;
 | 
			
		||||
		fullName = GetLocalPath(filename);
 | 
			
		||||
 | 
			
		||||
		if (! File::Exists(fullName))
 | 
			
		||||
			return x;
 | 
			
		||||
#else
 | 
			
		||||
		return x;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
 | 
			
		||||
	x.exists = true;
 | 
			
		||||
 | 
			
		||||
	if (x.type != FILETYPE_DIRECTORY)
 | 
			
		||||
	{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		struct _stat64i32 s;
 | 
			
		||||
		_wstat64i32(fullName.c_str(), &s);
 | 
			
		||||
#else
 | 
			
		||||
		struct stat s;
 | 
			
		||||
		stat(fullName.c_str(), &s);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		x.size = File::GetSize(fullName);
 | 
			
		||||
		x.access = s.st_mode & 0x1FF;
 | 
			
		||||
		localtime_r((time_t*)&s.st_atime,&x.atime);
 | 
			
		||||
		localtime_r((time_t*)&s.st_ctime,&x.ctime);
 | 
			
		||||
		localtime_r((time_t*)&s.st_mtime,&x.mtime);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
 | 
			
		||||
	outpath = GetLocalPath(inpath);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define FILETIME_FROM_UNIX_EPOCH_US 11644473600000000ULL
 | 
			
		||||
 | 
			
		||||
static void tmFromFiletime(tm &dest, FILETIME &src)
 | 
			
		||||
{
 | 
			
		||||
	u64 from_1601_us = (((u64) src.dwHighDateTime << 32ULL) + (u64) src.dwLowDateTime) / 10ULL;
 | 
			
		||||
	u64 from_1970_us = from_1601_us - FILETIME_FROM_UNIX_EPOCH_US;
 | 
			
		||||
 | 
			
		||||
	time_t t = (time_t) (from_1970_us / 1000000UL);
 | 
			
		||||
	localtime_r(&t, &dest);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
 | 
			
		||||
	std::vector<PSPFileInfo> myVector;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	WIN32_FIND_DATA findData;
 | 
			
		||||
	HANDLE hFind;
 | 
			
		||||
 | 
			
		||||
	std::string w32path = GetLocalPath(path) + "\\*.*";
 | 
			
		||||
 | 
			
		||||
	hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData);
 | 
			
		||||
 | 
			
		||||
	if (hFind == INVALID_HANDLE_VALUE) {
 | 
			
		||||
		return myVector; //the empty list
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		PSPFileInfo entry;
 | 
			
		||||
		if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 | 
			
		||||
			entry.type = FILETYPE_DIRECTORY;
 | 
			
		||||
		else
 | 
			
		||||
			entry.type = FILETYPE_NORMAL;
 | 
			
		||||
 | 
			
		||||
		// TODO: Make this more correct?
 | 
			
		||||
		entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777;
 | 
			
		||||
		// TODO: is this just for .. or all subdirectories? Need to add a directory to the test
 | 
			
		||||
		// to find out. Also why so different than the old test results?
 | 
			
		||||
		if (!wcscmp(findData.cFileName, L"..") )
 | 
			
		||||
			entry.size = 4096;
 | 
			
		||||
		else
 | 
			
		||||
			entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
 | 
			
		||||
		entry.name = ConvertWStringToUTF8(findData.cFileName);
 | 
			
		||||
		tmFromFiletime(entry.atime, findData.ftLastAccessTime);
 | 
			
		||||
		tmFromFiletime(entry.ctime, findData.ftCreationTime);
 | 
			
		||||
		tmFromFiletime(entry.mtime, findData.ftLastWriteTime);
 | 
			
		||||
		myVector.push_back(entry);
 | 
			
		||||
 | 
			
		||||
		int retval = FindNextFile(hFind, &findData);
 | 
			
		||||
		if (!retval)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	dirent *dirp;
 | 
			
		||||
	std::string localPath = GetLocalPath(path);
 | 
			
		||||
	DIR *dp = opendir(localPath.c_str());
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
	if(dp == NULL && FixPathCase(basePath,path, FPC_FILE_MUST_EXIST)) {
 | 
			
		||||
		// May have failed due to case sensitivity, try again
 | 
			
		||||
		localPath = GetLocalPath(path);
 | 
			
		||||
		dp = opendir(localPath.c_str());
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (dp == NULL) {
 | 
			
		||||
		ERROR_LOG(FILESYS,"Error opening directory %s\n",path.c_str());
 | 
			
		||||
		return myVector;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((dirp = readdir(dp)) != NULL) {
 | 
			
		||||
		PSPFileInfo entry;
 | 
			
		||||
		struct stat s;
 | 
			
		||||
		std::string fullName = GetLocalPath(path) + "/"+dirp->d_name;
 | 
			
		||||
		stat(fullName.c_str(), &s);
 | 
			
		||||
		if (S_ISDIR(s.st_mode))
 | 
			
		||||
			entry.type = FILETYPE_DIRECTORY;
 | 
			
		||||
		else
 | 
			
		||||
			entry.type = FILETYPE_NORMAL;
 | 
			
		||||
		entry.access = s.st_mode & 0x1FF;
 | 
			
		||||
		entry.name = dirp->d_name;
 | 
			
		||||
		entry.size = s.st_size;
 | 
			
		||||
		localtime_r((time_t*)&s.st_atime,&entry.atime);
 | 
			
		||||
		localtime_r((time_t*)&s.st_ctime,&entry.ctime);
 | 
			
		||||
		localtime_r((time_t*)&s.st_mtime,&entry.mtime);
 | 
			
		||||
		myVector.push_back(entry);
 | 
			
		||||
	}
 | 
			
		||||
	closedir(dp);
 | 
			
		||||
#endif
 | 
			
		||||
	return myVector;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DirectoryFileSystem::DoState(PointerWrap &p) {
 | 
			
		||||
	if (!entries.empty()) {
 | 
			
		||||
		p.SetError(p.ERROR_WARNING);
 | 
			
		||||
		ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly.");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
VFSFileSystem::VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
 | 
			
		||||
	INFO_LOG(FILESYS, "Creating VFS file system");
 | 
			
		||||
	hAlloc = _hAlloc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VFSFileSystem::~VFSFileSystem() {
 | 
			
		||||
	for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
 | 
			
		||||
		delete [] iter->second.fileData;
 | 
			
		||||
	}
 | 
			
		||||
	entries.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string VFSFileSystem::GetLocalPath(std::string localPath) {
 | 
			
		||||
	return basePath + localPath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VFSFileSystem::MkDir(const std::string &dirname) {
 | 
			
		||||
	// NOT SUPPORTED - READ ONLY
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VFSFileSystem::RmDir(const std::string &dirname) {
 | 
			
		||||
	// NOT SUPPORTED - READ ONLY
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int VFSFileSystem::RenameFile(const std::string &from, const std::string &to) {
 | 
			
		||||
	// NOT SUPPORTED - READ ONLY
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VFSFileSystem::RemoveFile(const std::string &filename) {
 | 
			
		||||
	// NOT SUPPORTED - READ ONLY
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 VFSFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
 | 
			
		||||
	if (access != FILEACCESS_READ) {
 | 
			
		||||
		ERROR_LOG(FILESYS, "VFSFileSystem only supports plain reading");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string fullName = GetLocalPath(filename);
 | 
			
		||||
	const char *fullNameC = fullName.c_str();
 | 
			
		||||
	INFO_LOG(FILESYS,"VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str());
 | 
			
		||||
 | 
			
		||||
	size_t size;
 | 
			
		||||
	u8 *data = VFSReadFile(fullNameC, &size);
 | 
			
		||||
	if (!data) {
 | 
			
		||||
		ERROR_LOG(FILESYS, "VFSFileSystem failed to open %s", filename.c_str());
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	OpenFileEntry entry;
 | 
			
		||||
	entry.fileData = data;
 | 
			
		||||
	entry.size = size;
 | 
			
		||||
	entry.seekPos = 0;
 | 
			
		||||
	u32 newHandle = hAlloc->GetNewHandle();
 | 
			
		||||
	entries[newHandle] = entry;
 | 
			
		||||
	return newHandle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PSPFileInfo VFSFileSystem::GetFileInfo(std::string filename) {
 | 
			
		||||
	PSPFileInfo x;
 | 
			
		||||
	x.name = filename;
 | 
			
		||||
 | 
			
		||||
	std::string fullName = GetLocalPath(filename);
 | 
			
		||||
	INFO_LOG(FILESYS,"Getting VFS file info %s (%s)", fullName.c_str(), filename.c_str());
 | 
			
		||||
	FileInfo fo;
 | 
			
		||||
	VFSGetFileInfo(fullName.c_str(), &fo);
 | 
			
		||||
	x.exists = fo.exists;
 | 
			
		||||
	if (x.exists) {
 | 
			
		||||
		x.size = fo.size;
 | 
			
		||||
		x.type = fo.isDirectory ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
 | 
			
		||||
	}
 | 
			
		||||
	INFO_LOG(FILESYS,"Got VFS file info: size = %i", (int)x.size);
 | 
			
		||||
	return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VFSFileSystem::CloseFile(u32 handle) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end()) {
 | 
			
		||||
		delete [] iter->second.fileData;
 | 
			
		||||
		entries.erase(iter);
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot close file that hasn't been opened: %08x", handle);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VFSFileSystem::OwnsHandle(u32 handle) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	return (iter != entries.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
 | 
			
		||||
	INFO_LOG(FILESYS,"VFSFileSystem::ReadFile %08x %p %i", handle, pointer, (u32)size);
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end())
 | 
			
		||||
	{
 | 
			
		||||
		size_t bytesRead = size;
 | 
			
		||||
		memcpy(pointer, iter->second.fileData + iter->second.seekPos, size);
 | 
			
		||||
		iter->second.seekPos += size;
 | 
			
		||||
		return bytesRead;
 | 
			
		||||
	} else {
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot read file that hasn't been opened: %08x", handle);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t VFSFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
 | 
			
		||||
	// NOT SUPPORTED - READ ONLY
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t VFSFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
 | 
			
		||||
	EntryMap::iterator iter = entries.find(handle);
 | 
			
		||||
	if (iter != entries.end()) {
 | 
			
		||||
		switch (type) {
 | 
			
		||||
		case FILEMOVE_BEGIN:    iter->second.seekPos = position; break;
 | 
			
		||||
		case FILEMOVE_CURRENT:  iter->second.seekPos += position;  break;
 | 
			
		||||
		case FILEMOVE_END:      iter->second.seekPos = iter->second.size + position; break;
 | 
			
		||||
		}
 | 
			
		||||
		return iter->second.seekPos;
 | 
			
		||||
	} else {
 | 
			
		||||
		//This shouldn't happen...
 | 
			
		||||
		ERROR_LOG(FILESYS,"Cannot seek in file that hasn't been opened: %08x", handle);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool VFSFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
 | 
			
		||||
	// NOT SUPPORTED
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<PSPFileInfo> VFSFileSystem::GetDirListing(std::string path) {
 | 
			
		||||
	std::vector<PSPFileInfo> myVector;
 | 
			
		||||
	// TODO
 | 
			
		||||
	return myVector;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VFSFileSystem::DoState(PointerWrap &p) {
 | 
			
		||||
	if (!entries.empty()) {
 | 
			
		||||
		p.SetError(p.ERROR_WARNING);
 | 
			
		||||
		ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly.");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										158
									
								
								src/core/src/file_sys/file_sys_directory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/core/src/file_sys/file_sys_directory.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
// Copyright (c) 2012- PPSSPP Project.
 | 
			
		||||
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, version 2.0 or later versions.
 | 
			
		||||
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License 2.0 for more details.
 | 
			
		||||
 | 
			
		||||
// A copy of the GPL 2.0 should have been included with the program.
 | 
			
		||||
// If not, see http://www.gnu.org/licenses/
 | 
			
		||||
 | 
			
		||||
// Official git repository and contact information can be found at
 | 
			
		||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 | 
			
		||||
 | 
			
		||||
#ifndef CORE_FILE_SYS_DIRECTORY_H_
 | 
			
		||||
#define CORE_FILE_SYS_DIRECTORY_H_
 | 
			
		||||
 | 
			
		||||
// TODO: Remove the Windows-specific code, FILE is fine there too.
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
#include "file_sys.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
typedef void * HANDLE;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IPHONE
 | 
			
		||||
#define HOST_IS_CASE_SENSITIVE 1
 | 
			
		||||
#elif TARGET_IPHONE_SIMULATOR
 | 
			
		||||
#define HOST_IS_CASE_SENSITIVE 0
 | 
			
		||||
#else
 | 
			
		||||
// Mac OSX case sensitivity defaults off, but is user configurable (when
 | 
			
		||||
// creating a filesytem), so assume the worst:
 | 
			
		||||
#define HOST_IS_CASE_SENSITIVE 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#elif defined(_WIN32) || defined(__SYMBIAN32__)
 | 
			
		||||
#define HOST_IS_CASE_SENSITIVE 0
 | 
			
		||||
 | 
			
		||||
#else  // Android, Linux, BSD (and the rest?)
 | 
			
		||||
#define HOST_IS_CASE_SENSITIVE 1
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HOST_IS_CASE_SENSITIVE
 | 
			
		||||
enum FixPathCaseBehavior {
 | 
			
		||||
	FPC_FILE_MUST_EXIST,  // all path components must exist (rmdir, move from)
 | 
			
		||||
	FPC_PATH_MUST_EXIST,  // all except the last one must exist - still tries to fix last one (fopen, move to)
 | 
			
		||||
	FPC_PARTIAL_ALLOWED,  // don't care how many exist (mkdir recursive)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct DirectoryFileHandle
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	HANDLE hFile;
 | 
			
		||||
#else
 | 
			
		||||
	FILE* hFile;
 | 
			
		||||
#endif
 | 
			
		||||
	DirectoryFileHandle()
 | 
			
		||||
	{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		hFile = (HANDLE)-1;
 | 
			
		||||
#else
 | 
			
		||||
		hFile = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string GetLocalPath(std::string& basePath, std::string localpath);
 | 
			
		||||
	bool Open(std::string& basePath, std::string& fileName, FileAccess access);
 | 
			
		||||
	size_t Read(u8* pointer, s64 size);
 | 
			
		||||
	size_t Write(const u8* pointer, s64 size);
 | 
			
		||||
	size_t Seek(s32 position, FileMove type);
 | 
			
		||||
	void Close();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DirectoryFileSystem : public IFileSystem {
 | 
			
		||||
public:
 | 
			
		||||
	DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
 | 
			
		||||
	~DirectoryFileSystem();
 | 
			
		||||
 | 
			
		||||
	void DoState(PointerWrap &p);
 | 
			
		||||
	std::vector<PSPFileInfo> GetDirListing(std::string path);
 | 
			
		||||
	u32      OpenFile(std::string filename, FileAccess access, const char *devicename=NULL);
 | 
			
		||||
	void     CloseFile(u32 handle);
 | 
			
		||||
	size_t   ReadFile(u32 handle, u8 *pointer, s64 size);
 | 
			
		||||
	size_t   WriteFile(u32 handle, const u8 *pointer, s64 size);
 | 
			
		||||
	size_t   SeekFile(u32 handle, s32 position, FileMove type);
 | 
			
		||||
	PSPFileInfo GetFileInfo(std::string filename);
 | 
			
		||||
	bool     OwnsHandle(u32 handle);
 | 
			
		||||
 | 
			
		||||
	bool MkDir(const std::string &dirname);
 | 
			
		||||
	bool RmDir(const std::string &dirname);
 | 
			
		||||
	int  RenameFile(const std::string &from, const std::string &to);
 | 
			
		||||
	bool RemoveFile(const std::string &filename);
 | 
			
		||||
	bool GetHostPath(const std::string &inpath, std::string &outpath);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	struct OpenFileEntry {
 | 
			
		||||
		DirectoryFileHandle hFile;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	typedef std::map<u32, OpenFileEntry> EntryMap;
 | 
			
		||||
	EntryMap entries;
 | 
			
		||||
	std::string basePath;
 | 
			
		||||
	IHandleAllocator *hAlloc;
 | 
			
		||||
 | 
			
		||||
	// In case of Windows: Translate slashes, etc.
 | 
			
		||||
	std::string GetLocalPath(std::string localpath);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts.
 | 
			
		||||
// Very inefficient - always load the whole file on open.
 | 
			
		||||
class VFSFileSystem : public IFileSystem {
 | 
			
		||||
public:
 | 
			
		||||
	VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
 | 
			
		||||
	~VFSFileSystem();
 | 
			
		||||
 | 
			
		||||
	void DoState(PointerWrap &p);
 | 
			
		||||
	std::vector<PSPFileInfo> GetDirListing(std::string path);
 | 
			
		||||
	u32      OpenFile(std::string filename, FileAccess access, const char *devicename=NULL);
 | 
			
		||||
	void     CloseFile(u32 handle);
 | 
			
		||||
	size_t   ReadFile(u32 handle, u8 *pointer, s64 size);
 | 
			
		||||
	size_t   WriteFile(u32 handle, const u8 *pointer, s64 size);
 | 
			
		||||
	size_t   SeekFile(u32 handle, s32 position, FileMove type);
 | 
			
		||||
	PSPFileInfo GetFileInfo(std::string filename);
 | 
			
		||||
	bool     OwnsHandle(u32 handle);
 | 
			
		||||
 | 
			
		||||
	bool MkDir(const std::string &dirname);
 | 
			
		||||
	bool RmDir(const std::string &dirname);
 | 
			
		||||
	int  RenameFile(const std::string &from, const std::string &to);
 | 
			
		||||
	bool RemoveFile(const std::string &filename);
 | 
			
		||||
	bool GetHostPath(const std::string &inpath, std::string &outpath);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	struct OpenFileEntry {
 | 
			
		||||
		u8 *fileData;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		size_t seekPos;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	typedef std::map<u32, OpenFileEntry> EntryMap;
 | 
			
		||||
	EntryMap entries;
 | 
			
		||||
	std::string basePath;
 | 
			
		||||
	IHandleAllocator *hAlloc;
 | 
			
		||||
 | 
			
		||||
	std::string GetLocalPath(std::string localpath);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // CORE_FILE_SYS_DIRECTORY_H_
 | 
			
		||||
		Reference in New Issue
	
	Block a user