summaryrefslogtreecommitdiff
path: root/zen/recycler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/recycler.cpp')
-rw-r--r--zen/recycler.cpp95
1 files changed, 56 insertions, 39 deletions
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index 11b599d4..b9245259 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -5,17 +5,14 @@
// **************************************************************************
#include "recycler.h"
-//#include <stdexcept>
-//#include <iterator>
#include <zen/file_handling.h>
#ifdef ZEN_WIN
-//#include <algorithm>
-//#include <functional>
-#include <zen/dll.h>
-#include <zen/assert_static.h>
-#include <zen/win_ver.h>
-#include <zen/long_path_prefix.h>
+#include "thread.h"
+#include "dll.h"
+#include "assert_static.h"
+#include "win_ver.h"
+#include "long_path_prefix.h"
#include "IFileOperation/file_op.h"
#elif defined ZEN_LINUX
@@ -45,7 +42,6 @@ IFileOperation - multiple files 2,1s
Nevertheless, let's use IFileOperation for better error reporting (including details on locked files)!
*/
-const bool useIFileOperation = vistaOrLater(); //caveat: function scope static initialization is not thread-safe in VS 2010!
struct CallbackData
{
@@ -58,7 +54,7 @@ struct CallbackData
};
-bool recyclerCallback(const wchar_t* filename, void* sink)
+bool onRecyclerCallback(const wchar_t* filename, void* sink)
{
CallbackData& cbd = *static_cast<CallbackData*>(sink); //sink is NOT optional here
@@ -76,6 +72,7 @@ bool recyclerCallback(const wchar_t* filename, void* sink)
}
}
+
void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus)
{
if (filenames.empty())
@@ -85,7 +82,7 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func
//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!
- if (useIFileOperation) //new recycle bin usage: available since Vista
+ if (vistaOrLater()) //new recycle bin usage: available since Vista
{
using namespace fileop;
const DllFun<FunType_moveToRecycleBin> moveToRecycler(getDllName(), funName_moveToRecycleBin);
@@ -100,16 +97,14 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func
cNames.push_back(it->c_str());
CallbackData cbd(notifyDeletionStatus);
- if (!moveToRecycler(&cNames[0], cNames.size(), recyclerCallback, &cbd))
+ if (!moveToRecycler(&cNames[0], cNames.size(), onRecyclerCallback, &cbd))
{
if (cbd.exceptionInUserCallback)
- try
- {
- assert(notifyDeletionStatus);
- notifyDeletionStatus(Zstring()); //should throw again!!!
- assert(false);
- }
- catch (...) { throw; }
+ {
+ assert(notifyDeletionStatus);
+ notifyDeletionStatus(Zstring()); //should throw again!!!
+ assert(false);
+ }
std::wstring filenameFmt = fmtFileName(filenames[0]); //probably not the correct file name for file lists larger than 1!
if (filenames.size() > 1)
@@ -174,7 +169,7 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError
//implement same behavior as in Windows: if recycler is not existing, delete permanently
if (error->code == G_IO_ERROR_NOT_SUPPORTED)
{
- struct stat fileInfo = {};
+ struct ::stat fileInfo = {};
if (::lstat(filename.c_str(), &fileInfo) != 0)
return false;
@@ -205,7 +200,7 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError
throw FileError(errorMsg, errorDescr);
};
- FSRef objectRef;
+ FSRef objectRef = {}; //= POD structure not a pointer type!
OSStatus rv = ::FSPathMakeRefWithOptions(filenameUtf8, //const UInt8 *path,
kFSPathMakeRefDoNotFollowLeafSymlink, //OptionBits options,
&objectRef, //FSRef *ref,
@@ -222,7 +217,7 @@ bool zen::recycleOrDelete(const Zstring& filename) //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 = {};
+ struct ::stat fileInfo = {};
if (::lstat(filename.c_str(), &fileInfo) != 0)
return false;
@@ -241,31 +236,53 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError
#ifdef ZEN_WIN
-StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
+bool zen::recycleBinExists(const Zstring& pathName, const std::function<void ()>& onUpdateGui) //throw FileError
{
- const DWORD bufferSize = MAX_PATH + 1;
- std::vector<wchar_t> buffer(bufferSize);
- if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
- &buffer[0], //__out LPTSTR lpszVolumePathName,
- bufferSize)) //__in DWORD cchBufferLength
- return STATUS_REC_UNKNOWN;
+ if (vistaOrLater())
+ {
+ using namespace fileop;
+ const DllFun<FunType_getRecycleBinStatus> getRecycleBinStatus(getDllName(), funName_getRecycleBinStatus);
+ const DllFun<FunType_getLastError> getLastError (getDllName(), funName_getLastError);
+
+ if (!getRecycleBinStatus || !getLastError)
+ throw FileError(replaceCpy(_("Checking recycle bin failed for folder %x."), L"%x", fmtFileName(pathName)),
+ replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
+
+ bool hasRecycler = false;
+ if (!getRecycleBinStatus(pathName.c_str(), hasRecycler))
+ throw FileError(replaceCpy(_("Checking recycle bin failed for folder %x."), L"%x", fmtFileName(pathName)), getLastError());
+
+ return hasRecycler;
+ }
+ else
+ {
+ //excessive runtime if recycle bin exists, is full and drive is slow:
+ auto ft = async([pathName]()
+ {
+ SHQUERYRBINFO recInfo = {};
+ recInfo.cbSize = sizeof(recInfo);
+ return ::SHQueryRecycleBin(pathName.c_str(), //__in_opt LPCTSTR pszRootPath,
+ &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
+ });
- const Zstring rootPathPf = appendSeparator(&buffer[0]);
+ while (!ft.timed_wait(boost::posix_time::milliseconds(50)))
+ if (onUpdateGui)
+ onUpdateGui(); //may throw!
+
+ return ft.get() == S_OK;
+ }
- SHQUERYRBINFO recInfo = {};
- recInfo.cbSize = sizeof(recInfo);
- HRESULT rv = ::SHQueryRecycleBin(rootPathPf.c_str(), //__in_opt LPCTSTR pszRootPath,
- &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
+ //1. ::SHQueryRecycleBin() is excessive: traverses whole $Recycle.Bin directory tree each time!!!! But it's safe and correct.
- return rv == S_OK ? STATUS_REC_EXISTS : STATUS_REC_MISSING;
- //1. excessive: traverses whole C:\$Recycle.Bin directory tree each time!!!! But it's safe and correct.
+ //2. we can't simply buffer the ::SHQueryRecycleBin() based on volume serial number:
+ // "subst S:\ C:\" => GetVolumeInformation() returns same serial for C:\ and S:\, but S:\ does not support recycle bin!
- //2. we would prefer to use CLSID_RecycleBinManager beginning with Vista... if only this interface were documented!!!
+ //3. we would prefer to use CLSID_RecycleBinManager beginning with Vista... if only this interface were documented!!!
- //3. check directory existence of "C:\$Recycle.Bin, C:\RECYCLER, C:\RECYCLED"
+ //4. check directory existence of "C:\$Recycle.Bin, C:\RECYCLER, C:\RECYCLED"
// -> not upward-compatible, wrong result for subst-alias: recycler assumed existing, although it is not!
- //4. alternative approach a'la Raymond Chen: http://blogs.msdn.com/b/oldnewthing/archive/2008/09/18/8956382.aspx
+ //5. alternative approach a'la Raymond Chen: http://blogs.msdn.com/b/oldnewthing/archive/2008/09/18/8956382.aspx
//caveat: might not be reliable, e.g. "subst"-alias of volume contains "$Recycle.Bin" although it is not available!
/*
bgstack15