summaryrefslogtreecommitdiff
path: root/library/fileHandling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/fileHandling.cpp')
-rw-r--r--library/fileHandling.cpp342
1 files changed, 210 insertions, 132 deletions
diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp
index 688d3640..cda81ef5 100644
--- a/library/fileHandling.cpp
+++ b/library/fileHandling.cpp
@@ -1,19 +1,13 @@
#include "fileHandling.h"
#include <wx/intl.h>
#include <wx/msgdlg.h>
-#include "resources.h"
+#include "../algorithm.h"
+#include <wx/filename.h>
#ifdef FFS_WIN
#include <wx/msw/wrapwin.h> //includes "windows.h"
#endif // FFS_WIN
-inline
-bool endsWithPathSeparator(const Zstring& name)
-{
- const size_t len = name.length();
- return len && (name[len - 1] == GlobalResources::FILE_NAME_SEPARATOR);
-}
-
class RecycleBin
{
@@ -89,19 +83,30 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin)
if (useRecycleBin)
{
if (!moveToRecycleBin(filename))
- throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + filename + wxT("\""));
+ throw FileError(Zstring(_("Error moving to Recycle Bin:")) + wxT("\n\"") + filename + wxT("\""));
return;
}
#ifdef FFS_WIN
+ //initialize file attributes
if (!SetFileAttributes(
- filename.c_str(), //address of filename
- FILE_ATTRIBUTE_NORMAL //attributes to set
- )) throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\""));
-#endif //FFS_WIN
+ filename.c_str(), //address of filename
+ FILE_ATTRIBUTE_NORMAL)) //attributes to set
+ {
+ Zstring errorMessage = Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ //remove file, support for \\?\-prefix
+ if (DeleteFile(filename.c_str()) == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+#else
if (!wxRemoveFile(filename.c_str()))
- throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\""));
+ throw FileError(Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\""));
+#endif
}
@@ -112,53 +117,65 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc
if (useRecycleBin)
{
if (!moveToRecycleBin(directory))
- throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + directory + wxT("\""));
+ throw FileError(Zstring(_("Error moving to Recycle Bin:")) + wxT("\n\"") + directory + wxT("\""));
return;
}
std::vector<Zstring> fileList;
std::vector<Zstring> dirList;
- try
- { //should be executed in own scope so that directory access does not disturb deletion!
- getAllFilesAndDirs(directory, fileList, dirList);
- }
- catch (const FileError& e)
- {
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + directory + wxT("\""));
- }
+ getAllFilesAndDirs(directory, fileList, dirList);
for (unsigned int j = 0; j < fileList.size(); ++j)
removeFile(fileList[j], false);
- dirList.insert(dirList.begin(), directory); //this directory will be deleted last
+ dirList.insert(dirList.begin(), directory); //parent directory will be deleted last
for (int j = int(dirList.size()) - 1; j >= 0 ; --j)
{
#ifdef FFS_WIN
+ //initialize file attributes
if (!SetFileAttributes(
dirList[j].c_str(), // address of directory name
FILE_ATTRIBUTE_NORMAL)) // attributes to set
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\""));
-#endif // FFS_WIN
+ {
+ Zstring errorMessage = Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ //remove directory, support for \\?\-prefix
+ if (RemoveDirectory(dirList[j].c_str()) == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+#else
if (!wxRmdir(dirList[j].c_str()))
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\""));
+ throw FileError(Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\""));
+#endif
}
}
void FreeFileSync::createDirectory(const Zstring& directory, const int level)
{
- if (wxDirExists(directory))
+ if (wxDirExists(directory.c_str()))
return;
if (level == 50) //catch endless recursion
return;
- //try to create directory
- if (wxMkdir(directory.c_str()))
+ //try to create directory, support for \\?\-prefix
+#ifdef FFS_WIN
+ if (CreateDirectory(
+ directory.c_str(), // pointer to a directory path string
+ NULL // pointer to a security descriptor
+ ) != 0)
+ return;
+#else
+ if (wxMkdir(directory.c_str())) //wxMkDir has different signature under Linux!
return;
+#endif
//if not successfull try to create parent folders first
Zstring parentDir;
@@ -176,11 +193,25 @@ void FreeFileSync::createDirectory(const Zstring& directory, const int level)
createDirectory(parentDir, level + 1);
//now creation should be possible
- if (!wxMkdir(directory.c_str()))
+#ifdef FFS_WIN
+ if (CreateDirectory(
+ directory.c_str(), // pointer to a directory path string
+ NULL // pointer to a security descriptor
+ ) == 0)
+ {
+ if (level == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error creating directory:")) + wxT("\n\"") + directory + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ }
+#else
+ if (!wxMkdir(directory.c_str())) //wxMkDir has different signature under Linux!
{
if (level == 0)
- throw FileError(Zstring(_("Error creating directory:")) + wxT(" \"") + directory + wxT("\""));
+ throw FileError(Zstring(_("Error creating directory:")) + wxT("\n\"") + directory + wxT("\""));
}
+#endif
}
@@ -189,41 +220,44 @@ void FreeFileSync::copyFolderAttributes(const Zstring& source, const Zstring& ta
#ifdef FFS_WIN
DWORD attr = GetFileAttributes(source.c_str()); // address of the name of a file or directory
if (attr == 0xFFFFFFFF)
- throw FileError(Zstring(_("Error reading folder attributes:")) + wxT(" \"") + source + wxT("\""));
+ {
+ Zstring errorMessage = Zstring(_("Error reading folder attributes:")) + wxT("\n\"") + source + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
if (!SetFileAttributes(
target.c_str(), // address of filename
attr)) // address of attributes to set
- throw FileError(Zstring(_("Error writing folder attributes:")) + wxT(" \"") + target + wxT("\""));
+ {
+ Zstring errorMessage = Zstring(_("Error writing folder attributes:")) + wxT("\n\"") + target + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
#elif defined FFS_LINUX
//Linux doesn't use attributes for files or folders
#endif
}
-class GetAllFilesSimple : public wxDirTraverser
+class FilesDirsOnlyTraverser : public FreeFileSync::FullDetailFileTraverser
{
public:
- GetAllFilesSimple(std::vector<Zstring>& files, std::vector<Zstring>& subDirectories) :
+ FilesDirsOnlyTraverser(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
m_files(files),
- m_dirs(subDirectories) {}
+ m_dirs(dirs) {}
- wxDirTraverseResult OnDir(const wxString& dirname)
+ virtual wxDirTraverseResult OnFile(const Zstring& filename, const FreeFileSync::FileInfo& details)
{
- m_dirs.push_back(dirname.c_str());
+ m_files.push_back(filename);
return wxDIR_CONTINUE;
}
-
- wxDirTraverseResult OnFile(const wxString& filename)
+ virtual wxDirTraverseResult OnDir(const Zstring& dirname)
{
- m_files.push_back(filename.c_str());
+ m_dirs.push_back(dirname);
return wxDIR_CONTINUE;
}
-
- wxDirTraverseResult OnOpenError(const wxString& openerrorname)
+ virtual wxDirTraverseResult OnError(const Zstring& errorText)
{
- wxMessageBox(openerrorname, _("Error"));
- return wxDIR_IGNORE;
+ throw FileError(errorText);
}
private:
@@ -238,11 +272,8 @@ void FreeFileSync::getAllFilesAndDirs(const Zstring& sourceDir, std::vector<Zstr
directories.clear();
//get all files and directories from current directory (and subdirectories)
- wxDir dir(sourceDir.c_str());
- GetAllFilesSimple traverser(files, directories);
-
- if (dir.Traverse(traverser) == (size_t)-1)
- throw FileError(Zstring(_("Error traversing directory:")) + wxT(" \"") + sourceDir + wxT("\""));
+ FilesDirsOnlyTraverser traverser(files, directories);
+ traverseInDetail(sourceDir, false, &traverser);
}
@@ -285,7 +316,7 @@ public:
{
struct stat fileInfo;
if (stat(filename.c_str(), &fileInfo) != 0)
- return m_sink->OnError(Zstring(_("Could not retrieve file info for:")) + wxT(" \"") + filename.c_str() + wxT("\""));
+ return m_sink->OnError(Zstring(_("Could not retrieve file info for:")) + wxT("\n\"") + filename.c_str() + wxT("\""));
FreeFileSync::FileInfo details;
details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second
@@ -310,115 +341,162 @@ private:
#endif
-bool FreeFileSync::traverseInDetail(const Zstring& directory, FullDetailFileTraverser* sink, const int level)
+class TraverseRecursively
{
-#ifdef FFS_WIN
- if (level == 50) //catch endless recursion
+public:
+ TraverseRecursively(const bool traverseSymbolicLinks, FreeFileSync::FullDetailFileTraverser* sink) :
+ m_traverseSymbolicLinks(traverseSymbolicLinks),
+ m_sink(sink) {}
+
+ bool traverse(const Zstring& directory, const int level)
{
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directory) == wxDIR_STOP)
- return false;
- else
- return true;
- }
+#ifdef FFS_WIN
+ if (level == 50) //catch endless recursion
+ {
+ if (m_sink->OnError(Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\"")) == wxDIR_STOP)
+ return false;
+ else
+ return true;
+ }
- Zstring directoryFormatted = directory;
- if (!endsWithPathSeparator(directoryFormatted))
- directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR;
+ Zstring directoryFormatted = directory;
+ if (!FreeFileSync::endsWithPathSeparator(directoryFormatted))
+ directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR;
- const Zstring filespec = directoryFormatted + wxT("*.*");
+ const Zstring filespec = directoryFormatted + DefaultChar('*');
- WIN32_FIND_DATA fileMetaData;
- HANDLE searchHandle = FindFirstFile(filespec.c_str(), //pointer to name of file to search for
- &fileMetaData); //pointer to returned information
+ WIN32_FIND_DATA fileMetaData;
+ HANDLE searchHandle = FindFirstFile(filespec.c_str(), //pointer to name of file to search for
+ &fileMetaData); //pointer to returned information
- if (searchHandle == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return true;
- //else: we have a problem...
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP)
- return false;
- else
- return true;
- }
- CloseOnExit dummy(searchHandle);
-
- do
- { //don't return "." and ".."
- const wxChar* name = fileMetaData.cFileName;
- if ( name[0] == wxChar('.') &&
- ((name[1] == wxChar('.') && name[2] == wxChar('\0')) ||
- name[1] == wxChar('\0')))
- continue;
-
- const Zstring fullName = directoryFormatted + name;
- if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory...
+ if (searchHandle == INVALID_HANDLE_VALUE)
{
- switch (sink->OnDir(fullName))
+ const DWORD lastError = GetLastError();
+ if (lastError == ERROR_FILE_NOT_FOUND)
+ return true;
+
+ //else: we have a problem... report it:
+ Zstring errorMessage = Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\" ") ;
+ if (m_sink->OnError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)) == wxDIR_STOP)
+ return false;
+ else
+ return true;
+ }
+ CloseOnExit dummy(searchHandle);
+
+ do
+ { //don't return "." and ".."
+ const wxChar* name = fileMetaData.cFileName;
+ if ( name[0] == wxChar('.') &&
+ ((name[1] == wxChar('.') && name[2] == wxChar('\0')) ||
+ name[1] == wxChar('\0')))
+ continue;
+
+ const Zstring fullName = directoryFormatted + name;
+
+ if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory...
{
- case wxDIR_IGNORE:
- break;
- case wxDIR_CONTINUE:
- if (!traverseInDetail(fullName, sink, level + 1))
+ switch (m_sink->OnDir(fullName))
+ {
+ case wxDIR_IGNORE:
+ break;
+ case wxDIR_CONTINUE:
+ //traverse into symbolic links, junctions, etc. if requested only:
+ if (m_traverseSymbolicLinks || (~fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ if (!this->traverse(fullName, level + 1))
+ return false;
+ break;
+ case wxDIR_STOP:
return false;
- else
+ default:
+ assert(false);
break;
- case wxDIR_STOP:
- return false;
- default:
- assert(false);
- break;
+ }
}
- }
- else //a file...
- {
- FileInfo details;
- getWin32FileInformation(fileMetaData, details);
-
- switch (sink->OnFile(fullName, details))
+ else //a file...
{
- case wxDIR_IGNORE:
- case wxDIR_CONTINUE:
- break;
- case wxDIR_STOP:
- return false;
- default:
- assert(false);
- break;
+ FreeFileSync::FileInfo details;
+ getWin32FileInformation(fileMetaData, details);
+
+ switch (m_sink->OnFile(fullName, details))
+ {
+ case wxDIR_IGNORE:
+ case wxDIR_CONTINUE:
+ break;
+ case wxDIR_STOP:
+ return false;
+ default:
+ assert(false);
+ break;
+ }
}
}
- }
- while (FindNextFile(searchHandle, // handle to search
- &fileMetaData)); // pointer to structure for data on found file
+ while (FindNextFile(searchHandle, // handle to search
+ &fileMetaData)); // pointer to structure for data on found file
- if (GetLastError() == ERROR_NO_MORE_FILES)
- return true; //everything okay
- else //an error occured
- {
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP)
+ const DWORD lastError = GetLastError();
+ if (lastError == ERROR_NO_MORE_FILES)
+ return true; //everything okay
+
+ //else: we have a problem... report it:
+ Zstring errorMessage = Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\" ") ;
+ if (m_sink->OnError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)) == wxDIR_STOP)
return false;
else
return true;
- }
#elif defined FFS_LINUX
- //use standard file traverser and enrich output with additional file information
- //could be improved with custom traversing algorithm for optimized performance
- EnhancedFileTraverser traverser(sink);
+ //use standard file traverser and enrich output with additional file information
+ //could be improved with custom traversing algorithm for optimized performance
+ EnhancedFileTraverser traverser(m_sink);
- wxDir dir(directory.c_str());
- if (dir.IsOpened())
- dir.Traverse(traverser);
+ wxDir dir(directory.c_str());
+ if (dir.IsOpened())
+ dir.Traverse(traverser);
- return true;
+ return true;
#else
- adapt this
+ adapt this
#endif
+ }
+
+private:
+ const bool m_traverseSymbolicLinks;
+ FreeFileSync::FullDetailFileTraverser* m_sink;
+};
+
+
+void FreeFileSync::traverseInDetail(const Zstring& directory,
+ const bool traverseSymbolicLinks,
+ FullDetailFileTraverser* sink)
+{
+ TraverseRecursively filewalker(traverseSymbolicLinks, sink);
+ filewalker.traverse(directory, 0);
}
+#ifdef FFS_WIN
+inline
+Zstring getDriveName(const Zstring& directoryName) //GetVolume() doesn't work under Linux!
+{
+ const Zstring volumeName = wxFileName(directoryName.c_str()).GetVolume().c_str();
+ if (volumeName.empty())
+ return Zstring();
+ return volumeName + wxFileName::GetVolumeSeparator().c_str() + GlobalResources::FILE_NAME_SEPARATOR;
+}
+bool FreeFileSync::isFatDrive(const Zstring& directoryName)
+{
+ const Zstring driveName = getDriveName(directoryName);
+ if (driveName.empty())
+ return false;
+ wxChar fileSystem[32];
+ if (!GetVolumeInformation(driveName.c_str(), NULL, 0, NULL, NULL, NULL, fileSystem, 32))
+ return false;
+ return Zstring(fileSystem).StartsWith(wxT("FAT"));
+}
+#endif //FFS_WIN
bgstack15