diff --git a/packages/mediacenter/kodi/patches/kodi-999.99-PR10206-recursive-remove.patch b/packages/mediacenter/kodi/patches/kodi-999.99-PR10206-recursive-remove.patch new file mode 100644 index 0000000000..411a315a67 --- /dev/null +++ b/packages/mediacenter/kodi/patches/kodi-999.99-PR10206-recursive-remove.patch @@ -0,0 +1,278 @@ +From 3040f6024904eb1cf92a5b7b0e5268be756aecb0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A4r=20Bj=C3=B6rklund?= +Date: Sun, 31 Jul 2016 21:33:55 +0200 +Subject: [PATCH] Add a recursive version of CDirectory::Remove + +Tested on Windows and works +Untested on POSIX systems +--- + xbmc/Application.cpp | 6 ++-- + xbmc/filesystem/Directory.cpp | 27 +++++++++++++++ + xbmc/filesystem/Directory.h | 2 ++ + xbmc/filesystem/IDirectory.h | 7 ++++ + xbmc/filesystem/posix/PosixDirectory.cpp | 50 ++++++++++++++++++++++++++++ + xbmc/filesystem/posix/PosixDirectory.h | 1 + + xbmc/filesystem/win32/Win32Directory.cpp | 56 ++++++++++++++++++++++++++++++++ + xbmc/filesystem/win32/Win32Directory.h | 13 ++++---- + 8 files changed, 154 insertions(+), 8 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index edec038..00b24f4 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -1079,8 +1079,10 @@ void CApplication::CreateUserDirs() const + + //Let's clear our archive cache before starting up anything more + auto archiveCachePath = CSpecialProtocol::TranslatePath("special://temp/archive_cache/"); +- CDirectory::Remove(archiveCachePath); +- CDirectory::Create(archiveCachePath); ++ if (CDirectory::RemoveRecursive(archiveCachePath)) ++ CDirectory::Create(archiveCachePath); ++ else ++ CLog::Log(LOGWARNING, "Failed to remove the archive cache at %s", archiveCachePath.c_str()); + + } + +diff --git a/xbmc/filesystem/Directory.cpp b/xbmc/filesystem/Directory.cpp +index 05a3e43..25c0ba4 100644 +--- a/xbmc/filesystem/Directory.cpp ++++ b/xbmc/filesystem/Directory.cpp +@@ -323,6 +323,11 @@ bool CDirectory::Remove(const std::string& strPath) + return Remove(pathToUrl); + } + ++bool CDirectory::RemoveRecursive(const std::string& strPath) ++{ ++ return RemoveRecursive(CURL{ strPath }); ++} ++ + bool CDirectory::Remove(const CURL& url) + { + try +@@ -345,6 +350,28 @@ bool CDirectory::Remove(const CURL& url) + return false; + } + ++bool CDirectory::RemoveRecursive(const CURL& url) ++{ ++ try ++ { ++ CURL realURL = URIUtils::SubstitutePath(url); ++ std::unique_ptr pDirectory(CDirectoryFactory::Create(realURL)); ++ if (pDirectory.get()) ++ if(pDirectory->RemoveRecursive(realURL)) ++ { ++ g_directoryCache.ClearFile(realURL.Get()); ++ return true; ++ } ++ } ++ XBMCCOMMONS_HANDLE_UNCHECKED ++ catch (...) ++ { ++ CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); ++ } ++ CLog::Log(LOGERROR, "%s - Error removing %s", __FUNCTION__, url.GetRedacted().c_str()); ++ return false; ++} ++ + void CDirectory::FilterFileDirectories(CFileItemList &items, const std::string &mask) + { + for (int i=0; i< items.Size(); ++i) +diff --git a/xbmc/filesystem/Directory.h b/xbmc/filesystem/Directory.h +index bb06f32..a1f8f85 100644 +--- a/xbmc/filesystem/Directory.h ++++ b/xbmc/filesystem/Directory.h +@@ -58,6 +58,7 @@ class CDirectory + static bool Create(const CURL& url); + static bool Exists(const CURL& url, bool bUseCache = true); + static bool Remove(const CURL& url); ++ static bool RemoveRecursive(const CURL& url); + + static bool GetDirectory(const std::string& strPath + , CFileItemList &items +@@ -73,6 +74,7 @@ class CDirectory + static bool Create(const std::string& strPath); + static bool Exists(const std::string& strPath, bool bUseCache = true); + static bool Remove(const std::string& strPath); ++ static bool RemoveRecursive(const std::string& strPath); + + /*! \brief Filter files that act like directories from the list, replacing them with their directory counterparts + \param items The item list to filter +diff --git a/xbmc/filesystem/IDirectory.h b/xbmc/filesystem/IDirectory.h +index 03e086b..246c4d0 100644 +--- a/xbmc/filesystem/IDirectory.h ++++ b/xbmc/filesystem/IDirectory.h +@@ -102,6 +102,13 @@ class IDirectory + virtual bool Remove(const CURL& url) { return false; } + + /*! ++ \brief Recursively removes the directory ++ \param url Directory to remove. ++ \return Returns \e false if not succesful ++ */ ++ virtual bool RemoveRecursive(const CURL& url) { return false; } ++ ++ /*! + \brief Whether this file should be listed + \param url File to test. + \return Returns \e true if the file should be listed +diff --git a/xbmc/filesystem/posix/PosixDirectory.cpp b/xbmc/filesystem/posix/PosixDirectory.cpp +index f23037d..c90572d 100644 +--- a/xbmc/filesystem/posix/PosixDirectory.cpp ++++ b/xbmc/filesystem/posix/PosixDirectory.cpp +@@ -128,6 +128,56 @@ bool CPosixDirectory::Remove(const CURL& url) + + return !Exists(url); + } ++ bool CPosixDirectory::RemoveRecursive(const CURL& url) ++ { ++ std::string root = url.Get(); ++ ++ if (IsAliasShortcut(root, true)) ++ TranslateAliasShortcut(root); ++ ++ DIR *dir = opendir(root.c_str()); ++ if (!dir) ++ return false; ++ ++ struct dirent* entry; ++ while ((entry = readdir(dir)) != NULL) ++ { ++ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) ++ continue; ++ ++ std::string itemLabel(entry->d_name); ++ CCharsetConverter::unknownToUTF8(itemLabel); ++ std::string itemPath(URIUtils::AddFileToFolder(root, entry->d_name)); ++ ++ bool bStat = false; ++ struct stat buffer; ++ ++ // Unix-based readdir implementations may return an incorrect dirent.d_ino value that ++ // is not equal to the (correct) stat() obtained one. In this case the file type ++ // could not be determined and the value of dirent.d_type is set to DT_UNKNOWN. ++ // In order to get a correct value we have to incur the cost of calling stat. ++ if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) ++ { ++ if (stat(itemPath.c_str(), &buffer) == 0) ++ bStat = true; ++ } ++ ++ if (entry->d_type == DT_DIR || (bStat && S_ISDIR(buffer.st_mode))) ++ { ++ if (!RemoveRecursive(CURL{ itemPath })) ++ return false; ++ if (rmdir(itemPath.c_str()) != 0) ++ return false; ++ } ++ else ++ { ++ if (unlink(itemPath.c_str()) != 0) ++ return false; ++ } ++ } ++ closedir(dir); ++ return true; ++ } + + bool CPosixDirectory::Exists(const CURL& url) + { +diff --git a/xbmc/filesystem/posix/PosixDirectory.h b/xbmc/filesystem/posix/PosixDirectory.h +index 91b97c6..8c2a837 100644 +--- a/xbmc/filesystem/posix/PosixDirectory.h ++++ b/xbmc/filesystem/posix/PosixDirectory.h +@@ -33,5 +33,6 @@ class CPosixDirectory : public IDirectory + virtual bool Create(const CURL& url); + virtual bool Exists(const CURL& url); + virtual bool Remove(const CURL& url); ++ virtual bool RemoveRecursive(const CURL& url); + }; + } +diff --git a/xbmc/filesystem/win32/Win32Directory.cpp b/xbmc/filesystem/win32/Win32Directory.cpp +index 339cefa..c580c2b 100644 +--- a/xbmc/filesystem/win32/Win32Directory.cpp ++++ b/xbmc/filesystem/win32/Win32Directory.cpp +@@ -178,4 +178,60 @@ bool CWin32Directory::Remove(const CURL& url) + return !Exists(url); + } + ++bool CWin32Directory::RemoveRecursive(const CURL& url) ++{ ++ std::string pathWithSlash(url.Get()); ++ if (!pathWithSlash.empty() && pathWithSlash.back() != '\\') ++ pathWithSlash.push_back('\\'); ++ ++ auto basePath = CWIN32Util::ConvertPathToWin32Form(pathWithSlash); ++ if (basePath.empty()) ++ return false; ++ ++ auto searchMask = basePath + L'*'; ++ ++ HANDLE hSearch; ++ WIN32_FIND_DATAW findData = {}; ++ ++ if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin7)) ++ hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH); ++ else ++ hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, nullptr, 0); ++ ++ if (hSearch == INVALID_HANDLE_VALUE) ++ return GetLastError() == ERROR_FILE_NOT_FOUND ? Exists(url) : false; // return true if directory exist and empty ++ ++ do ++ { ++ std::wstring itemNameW(findData.cFileName); ++ if (itemNameW == L"." || itemNameW == L"..") ++ continue; ++ ++ auto pathW = basePath + itemNameW; ++ if (0 != (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) ++ { ++ std::string path; ++ if (!g_charsetConverter.wToUTF8(pathW, path, true)) ++ { ++ CLog::Log(LOGERROR, "%s: Can't convert wide string name to UTF-8 encoding", __FUNCTION__); ++ continue; ++ } ++ ++ if (!RemoveRecursive(CURL{ path })) ++ return false; ++ ++ if (FALSE == RemoveDirectoryW(pathW.c_str())) ++ return false; ++ } ++ else ++ { ++ if (FALSE == DeleteFileW(pathW.c_str())) ++ return false; ++ } ++ } while (FindNextFileW(hSearch, &findData)); ++ ++ FindClose(hSearch); ++ ++ return true; ++} + #endif // TARGET_WINDOWS +diff --git a/xbmc/filesystem/win32/Win32Directory.h b/xbmc/filesystem/win32/Win32Directory.h +index 2d77588..c03e68b 100644 +--- a/xbmc/filesystem/win32/Win32Directory.h ++++ b/xbmc/filesystem/win32/Win32Directory.h +@@ -27,11 +27,12 @@ namespace XFILE + class CWin32Directory : public IDirectory + { + public: +- CWin32Directory(void); +- virtual ~CWin32Directory(void); +- virtual bool GetDirectory(const CURL& url, CFileItemList &items); +- virtual bool Create(const CURL& url); +- virtual bool Exists(const CURL& url); +- virtual bool Remove(const CURL& url); ++ CWin32Directory(); ++ virtual ~CWin32Directory(); ++ bool GetDirectory(const CURL& url, CFileItemList &items) override; ++ bool Create(const CURL& url) override; ++ bool Exists(const CURL& url) override; ++ bool Remove(const CURL& url) override; ++ bool RemoveRecursive(const CURL& url) override; + }; + }