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/UWP/UWPHelpers/StorageManager.cpp
Views: 1401
// Copyright (c) 2023- 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 "pch.h"18#include <io.h>19#include <fcntl.h>20#include <collection.h>2122#include "Common/Log.h"23#include "Core/Config.h"24#include "Common/File/Path.h"25#include "Common/StringUtils.h"26#include "UWPUtil.h"2728#include "StorageManager.h"29#include "StorageAsync.h"30#include "StorageAccess.h"313233using namespace Platform;34using namespace Windows::Storage;35using namespace Windows::Foundation;36using namespace Windows::ApplicationModel;373839#pragma region Locations40std::string GetPSPFolder() {41if (g_Config.memStickDirectory.empty()) {42return g_Config.internalDataDirectory.ToString();43}44else {45return g_Config.memStickDirectory.ToString();46}47}48std::string GetInstallationFolder() {49return FromPlatformString(Package::Current->InstalledLocation->Path);50}51StorageFolder^ GetLocalStorageFolder() {52return ApplicationData::Current->LocalFolder;53}54std::string GetLocalFolder() {55return FromPlatformString(GetLocalStorageFolder()->Path);56}57std::string GetTempFolder() {58return FromPlatformString(ApplicationData::Current->TemporaryFolder->Path);59}60std::string GetTempFile(std::string name) {61StorageFile^ tmpFile;62ExecuteTask(tmpFile, ApplicationData::Current->TemporaryFolder->CreateFileAsync(ToPlatformString(name), CreationCollisionOption::GenerateUniqueName));63if (tmpFile != nullptr) {64return FromPlatformString(tmpFile->Path);65}66else {67return "";68}69}70std::string GetPicturesFolder() {71// Requires 'picturesLibrary' capability72return FromPlatformString(KnownFolders::PicturesLibrary->Path);73}74std::string GetVideosFolder() {75// Requires 'videosLibrary' capability76return FromPlatformString(KnownFolders::VideosLibrary->Path);77}78std::string GetDocumentsFolder() {79// Requires 'documentsLibrary' capability80return FromPlatformString(KnownFolders::DocumentsLibrary->Path);81}82std::string GetMusicFolder() {83// Requires 'musicLibrary' capability84return FromPlatformString(KnownFolders::MusicLibrary->Path);85}86std::string GetPreviewPath(std::string path) {87std::string pathView = path;88pathView = ReplaceAll(pathView, "/", "\\");89std::string currentMemoryStick = GetPSPFolder();90// Ensure memStick sub path replaced by 'ms:'91pathView = ReplaceAll(pathView, currentMemoryStick + "\\", "ms:\\");92auto appData = ReplaceAll(GetLocalFolder(), "\\LocalState", "");93pathView = ReplaceAll(pathView, appData, "AppData");9495return pathView;96}97bool isLocalState(std::string path) {98return !_stricmp(GetPreviewPath(path).c_str(), "LocalState");99}100#pragma endregion101102#pragma region Internal103Path PathResolver(Path path) {104auto root = path.GetDirectory();105auto newPath = path.ToString();106if (path.IsRoot() || !_stricmp(root.c_str(), "/") || !_stricmp(root.c_str(), "\\")) {107// System requesting file from app data108newPath = ReplaceAll(newPath, "/", (GetLocalFolder() + (path.size() > 1 ? "/" : "")));109}110return Path(newPath);111}112Path PathResolver(std::string path) {113return PathResolver(Path(path));114}115116std::string ResolvePathUWP(std::string path) {117return PathResolver(path).ToString();118}119#pragma endregion120121#pragma region Functions122std::map<std::string, bool> accessState;123bool CheckDriveAccess(std::string driveName) {124bool state = false;125126HANDLE searchResults;127WIN32_FIND_DATA findDataResult;128auto keyIter = accessState.find(driveName);129if (keyIter != accessState.end()) {130state = keyIter->second;131}132else {133try {134wchar_t* filteredPath = _wcsdup(ConvertUTF8ToWString(driveName).c_str());135wcscat_s(filteredPath, sizeof(L"\\*.*"), L"\\*.*");136137searchResults = FindFirstFileExFromAppW(138filteredPath, FindExInfoBasic, &findDataResult,139FindExSearchNameMatch, NULL, 0);140141state = searchResults != NULL && searchResults != INVALID_HANDLE_VALUE;142if (state) {143FindClose(searchResults);144}145// Cache the state146accessState.insert(std::make_pair(driveName, state));147}148catch (...) {149}150}151if (!state) {152state = IsRootForAccessibleItems(driveName);153}154return state;155}156157FILE* GetFileStreamFromApp(std::string path, const char* mode) {158159FILE* file{};160161auto pathResolved = Path(ResolvePathUWP(path));162HANDLE handle;163164DWORD dwDesiredAccess = GENERIC_READ;165DWORD dwShareMode = FILE_SHARE_READ;166DWORD dwCreationDisposition = OPEN_EXISTING;167int flags = 0;168169if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt"))170{171dwDesiredAccess = GENERIC_READ;172dwShareMode = FILE_SHARE_READ;173dwCreationDisposition = OPEN_EXISTING;174flags = _O_RDONLY;175}176else if (!strcmp(mode, "r+") || !strcmp(mode, "rb+") || !strcmp(mode, "r+b") || !strcmp(mode, "rt+") || !strcmp(mode, "r+t"))177{178dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;179dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;180dwCreationDisposition = OPEN_EXISTING;181flags = _O_RDWR;182}183else if (!strcmp(mode, "a") || !strcmp(mode, "ab") || !strcmp(mode, "at")) {184dwDesiredAccess = GENERIC_WRITE;185dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;186dwCreationDisposition = OPEN_ALWAYS;187flags = _O_APPEND | _O_WRONLY | _O_CREAT;188}189else if (!strcmp(mode, "a+") || !strcmp(mode, "ab+") || !strcmp(mode, "a+b") || !strcmp(mode, "at+") || !strcmp(mode, "a+t")) {190dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;191dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;192dwCreationDisposition = OPEN_ALWAYS;193flags = _O_APPEND | _O_RDWR | _O_CREAT;194}195else if (!strcmp(mode, "w") || !strcmp(mode, "wb") || !strcmp(mode, "wt"))196{197dwDesiredAccess = GENERIC_WRITE;198dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;199dwCreationDisposition = CREATE_ALWAYS;200flags = _O_WRONLY | _O_CREAT | _O_TRUNC;201}202else if (!strcmp(mode, "w+") || !strcmp(mode, "wb+") || !strcmp(mode, "w+b") || !strcmp(mode, "wt+") || !strcmp(mode, "w+t"))203{204dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;205dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;206dwCreationDisposition = CREATE_ALWAYS;207flags = _O_RDWR | _O_CREAT | _O_TRUNC;208}209210if (strpbrk(mode, "t") != nullptr) {211flags |= _O_TEXT;212}213214handle = CreateFile2FromAppW(pathResolved.ToWString().c_str(), dwDesiredAccess, dwShareMode, dwCreationDisposition, nullptr);215216if (handle != INVALID_HANDLE_VALUE) {217file = _fdopen(_open_osfhandle((intptr_t)handle, flags), mode);218}219220return file;221}222223#pragma endregion224225#pragma region FakeFolders226// Parent and child full path227std::string getSubRoot(std::string parent, std::string child) {228auto childCut = child;229childCut = ReplaceAll(childCut, (parent + "/"), "");230size_t len = childCut.find_first_of('/', 0);231auto subRoot = childCut.substr(0, len);232233return parent + "/" + subRoot;234}235236bool isChild(std::string parent, std::string child) {237return child.find(parent) != std::string::npos;238}239240// Parent full path, child full path, child name only241bool isParent(std::string parent, std::string child, std::string childName) {242parent.append("/" + childName);243return parent == child;244}245246bool IsRootForAccessibleItems(Path path, std::list<std::string>& subRoot, bool breakOnFirstMatch = false) {247path = PathResolver(path);248auto FutureAccessItems = GetFutureAccessList();249for (auto& fItem : FutureAccessItems) {250if (isChild(path.ToString(), fItem)) {251if (breakOnFirstMatch) {252// Just checking, we don't need to loop for each item253return true;254}255auto sub = getSubRoot(path.ToString(), fItem);256257// This check can be better, but that's how I can do it in C++258if (!endsWith(sub, ":")) {259bool alreadyAdded = false;260for each (auto sItem in subRoot) {261if (!strcmp(sItem.c_str(), sub.c_str())) {262alreadyAdded = true;263break;264}265}266if (!alreadyAdded) {267subRoot.push_back(sub);268}269}270}271}272return !subRoot.empty();273}274bool IsRootForAccessibleItems(std::string path)275{276std::list<std::string> tmp;277return IsRootForAccessibleItems(Path(path), tmp, true);278}279280bool GetFakeFolders(Path path, std::vector<File::FileInfo>* files, const char* filter, std::set<std::string> filters) {281bool state = false;282std::list<std::string> subRoot;283if (IsRootForAccessibleItems(path, subRoot)) {284if (!subRoot.empty()) {285for each (auto sItem in subRoot) {286auto folderPath = Path(sItem);287File::FileInfo info;288info.name = folderPath.GetFilename();289info.fullName = folderPath;290info.exists = true;291info.size = 1;292info.isDirectory = true;293info.isWritable = true;294info.atime = 0;295info.mtime = 0;296info.ctime = 0;297info.access = 0111;298299files->push_back(info);300state = true;301}302}303}304return state;305}306307#pragma endregion308309#pragma region Helpers310bool OpenFile(std::string path) {311bool state = false;312Platform::String^ wString = ref new Platform::String(Path(path).ToWString().c_str());313314StorageFile^ storageItem;315ExecuteTask(storageItem, StorageFile::GetFileFromPathAsync(wString));316if (storageItem != nullptr) {317ExecuteTask(state, Windows::System::Launcher::LaunchFileAsync(storageItem), false);318}319else {320auto uri = ref new Windows::Foundation::Uri(wString);321ExecuteTask(state, Windows::System::Launcher::LaunchUriAsync(uri), false);322}323return state;324}325326bool OpenFolder(std::string path) {327bool state = false;328Path itemPath(path);329Platform::String^ wString = ref new Platform::String(itemPath.ToWString().c_str());330StorageFolder^ storageItem;331ExecuteTask(storageItem, StorageFolder::GetFolderFromPathAsync(wString));332if (storageItem != nullptr) {333ExecuteTask(state, Windows::System::Launcher::LaunchFolderAsync(storageItem), false);334}335else {336// Try as it's file337Path parent = Path(itemPath.GetDirectory());338Platform::String^ wParentString = ref new Platform::String(parent.ToWString().c_str());339340ExecuteTask(storageItem, StorageFolder::GetFolderFromPathAsync(wParentString));341if (storageItem != nullptr) {342ExecuteTask(state, Windows::System::Launcher::LaunchFolderAsync(storageItem), false);343}344}345return state;346}347348bool GetDriveFreeSpace(Path path, int64_t& space) {349350bool state = false;351if (path.empty()) {352// This case happen on first start only353path = Path(GetPSPFolder());354if (g_Config.memStickDirectory.empty()) {355g_Config.memStickDirectory = path;356}357}358Platform::String^ wString = ref new Platform::String(path.ToWString().c_str());359StorageFolder^ storageItem;360ExecuteTask(storageItem, StorageFolder::GetFolderFromPathAsync(wString));361if (storageItem != nullptr) {362Platform::String^ freeSpaceKey = ref new Platform::String(L"System.FreeSpace");363Platform::Collections::Vector<Platform::String^>^ propertiesToRetrieve = ref new Platform::Collections::Vector<Platform::String^>();364propertiesToRetrieve->Append(freeSpaceKey);365Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ result;366ExecuteTask(result, storageItem->Properties->RetrievePropertiesAsync(propertiesToRetrieve));367if (result != nullptr && result->Size > 0) {368try {369auto value = result->Lookup(L"System.FreeSpace");370space = (uint64_t)value;371state = true;372}373catch (...) {374375}376}377}378379return state;380}381#pragma endregion382383#pragma region Logs384std::string GetLogFile() {385std::string logFile;386Path logFilePath = Path(GetPSPFolder() + "\\PSP\\ppsspplog.txt");387HANDLE h = CreateFile2FromAppW(logFilePath.ToWString().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);388if (h != INVALID_HANDLE_VALUE) {389logFile = logFilePath.ToString();390CloseHandle(h);391}392return logFile;393}394395#pragma endregion396397398