Skip to content

Commit

Permalink
Update 1.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
basharast committed Apr 29, 2023
1 parent 718833a commit cd3ada1
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 53 deletions.
58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ Open `StorageConfig.h` at the top you will find:
- Pictures: `picturesLibrary`
- Music: `musicLibrary`
**Note:** try to avoid `documentsLibrary`
it will throw exception in case you're trying to reach file is not declared in `appxmanifest` file
## Pick files/folders
Expand Down Expand Up @@ -184,6 +186,19 @@ Get `FILE*` stream for file:
FILE* GetFileStream(std::string path, const char* mode)
```

Get `FILE*` stream for file (DirectAPI):

This function is important to avoid using `fopen`,

preferred to be used before `GetFileStream()`

it will call `CreateFile2FromAppW` with `mode` converted to it's args

```c++
// This call will be similar to fopen
FILE* GetFileStreamFromApp(std::string path, const char* mode)
```
## Restrictions
- You cannot use `FindFirstFile`, `FindNextFile` with folder `HANDLE`
Expand Down Expand Up @@ -243,6 +258,10 @@ bool IsExistsUWP(std::string path);

// Check if target is directory
bool IsDirectoryUWP(std::string path);

// Check if drive is accessible
// 'checkIfContainsFutureAccessItems' for listing purposes not real access, 'driveName' like C:
bool CheckDriveAccess(std::string driveName, bool checkIfContainsFutureAccessItems);
```
Expand Down Expand Up @@ -277,34 +296,41 @@ I was able to make zip function working by doing the following:
- Do the following changes:
```c++
// Include this header
// Include headers
#ifdef MS_UWP
#include "UWP2C.h"
#include <fileapifromapp.h>
#endif
// Replace `zip_win32_file_operations_t ops_utf16` by below
#ifdef MS_UWP
static BOOL GetFileAttr(const void* name, GET_FILEEX_INFO_LEVELS info_level, void* lpFileInformation);
static BOOL __stdcall
GetFileAttr(const void* name, GET_FILEEX_INFO_LEVELS info_level, void* lpFileInformation) {
// Ignore `info_level` it will not be used for now
return GetFileAttributesUWP(name, lpFileInformation);
static BOOL __stdcall GetFileAttr(const void* name, GET_FILEEX_INFO_LEVELS info_level, void* lpFileInformation) {
BOOL state = GetFileAttributesExFromAppW(name, info_level, lpFileInformation);
if (state == FALSE) {
// Ignore `info_level` not in use for now
state = GetFileAttributesUWP(name, lpFileInformation);
}
return state;
}
static BOOL DelFile(const void* name);
static BOOL __stdcall
DelFile(const void* name) {
return DeleteFileUWP(name);
static BOOL __stdcall DelFile(const void* name) {
BOOL state = DeleteFileFromAppW(name);
if (state == FALSE) {
state = DeleteFileUWP(name);
}
return state;
}
// You got the idea so you can add more if you want
zip_win32_file_operations_t ops_utf16 = {
utf16_allocate_tempname,
utf16_create_file, // Will invoke UWP Storage manager (If needed)
DelFile, // Will invoke UWP Storage manager
GetFileAttributesW, // Not implemented
GetFileAttr, // Will invoke UWP Storage manager
DelFile, // Will invoke UWP Storage manager (If needed)
GetFileAttributesW,
GetFileAttr, // Will invoke UWP Storage manager (If needed)
utf16_make_tempname,
MoveFileExW, // Not implemented
MoveFileExW,
SetFileAttributesW,
utf16_strdup
};
Expand All @@ -320,7 +346,7 @@ and make the following changes:

```c++
#ifdef MS_UWP
HANDLE h = CreateFile2((const wchar_t*)name, access, share_mode, creation_disposition, NULL);
HANDLE h = CreateFile2FromAppW((const wchar_t*)name, access, share_mode, creation_disposition, NULL);
if (h == INVALID_HANDLE_VALUE) {
h = CreateFileUWP(name, (int)access, (int)share_mode, (int)creation_disposition);
}
Expand Down Expand Up @@ -354,7 +380,7 @@ and inside it will be new file for each launch at the time `GetLogFile()` called

# Tips

It's prefered to use file APIs first,
It's preferred to use file APIs first,

then forward the request to storage manager if APIs failed

Expand Down
3 changes: 3 additions & 0 deletions UWPHelpers (CX)/StorageExtensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ std::string& trim(std::string& s, const char* t)
bool isWriteMode(const char* mode) {
return (!strcmp(mode, "w") || !strcmp(mode, "wb") || !strcmp(mode, "wt") || !strcmp(mode, "at") || !strcmp(mode, "a"));
}
bool isAppendMode(const char* mode) {
return (!strcmp(mode, "at") || !strcmp(mode, "a"));
}

// Parent and child full path
std::string getSubRoot(std::string parent, std::string child) {
Expand Down
1 change: 1 addition & 0 deletions UWPHelpers (CX)/StorageExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ bool findInList(std::list<T>& inputList, T& str) {
};

bool isWriteMode(const char* mode);
bool isAppendMode(const char* mode);
// Parent and child full path
std::string getSubRoot(std::string parent, std::string child);

4 changes: 3 additions & 1 deletion UWPHelpers (CX)/StorageFolderW.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ class StorageFolderW {
// Do some fixes because 'TryGetItemAsync' is very sensetive
replace(itemName, "\\\\", "\\");
replace(itemName, "//", "/");
replace(itemName, "*", "");
rtrim(itemName, ":"); // remove ':' at the end of the path (if any)

path = PathUWP(itemName);
Expand Down Expand Up @@ -448,10 +449,11 @@ class StorageFolderW {
FILE* file{};

bool createIfNotExists = isWriteMode(mode);

bool isAppend = isAppendMode(mode);
StorageFile^ sfile;

if (createIfNotExists) {
auto createMode = isAppend ? CreationCollisionOption::OpenIfExists : CreationCollisionOption::ReplaceExisting;
ExecuteTask(sfile, storageFolder->CreateFileAsync(convert(name), CreationCollisionOption::OpenIfExists));
}
else {
Expand Down
160 changes: 139 additions & 21 deletions UWPHelpers (CX)/StorageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,15 @@ std::string GetMusicFolder() {
}
std::string GetPreviewPath(std::string path) {
std::string pathView = path;
windowsPath(pathView);
replace(pathView, GetLocalFolder(), "LocalState");
replace(pathView, GetTempFolder(), "TempState");
replace(pathView, GetInstallationFolder(), "Installation folder");
return pathView;
}
bool isLocalState(std::string path) {
return iequals(GetPreviewPath(path), "LocalState");
}
#pragma endregion

#pragma region Internal
Expand All @@ -129,7 +133,7 @@ PathUWP PathResolver(PathUWP path) {
auto newPath = path.ToString();
if (path.IsRoot() || iequals(root, "/") || iequals(root, "\\")) {
// System requesting file from app data
replace(newPath, "/", (GetLocalFolder() + (path.size() > 1 ? "/": "")));
replace(newPath, "/", (GetLocalFolder() + (path.size() > 1 ? "/" : "")));
}
path = PathUWP(newPath);
return path;
Expand All @@ -138,6 +142,10 @@ PathUWP PathResolver(std::string path) {
return PathResolver(PathUWP(path));
}

std::string ResolvePathUWP(std::string path) {
return PathResolver(path).ToString();
}

// Return closer parent
StorageItemW GetStorageItemParent(PathUWP path) {
path = PathResolver(path);
Expand Down Expand Up @@ -270,6 +278,10 @@ bool IsRootForAccessibleItems(PathUWP path, std::list<std::string>& subRoot, boo
bool IsRootForAccessibleItems(std::string path, std::list<std::string>& subRoot, bool breakOnFirstMatch = false) {
return IsRootForAccessibleItems(PathUWP(path), subRoot, breakOnFirstMatch);
}
bool IsRootForAccessibleItems(std::string path) {
std::list<std::string> tmp;
return IsRootForAccessibleItems(path, tmp, true);
}
#pragma endregion

#pragma region Functions
Expand All @@ -286,7 +298,8 @@ bool CreateIfNotExists(int openMode) {
}

HANDLE CreateFileUWP(std::string path, int accessMode, int shareMode, int openMode) {
HANDLE handle{};
HANDLE handle = INVALID_HANDLE_VALUE;

if (IsValidUWP(path)) {
bool createIfNotExists = CreateIfNotExists(openMode);
auto storageItem = GetStorageItem(path, createIfNotExists);
Expand All @@ -311,21 +324,81 @@ HANDLE CreateFileUWP(std::wstring path, int accessMode, int shareMode, int openM
return CreateFileUWP(pathString, accessMode, shareMode, openMode);
}

std::map<std::string, bool> accessState;
bool CheckDriveAccess(std::string driveName, bool checkIfContainsFutureAccessItems) {
bool state = false;

HANDLE searchResults;
WIN32_FIND_DATA findDataResult;
auto keyIter = accessState.find(driveName);
if (keyIter != accessState.end()) {
state = keyIter->second;
}
else {
try {
wchar_t* filteredPath = _wcsdup(convert(driveName)->Data());
wcscat_s(filteredPath, sizeof(L"\\*.*"), L"\\*.*");
#if !defined(_M_ARM)
searchResults = FindFirstFileExFromAppW(
filteredPath, FindExInfoBasic, &findDataResult,
FindExSearchNameMatch, NULL, 0);
#else
searchResults = FindFirstFileEx(
filteredPath, FindExInfoBasic, &findDataResult,
FindExSearchNameMatch, NULL, 0);
#endif
state = searchResults != NULL && searchResults != INVALID_HANDLE_VALUE;
if (state) {
FindClose(searchResults);
}
accessState.insert(std::make_pair(driveName, state));
}
catch (...) {
}
}

if (!state && checkIfContainsFutureAccessItems) {
// Consider the drive accessible in case it contain files/folder selected before to avoid empty results
state = IsRootForAccessibleItems(driveName) || IsContainsAccessibleItems(driveName);
}
return state;
}
bool IsValidUWP(std::string path) {
auto p = PathResolver(path);

//Check valid path
if (p.Type() == PathTypeUWP::UNDEFINED || !p.IsAbsolute()){
if (p.Type() == PathTypeUWP::UNDEFINED || !p.IsAbsolute()) {
// Nothing to do here
UWP_VERBOSE_LOG(UWPSMT, "File is not valid (%s)", p.ToString().c_str());
VERBOSE_LOG(FILESYS, "File is not valid (%s)", p.ToString().c_str());
return false;
}

return true;
}

bool IsValidUWP(std::wstring path){
return IsValidUWP(convert(path));

bool state = false;

auto resolvedPathStr = p.ToString();
if (ends_with(resolvedPathStr, "LocalState") || ends_with(resolvedPathStr, "TempState") || ends_with(resolvedPathStr, "LocalCache")) {
state = true;
}
else
if (isChild(GetLocalFolder(), resolvedPathStr)) {
state = true;
}
else if (isChild(GetInstallationFolder(), resolvedPathStr)) {
state = true;
}
else if (isChild(GetTempFolder(), resolvedPathStr)) {
state = true;
}

if (!state)
{
auto p = PathUWP(path);
std::string driveName = p.GetRootVolume().ToString();
state = CheckDriveAccess(driveName, false);
}

return !state;
}

bool IsExistsUWP(std::string path) {
Expand Down Expand Up @@ -404,6 +477,39 @@ FILE* GetFileStream(std::wstring path, const char* mode) {
return GetFileStream(convert(path), mode);
}

FILE* GetFileStreamFromApp(std::string path, const char* mode) {

FILE* file{};

auto pathResolved = PathUWP(ResolvePathUWP(path));
HANDLE handle;
auto access = GENERIC_READ;
auto share = FILE_SHARE_READ;
auto creation = OPEN_EXISTING;
bool isWrite = isWriteMode(mode);
bool isAppend = isAppendMode(mode);

if (isWrite) {
access = GENERIC_WRITE;
share = FILE_SHARE_WRITE;
creation = isAppend ? OPEN_ALWAYS : CREATE_ALWAYS;
}
#if !defined(_M_ARM)
handle = CreateFile2FromAppW(pathResolved.ToWString().c_str(), access, share, creation, nullptr);
#else
handle = CreateFile2(pathResolved.ToWString().c_str(), access, share, creation, nullptr);
#endif
if (handle != INVALID_HANDLE_VALUE) {
int flags = _O_RDONLY;
if (isWrite) {
flags = _O_RDWR;
}
file = _fdopen(_open_osfhandle((intptr_t)handle, flags), mode);
}

return file;
}

#pragma region Content Helpers
ItemInfoUWP GetFakeFolderInfo(std::string folder) {
ItemInfoUWP info;
Expand Down Expand Up @@ -450,7 +556,7 @@ std::list<ItemInfoUWP> GetFolderContents(std::string path, bool deepScan) {
else {
UWP_ERROR_LOG(UWPSMT, "Cannot get contents!, checking for other options.. (%s)", path.c_str());
}
; }
}

if (contents.size() == 0) {
// Folder maybe not accessible or not exists
Expand Down Expand Up @@ -496,14 +602,17 @@ std::list<ItemInfoUWP> GetFolderContents(std::wstring path, bool deepScan) {

ItemInfoUWP GetItemInfoUWP(std::string path) {
ItemInfoUWP info;
auto storageItem = GetStorageItem(path);
if (storageItem.IsValid()) {
info = storageItem.GetItemInfo();
}
else {
info.size = -1;
info.attributes = INVALID_FILE_ATTRIBUTES;
UWP_ERROR_LOG(UWPSMT, "Couldn't find or access (%s)", path.c_str());
info.size = -1;
info.attributes = INVALID_FILE_ATTRIBUTES;

if (IsValidUWP(path)) {
auto storageItem = GetStorageItem(path);
if (storageItem.IsValid()) {
info = storageItem.GetItemInfo();
}
else {
ERROR_LOG(FILESYS, "Couldn't find or access (%s)", path.c_str());
}
}

return info;
Expand Down Expand Up @@ -676,10 +785,19 @@ bool RenameUWP(std::wstring path, std::wstring name) {

#pragma region Helpers
bool OpenFile(std::string path) {
auto uri = ref new Windows::Foundation::Uri(convert(path));
bool state = false;

bool state;
ExecuteTask(state, Windows::System::Launcher::LaunchUriAsync(uri), false);
auto storageItem = GetStorageItem(path);
if (storageItem.IsValid()) {
if (!storageItem.IsDirectory()) {
ExecuteTask(state, Windows::System::Launcher::LaunchFileAsync(storageItem.GetStorageFile()), false);
}
}
else {
auto uri = ref new Windows::Foundation::Uri(convert(path));

ExecuteTask(state, Windows::System::Launcher::LaunchUriAsync(uri), false);
}
return state;
}

Expand Down
Loading

0 comments on commit cd3ada1

Please sign in to comment.