diff --git a/Include/Aurora/Processes/Open.hpp b/Include/Aurora/Processes/Open.hpp index b777851c..7b178121 100644 --- a/Include/Aurora/Processes/Open.hpp +++ b/Include/Aurora/Processes/Open.hpp @@ -13,13 +13,20 @@ namespace Aurora::Processes * @brief Opens a standard uri formatted string (eg, protocol://endpoint/path) * @param uri * @return - */ + */ AUKN_SYM void OpenUri(const AuROString &uri); /** * @brief Opens a file or directory - * @param file unexpanded relative or absolute filepath - * @return - */ + * @param file: unexpanded relative or absolute filepath + * @return + */ AUKN_SYM void OpenFile(const AuROString &file); + + /** + * @brief Reveals a file or directory in the platform shell + * @param file: unexpanded relative or absolute filepath + * @return + */ + AUKN_SYM void RevealInDirectory(const AuROString &file); } \ No newline at end of file diff --git a/Source/AuProcAddresses.NT.cpp b/Source/AuProcAddresses.NT.cpp index e41d09a4..d010f5a5 100644 --- a/Source/AuProcAddresses.NT.cpp +++ b/Source/AuProcAddresses.NT.cpp @@ -428,6 +428,9 @@ namespace Aurora ADD_GET_PROC(Shell, SHGetFolderPathA) ADD_GET_PROC(Shell, CommandLineToArgvW) ADD_GET_PROC(Shell, ShellExecuteW) + ADD_GET_PROC(Shell, ILCreateFromPathW) + ADD_GET_PROC(Shell, ILFree) + ADD_GET_PROC(Shell, SHOpenFolderAndSelectItems) ADD_GET_PROC(User32, GetClipboardData); ADD_GET_PROC(User32, MapVirtualKeyA); diff --git a/Source/AuProcAddresses.NT.hpp b/Source/AuProcAddresses.NT.hpp index c9f29342..1346d80e 100644 --- a/Source/AuProcAddresses.NT.hpp +++ b/Source/AuProcAddresses.NT.hpp @@ -768,6 +768,21 @@ namespace Aurora LPSTR pszPath ); + inline void *(__stdcall *pILCreateFromPathW)( + LPCWSTR lpPath + ); + + inline HRESULT (__stdcall *pSHOpenFolderAndSelectItems)( + void * pidlFolder, + UINT cidl, + void * apidl, + DWORD dwFlags + ); + + inline void (__stdcall *pILFree)( + void * pidl + ); + inline LPWSTR *(__stdcall *pCommandLineToArgvW)( LPCWSTR lpCmdLine, int * pNumArgs diff --git a/Source/Processes/AuOpen.Unix.cpp b/Source/Processes/AuOpen.Unix.cpp index 375e9c96..97860fbd 100644 --- a/Source/Processes/AuOpen.Unix.cpp +++ b/Source/Processes/AuOpen.Unix.cpp @@ -14,14 +14,14 @@ namespace Aurora::Processes { - static void UnixOpenAsyncThread(AuString uri, bool bType) + static void UnixOpenAsyncThread(AuString uri, int iType) { bool bDirExists {}; bool bFileExists {}; bFileExists = AuIOFS::FileExists(uri); - if (!bType) + if (iType) { bDirExists = AuIOFS::DirExists(uri); @@ -56,70 +56,170 @@ namespace Aurora::Processes } else { - if (fork() == 0) + static AuInitOnce gInitOnce; + static bool gUseDShid {}; + + gInitOnce.Call([]() + { + auto optStringA = AuProcess::EnvironmentGetOne("container"); + auto optStringB = AuProcess::EnvironmentGetOne("AURORA_RUNTIME_USE_GDBUS_BIN_TO_PORTAL"); + auto optStringC = AuProcess::EnvironmentGetOne("AURORA_RUNTIME_NO_MICROSOFT_REDHAT_SABOTAGE"); + + bool bIsFireJail = optStringA && optStringA.Value() == "firejail"; + bool bIsForcedDBUS = optStringB && optStringB.Value() == "YES"; + bool bAllowDbus = !optStringC && (AuFS::FileExists("/usr/bin/gdbus") || AuFS::FileExists("/bin/gdbus")); + + if (bIsFireJail || bIsForcedDBUS || bAllowDbus) + { + gUseDShid = true; + } + else + { + gUseDShid = false; + } + }); + + if (!gUseDShid) + { + if (iType == 2) + { + AuROString out; + if (AuEndsWith(uri, '/')) + { + AuFS::GoUpToSeparator(out, uri); + AuFS::GoUpToSeparator(out, out); + } + else + { + AuFS::GoUpToSeparator(out, uri); + } + uri = AuString(out); + } + } + + AuSemaphore semaphore; + volatile int type2 = iType; + + auto iFork = fork(); + if (iFork == 0) { setsid(); + // isn't posix fun? PosixDoForkHooks(); PosixShutup(); PosixFDYeetus(); - auto optStringA = AuProcess::EnvironmentGetOne("container"); - auto optStringB = AuProcess::EnvironmentGetOne("AURORA_RUNTIME_USE_GDBUS_BIN_TO_PORTAL"); - bool bIsFireJail = optStringA && optStringA.Value() == "firejail"; - bool bIsForcedDBUS = optStringB && optStringB.Value() == "YES"; - if (bIsFireJail || bIsForcedDBUS) + auto pBaseURI = (char *)SysAllocateLarge(uri.size() + 1); + if (pBaseURI) { + AuMemcpy(pBaseURI, uri.c_str(), uri.size() + 1); + } + + int iType = type2; + + // ...super fun + semaphore->Unlock(1); + // ...the original iType and uri buffer will be trashed from this point onwards + + // and as if dealing with posix isn't bad enough... + // here's some more redhat/lennart poettering/dbus/xdg bullshid + if (gUseDShid) + { + const char *pExecString {}; + bool bFuckRedHat { true }; + char incompetentRedCunts[32]; + + if (iType == 2) + { + pExecString = "org.freedesktop.portal.OpenURI.OpenDirectory"; + } + else if (bFileExists || bDirExists) + { + pExecString = "org.freedesktop.portal.OpenURI.OpenFile"; + } + else + { + pExecString = "org.freedesktop.portal.OpenURI.OpenURI"; + bFuckRedHat = false; + } + + // it only gets worse, doesn't it? + if (bFuckRedHat) + { + int fu = PosixOpen(pBaseURI, + O_RDONLY, + 0664); // dont care. use a real os that isnt controlled by redhat + snprintf(incompetentRedCunts, 32, "%i", fu); + pBaseURI = incompetentRedCunts; + } + + // and now we pray to the demons of dshid execlp("gdbus", "gdbus", "call", "--session", "--dest", "org.freedesktop.portal.Desktop", "--object-path", "/org/freedesktop/portal/desktop", - "--method", bFileExists ? "org.freedesktop.portal.OpenURI.OpenFile" : "org.freedesktop.portal.OpenURI.OpenURI", + "--method", pExecString, "", - uri.c_str(), + pBaseURI, "{}", (char *)nullptr); } else { - if (AuFS::FileExists("/usr/bin/xdg-open")) + // how did we go from this to the above redhat bs? + // freetards have no standards whatsoever - in both a literal and figurative sense + if (AuFS::FileExists("/bin/xdg-open")) { - execl("/usr/bin/xdg-open", "xdg-open", uri.c_str(), (char *)nullptr); + execl("/bin/xdg-open", "xdg-open", pBaseURI, (char *)nullptr); + } + else if (AuFS::FileExists("/usr/bin/xdg-open")) + { + execl("/usr/bin/xdg-open", "xdg-open", pBaseURI, (char *)nullptr); } else if (AuFS::FileExists("/usr/local/bin/xdg-open")) { - execl("/usr/local/bin/xdg-open", "xdg-open", uri.c_str(), (char *)nullptr); + execl("/usr/local/bin/xdg-open", "xdg-open", pBaseURI, (char *)nullptr); } else { - execlp("xdg-open", "xdg-open", uri.c_str(), (char *)nullptr); + execlp("xdg-open", "xdg-open", pBaseURI, (char *)nullptr); } } exit(0); } + else if (iFork > 0) + { + semaphore->Lock(); + } } } - static void UnixOpenAsync(const AuROString &uri, bool bType) + static void UnixOpenAsync(const AuROString &uri, int iType) { if (uri.empty()) { return; } - AuThreads::Spawn(std::bind(&UnixOpenAsyncThread, AuString(uri), bType), true); + AuThreads::Spawn(std::bind(&UnixOpenAsyncThread, AuString(uri), iType), true); } AUKN_SYM void OpenUri(const AuROString &uri) { - UnixOpenAsync(uri, true); + UnixOpenAsync(uri, 0); } AUKN_SYM void OpenFile(const AuROString &file) { - UnixOpenAsync(file, false); + UnixOpenAsync(file, 1); + } + + AUKN_SYM void RevealInDirectory(const AuROString &file) + { + UnixOpenAsync(file, 2); } } \ No newline at end of file diff --git a/Source/Processes/AuOpen.Win32.cpp b/Source/Processes/AuOpen.Win32.cpp index a6024d8d..a0a52419 100644 --- a/Source/Processes/AuOpen.Win32.cpp +++ b/Source/Processes/AuOpen.Win32.cpp @@ -15,7 +15,7 @@ namespace Aurora::Processes { - static AuList> gOpenItems; + static AuList> gOpenItems; static AuConditionMutex gCondMutex; static AuConditionVariable gCondVariable(AuUnsafeRaiiToShared(gCondMutex.AsPointer())); static AuThreads::ThreadUnique_t gOpenerThread; @@ -24,7 +24,7 @@ namespace Aurora::Processes { AU_LOCK_GUARD(gCondMutex); - while (AuIsThreadRunning()) + while (AuIsThreadRunning() || gOpenItems.size()) { try { @@ -48,7 +48,7 @@ namespace Aurora::Processes bFileExists = AuIOFS::FileExists(uri); - if (!type) + if (type) { bDirExists = AuIOFS::DirExists(uri); @@ -79,18 +79,34 @@ namespace Aurora::Processes auto u16OpenURI = Locale::ConvertFromUTF8(uri); auto pOpenType = bDirExists ? L"explore" : L"open"; + bool bReveal = type == 2 && + pILCreateFromPathW && + pSHOpenFolderAndSelectItems && + pILFree; gCondMutex->Unlock(); - pShellExecuteW(nullptr, - pOpenType, - u16OpenURI.c_str(), - nullptr, - nullptr, - SW_SHOWNORMAL); + if (bReveal) + { + if (auto pIL = pILCreateFromPathW(u16OpenURI.c_str())) + { + pSHOpenFolderAndSelectItems(pIL, 0, nullptr, 0); + pILFree(pIL); + } + } + else + { + pShellExecuteW(nullptr, + pOpenType, + u16OpenURI.c_str(), + nullptr, + nullptr, + SW_SHOWNORMAL); + } gCondMutex->Lock(); - // Move all N-1 elements for each N, vs clearing later (requires lock?), vs making a copy of the work (requires another alloc?). - // We can just do ShellExecuteW outside of the lock, and access a locally owned U16-translated string container, without bothering the write side mutex or mutable work container. + // Work mostly in-place and move all N-1 elements for each N, vs do all in place and clear all later (requires uninterrupted mutex lock?), vs making a copy of the work queue (requires another alloc unless AuExchanged in-place, + needs another nested indentation for a for itr loop). + // The former is pretty much the same as the latter with an AuExchange, except we use .erase(itr) moves to single step through the queue instead of batching & erasing all at once. + // We can just do ShellExecuteW outside of the lock and access a locally owned U16-translated string container, without bothering the write side mutex or mutable work container. // A work queue buffer could solve this, but eh. gOpenItems.erase(gOpenItems.begin()); } @@ -145,7 +161,7 @@ namespace Aurora::Processes AUKN_SYM void OpenUri(const AuROString &uri) { AU_LOCK_GLOBAL_GUARD(gCondMutex); - AuTryInsert(gOpenItems, AuMakePair(AuString(uri), true)); + AuTryInsert(gOpenItems, AuMakePair(AuString(uri), 0)); gCondVariable->Signal(); } @@ -161,7 +177,24 @@ namespace Aurora::Processes { AU_LOCK_GLOBAL_GUARD(gCondMutex); - AuTryInsert(gOpenItems, AuMove(AuMakePair(AuMove(path), false))); + AuTryInsert(gOpenItems, AuMove(AuMakePair(AuMove(path), 1))); + gCondVariable->Signal(); + } + } + + AUKN_SYM void RevealInDirectory(const AuROString &file) + { + auto path = AuIOFS::NormalizePathRet(file); + + if (path.empty()) + { + SysPushErrorMemory(); + return; + } + + { + AU_LOCK_GLOBAL_GUARD(gCondMutex); + AuTryInsert(gOpenItems, AuMove(AuMakePair(AuMove(path), 2))); gCondVariable->Signal(); } }