bool CState::RecursiveCopy(CLocalPath source, const CLocalPath& target)
{
	if (source.empty() || target.empty())
		return false;

	if (source == target)
		return false;

	if (source.IsParentOf(target))
		return false;

	if (!source.HasParent())
		return false;

	wxString last_segment;
	if (!source.MakeParent(&last_segment))
		return false;

	std::list<wxString> dirsToVisit;
	dirsToVisit.push_back(last_segment + CLocalPath::path_separator);

	// Process any subdirs which still have to be visited
	while (!dirsToVisit.empty())
	{
		wxString dirname = dirsToVisit.front();
		dirsToVisit.pop_front();
		wxMkdir(target.GetPath() + dirname);

		CLocalFileSystem fs;
		if (!fs.BeginFindFiles(source.GetPath() + dirname, false))
			continue;

		bool is_dir, is_link;
		wxString file;
		while (fs.GetNextFile(file, is_link, is_dir, 0, 0, 0))
		{
			if (file.empty())
			{
				wxGetApp().DisplayEncodingWarning();
				continue;
			}

			if (is_dir)
			{
				if (is_link)
					continue;

				const wxString subDir = dirname + file + CLocalPath::path_separator;
				dirsToVisit.push_back(subDir);
			}
			else
				wxCopyFile(source.GetPath() + dirname + file, target.GetPath() + dirname + file);
		}
	}

	return true;
}
Пример #2
0
bool CLocalFileSystem::RecursiveDelete(std::list<wxString> dirsToVisit, wxWindow* parent)
{
	// Under Windows use SHFileOperation to delete files and directories.
	// Under other systems, we have to recurse into subdirectories manually
	// to delete all contents.

#ifdef __WXMSW__
	// SHFileOperation accepts a list of null-terminated strings. Go through all
	// paths to get the required buffer length

	size_t len = 1; // String list terminated by empty string

	for (auto const& dir : dirsToVisit) {
		len += dir.size() + 1;
	}

	// Allocate memory
	wxChar* pBuffer = new wxChar[len];
	wxChar* p = pBuffer;

	for (auto& dir : dirsToVisit) {
		if (dir.Last() == wxFileName::GetPathSeparator())
			dir.RemoveLast();
		if (GetFileType(dir) == unknown)
			continue;

		_tcscpy(p, dir);
		p += dir.size() + 1;
	}
	if (p != pBuffer) {
		*p = 0;

		// Now we can delete the files in the buffer
		SHFILEOPSTRUCT op;
		memset(&op, 0, sizeof(op));
		op.hwnd = parent ? (HWND)parent->GetHandle() : 0;
		op.wFunc = FO_DELETE;
		op.pFrom = pBuffer;

		if (parent) {
			// Move to trash if shift is not pressed, else delete
			op.fFlags = wxGetKeyState(WXK_SHIFT) ? 0 : FOF_ALLOWUNDO;
		}
		else
			op.fFlags = FOF_NOCONFIRMATION;

		SHFileOperation(&op);
	}
	delete [] pBuffer;

	return true;
#else
	if (parent) {
		if (wxMessageBoxEx(_("Really delete all selected files and/or directories from your computer?"), _("Confirmation needed"), wxICON_QUESTION | wxYES_NO, parent) != wxYES)
			return true;
	}

	for (auto& dir : dirsToVisit) {
		if (dir.Last() == '/' && dir != _T("/"))
			dir.RemoveLast();
	}

	bool encodingError = false;

	// Remember the directories to delete after recursing into them
	std::list<wxString> dirsToDelete;

	CLocalFileSystem fs;

	// Process all dirctories that have to be visited
	while (!dirsToVisit.empty()) {
		auto const iter = dirsToVisit.begin();
		wxString const& path = *iter;

		if (GetFileType(path) != dir) {
			wxRemoveFile(path);
			dirsToVisit.erase(iter);
			continue;
		}

		dirsToDelete.splice(dirsToDelete.begin(), dirsToVisit, iter);

		if (!fs.BeginFindFiles(path, false)) {
			continue;
		}

		// Depending on underlying platform, wxDir does not handle
		// changes to the directory contents very well.
		// See http://trac.filezilla-project.org/ticket/3482
		// To work around this, delete files after enumerating everything in current directory
		std::list<wxString> filesToDelete;

		wxString file;
		while (fs.GetNextFile(file)) {
			if (file.empty()) {
				encodingError = true;
				continue;
			}

			const wxString& fullName = path + _T("/") + file;

			if (CLocalFileSystem::GetFileType(fullName) == CLocalFileSystem::dir)
				dirsToVisit.push_back(fullName);
			else
				filesToDelete.push_back(fullName);
		}
		fs.EndFindFiles();

		// Delete all files and links in current directory enumerated before
		for (auto const& file : filesToDelete) {
			wxRemoveFile(file);
		}
	}

	// Delete the now empty directories
	for (auto const& dir : dirsToDelete) {
		wxRmdir(dir);
	}

	return !encodingError;
#endif
}