summaryrefslogtreecommitdiff
path: root/zen/recycler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/recycler.cpp')
-rw-r--r--zen/recycler.cpp104
1 files changed, 65 insertions, 39 deletions
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index 7f9e0a01..d8ee58c4 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -29,9 +29,8 @@ using namespace zen;
#ifdef ZEN_WIN
-void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::function<void (const std::wstring& displayPath)>& onRecycleItem)
+void zen::recycleOrDeleteIfExists(const std::vector<Zstring>& itemPaths, const std::function<void (const std::wstring& displayPath)>& onRecycleItem)
{
- if (itempaths.empty()) return;
//warning: moving long file paths to recycler does not work!
//both ::SHFileOperation() and ::IFileOperation cannot delete a folder named "System Volume Information" with normal attributes but shamelessly report success
//both ::SHFileOperation() and ::IFileOperation can't handle \\?\-prefix!
@@ -48,21 +47,25 @@ void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::func
Nevertheless, let's use IFileOperation for better error reporting (including details on locked files)!
*/
-#ifdef ZEN_WIN_VISTA_AND_LATER
- vista::moveToRecycleBin(itempaths, onRecycleItem); //throw FileError
+
+#ifdef ZEN_WIN_VISTA_AND_LATER //Win Vista recycle bin usage: 1. good error reporting 2. late failure
+ vista::moveToRecycleBinIfExists(itemPaths, onRecycleItem); //throw FileError
#else //regular recycle bin usage: available since XP: 1. bad error reporting 2. early failure
- Zstring itempathsDoubleNull;
- for (const Zstring& itempath : itempaths)
+ //TODO: this XP version fails if any item is not existing violating this function's API
+ if (itemPaths.empty()) return;
+
+ Zstring itemPathsDoubleNull;
+ for (const Zstring& itemPath : itemPaths)
{
- itempathsDoubleNull += itempath;
- itempathsDoubleNull += L'\0';
+ itemPathsDoubleNull += itemPath;
+ itemPathsDoubleNull += L'\0';
}
SHFILEOPSTRUCT fileOp = {};
fileOp.hwnd = nullptr;
fileOp.wFunc = FO_DELETE;
- fileOp.pFrom = itempathsDoubleNull.c_str();
+ fileOp.pFrom = itemPathsDoubleNull.c_str();
fileOp.pTo = nullptr;
fileOp.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
fileOp.fAnyOperationsAborted = false;
@@ -70,10 +73,10 @@ void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::func
fileOp.lpszProgressTitle = nullptr;
//"You should use fully-qualified path names with this function. Using it with relative path names is not thread safe."
- if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
+ if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) //fails if items are not existing!
{
- std::wstring itempathFmt = fmtPath(itempaths[0]); //probably not the correct file name for file lists larger than 1!
- if (itempaths.size() > 1)
+ std::wstring itempathFmt = fmtPath(itemPaths[0]); //probably not the correct file name for file lists larger than 1!
+ if (itemPaths.size() > 1)
itempathFmt += L", ..."; //give at least some hint that there are multiple files, and the error need not be related to the first one
throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", itempathFmt));
}
@@ -82,16 +85,37 @@ void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::func
#endif
-bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
+bool zen::recycleOrDeleteIfExists(const Zstring& itemPath) //throw FileError
{
- if (!somethingExists(itempath)) //[!] do not optimize away, OS X needs this for reliable detection of "recycle bin missing"
- return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it!
-
#ifdef ZEN_WIN
- recycleOrDelete({ itempath }, nullptr); //throw FileError
+#ifdef ZEN_WIN_VISTA_AND_LATER
+ return vista::moveToRecycleBinIfExists({ itemPath }, nullptr) != 0; //throw FileError
+
+#else
+ Zstring itemPathDoubleNull = itemPath;
+ itemPathDoubleNull += L'\0';
+
+ SHFILEOPSTRUCT fileOp = {};
+ fileOp.wFunc = FO_DELETE;
+ fileOp.pFrom = itemPathDoubleNull.c_str();
+ fileOp.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
+
+ if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) //fails if item is not existing!
+ {
+ try
+ {
+ if (!getItemTypeIfExists(itemPath)) //throw FileError
+ return false;
+ }
+ catch (FileError&) {} //previous exception is more relevant
+
+ throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(itemPath)));
+ }
+ return true;
+#endif
#elif defined ZEN_LINUX
- GFile* file = ::g_file_new_for_path(itempath.c_str()); //never fails according to docu
+ GFile* file = ::g_file_new_for_path(itemPath.c_str()); //never fails according to docu
ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
GError* error = nullptr;
@@ -99,38 +123,38 @@ bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
if (!::g_file_trash(file, nullptr, &error))
{
- const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(itempath));
+ const Opt<ItemType> type = getItemTypeIfExists(itemPath); //throw FileError
+ if (!type)
+ return false;
+ const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(itemPath));
if (!error)
throw FileError(errorMsg, L"g_file_trash: unknown error."); //user should never see this
//implement same behavior as in Windows: if recycler is not existing, delete permanently
if (error->code == G_IO_ERROR_NOT_SUPPORTED)
{
- struct ::stat fileInfo = {};
- if (::lstat(itempath.c_str(), &fileInfo) != 0)
- return false;
-
- if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode))
- removeFile(itempath); //throw FileError
- else if (S_ISDIR(fileInfo.st_mode))
- removeDirectoryRecursively(itempath); //throw FileError
+ if (*type == ItemType::FOLDER)
+ removeDirectoryPlainRecursion(itemPath); //throw FileError
+ else
+ removeFilePlain(itemPath); //throw FileError
return true;
}
throw FileError(errorMsg, replaceCpy<std::wstring>(L"Glib Error Code %x:", L"%x", numberTo<std::wstring>(error->code)) + L" " + utfCvrtTo<std::wstring>(error->message));
//g_quark_to_string(error->domain)
}
+ return true;
#elif defined ZEN_MAC
//we cannot use FSPathMoveObjectToTrashSync directly since it follows symlinks!
static_assert(sizeof(Zchar) == sizeof(char), "");
- const UInt8* itempathUtf8 = reinterpret_cast<const UInt8*>(itempath.c_str());
+ const UInt8* itemPathUtf8 = reinterpret_cast<const UInt8*>(itemPath.c_str());
auto throwFileError = [&](OSStatus oss)
{
- const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(itempath));
+ const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(itemPath));
std::wstring errorDescr = L"OSStatus Code " + numberTo<std::wstring>(oss);
if (const char* description = ::GetMacOSStatusCommentString(oss)) //found no documentation for proper use of GetMacOSStatusCommentString
@@ -138,8 +162,14 @@ bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
throw FileError(errorMsg, errorDescr);
};
+ //[!] do not optimize away, OS X needs this for reliable detection of "recycle bin unsupported"
+ //both "not supported" and "item missing" let FSMoveObjectToTrashSync fail with -120
+ const Opt<ItemType> type = getItemTypeIfExists(itemPath); //throw FileError
+ if (!type)
+ return false;
+
FSRef objectRef = {}; //= POD structure not a pointer type!
- OSStatus rv = ::FSPathMakeRefWithOptions(itempathUtf8, //const UInt8 *path,
+ OSStatus rv = ::FSPathMakeRefWithOptions(itemPathUtf8, //const UInt8 *path,
kFSPathMakeRefDoNotFollowLeafSymlink, //OptionBits options,
&objectRef, //FSRef *ref,
nullptr); //Boolean *isDirectory
@@ -155,21 +185,17 @@ bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
//implement same behavior as in Windows: if recycler is not existing, delete permanently
if (rv2 == -120) //=="Directory not found or incomplete pathname." but should really be "recycle bin directory not found"!
{
- struct ::stat fileInfo = {};
- if (::lstat(itempath.c_str(), &fileInfo) != 0)
- return false;
-
- if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode))
- removeFile(itempath); //throw FileError
- else if (S_ISDIR(fileInfo.st_mode))
- removeDirectoryRecursively(itempath); //throw FileError
+ if (*type == ItemType::FOLDER)
+ removeDirectoryPlainRecursion(itemPath); //throw FileError
+ else
+ removeFilePlain(itemPath); //throw FileError
return true;
}
throwFileError(rv2);
}
-#endif
return true;
+#endif
}
bgstack15