summaryrefslogtreecommitdiff
path: root/zen/file_traverser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_traverser.cpp')
-rw-r--r--zen/file_traverser.cpp72
1 files changed, 46 insertions, 26 deletions
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 9c1b01a4..70593d1d 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -22,6 +22,7 @@
#endif
#if defined ZEN_LINUX || defined ZEN_MAC
+#include <cstddef> //required by GCC 4.8.1 to find ptrdiff_t
#include <sys/stat.h>
#include <dirent.h>
#endif
@@ -153,8 +154,7 @@ typedef ... FindData;
static void create(const Zstring& directory, DirHandle& hnd); //throw FileError - *no* concession to FindFirstFile(): open handle only, *no* return of data!
static void destroy(DirHandle hnd); //throw()
-template <class FallbackFun>
-static bool getEntry(DirHandle hnd, const Zstring& directory, FindData& fileInfo, FallbackFun fb) //throw FileError -> fb: fallback to FindFirstFile()/FindNextFile()
+static bool getEntry(DirHandle hnd, const Zstring& directory, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser -> fallback to FindFirstFile()/FindNextFile()
//FindData "member" functions
static void extractFileInfo (const FindData& fileInfo, DWORD volumeSerial, TraverseCallback::FileInfo& output); //volumeSerial may be 0 if not available!
@@ -207,8 +207,7 @@ struct Win32Traverser
static void destroy(const DirHandle& hnd) { ::FindClose(hnd.searchHandle); } //throw()
- template <class FallbackFun>
- static bool getEntry(DirHandle& hnd, const Zstring& dirname, FindData& fileInfo, FallbackFun) //throw FileError
+ static bool getEntry(DirHandle& hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError
{
if (hnd.searchHandle == INVALID_HANDLE_VALUE) //handle special case of "truly empty directories"
return false;
@@ -247,6 +246,9 @@ struct Win32Traverser
};
+class NeedFallbackToWin32Traverser {}; //special exception class
+
+
struct FilePlusTraverser
{
struct DirHandle
@@ -267,8 +269,7 @@ struct FilePlusTraverser
static void destroy(DirHandle hnd) { ::closeDir(hnd.searchHandle); } //throw()
- template <class FallbackFun>
- static bool getEntry(DirHandle hnd, const Zstring& dirname, FindData& fileInfo, FallbackFun fb) //throw FileError
+ static bool getEntry(DirHandle hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser
{
if (!::readDir(hnd.searchHandle, fileInfo))
{
@@ -281,10 +282,8 @@ struct FilePlusTraverser
this is required for NetDrive mounted Webdav, e.g. www.box.net and NT4, 2000 remote drives, et al.
*/
if (lastError == ERROR_NOT_SUPPORTED)
- {
- fb(); //fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications!
- return false;
- }
+ throw NeedFallbackToWin32Traverser();
+ //fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications!
//else we have a problem... report it:
throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"readDir", lastError));
@@ -312,6 +311,12 @@ struct FilePlusTraverser
class DirTraverser
{
public:
+ static void execute(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback)
+ {
+ DirTraverser(baseDirectory, sink, dstCallback);
+ }
+
+private:
DirTraverser(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback) :
needDstHack(dstCallback ? dst::isFatDrive(baseDirectory) : false)
{
@@ -322,7 +327,13 @@ public:
catch (FileError&) {} //don't cause issues in user mode
if (::openDir && ::readDir && ::closeDir)
- traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //retrieveVolumeSerial returns 0 on error
+ {
+ try
+ {
+ traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //throw NeedFallbackToWin32Traverser; retrieveVolumeSerial returns 0 on error
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(baseDirectory, sink, 0); }
+ }
else //fallback
traverse<Win32Traverser>(baseDirectory, sink, 0);
@@ -332,33 +343,29 @@ public:
applyDstHack(*dstCallback);
}
-private:
DirTraverser(const DirTraverser&);
DirTraverser& operator=(const DirTraverser&);
template <class Trav>
- void traverse(const Zstring& dirname, zen::TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/)
+ void traverse(const Zstring& dirname, zen::TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/) //throw NeedFallbackToWin32Traverser
{
//no need to check for endless recursion: Windows seems to have an internal path limit of about 700 chars
typename Trav::DirHandle searchHandle;
- if (!tryReportingDirError([&]
- {
- typedef Trav Trav; //f u VS!
- Trav::create(dirname, searchHandle); //throw FileError
- }, sink))
+ if (!tryReportingDirError([&] { Trav::create(dirname, searchHandle); /*throw FileError*/ }, sink))
return; //ignored error
- ZEN_ON_SCOPE_EXIT(typedef Trav Trav; Trav::destroy(searchHandle));
+ ZEN_ON_SCOPE_EXIT(Trav::destroy(searchHandle));
typename Trav::FindData findData = {};
- auto fallback = [&] { this->traverse<Win32Traverser>(dirname, sink, volumeSerial); }; //help VS2010 a little by avoiding too deeply nested lambdas
-
for (;;)
{
bool gotEntry = false;
- tryReportingDirError([&] { typedef Trav Trav; /*VS 2010 bug*/ gotEntry = Trav::getEntry(searchHandle, dirname, findData, fallback); }, sink); //throw FileError
+ tryReportingDirError([&]
+ {
+ gotEntry = Trav::getEntry(searchHandle, dirname, findData); //throw FileError, NeedFallbackToWin32Traverser
+ }, sink);
if (!gotEntry) //no more items or ignored error
return;
@@ -383,7 +390,11 @@ private:
if (TraverseCallback* trav = sink.onDir(shortName, fullName))
{
ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav));
- traverse<Trav>(fullName, *trav, retrieveVolumeSerial(fullName)); //symlink may link to different volume => redetermine volume serial!
+ try
+ {
+ traverse<Trav>(fullName, *trav, retrieveVolumeSerial(fullName)); //throw NeedFallbackToWin32Traverser; symlink may link to different volume => redetermine volume serial!
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); }
}
}
else //a file
@@ -410,7 +421,11 @@ private:
if (TraverseCallback* trav = sink.onDir(shortName, fullName))
{
ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav));
- traverse<Trav>(fullName, *trav, volumeSerial);
+ try
+ {
+ traverse<Trav>(fullName, *trav, volumeSerial); //throw NeedFallbackToWin32Traverser
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); }
}
}
else //a file
@@ -493,6 +508,12 @@ private:
class DirTraverser
{
public:
+ static void execute(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback)
+ {
+ DirTraverser(baseDirectory, sink, dstCallback);
+ }
+
+private:
DirTraverser(const Zstring& baseDirectory, zen::TraverseCallback& sink, zen::DstHackCallback* dstCallback)
{
const Zstring directoryFormatted = //remove trailing slash
@@ -511,7 +532,6 @@ public:
traverse(directoryFormatted, sink);
}
-private:
DirTraverser(const DirTraverser&);
DirTraverser& operator=(const DirTraverser&);
@@ -658,5 +678,5 @@ private:
void zen::traverseFolder(const Zstring& dirname, TraverseCallback& sink, DstHackCallback* dstCallback)
{
- DirTraverser(dirname, sink, dstCallback);
+ DirTraverser::execute(dirname, sink, dstCallback);
}
bgstack15