Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[xbmc/fix/filesystem] Add a recursive version of CDirectory::Remove #10206

Merged
merged 1 commit into from
Aug 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions xbmc/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());

}

Expand Down
27 changes: 27 additions & 0 deletions xbmc/filesystem/Directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<IDirectory> 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)
Expand Down
2 changes: 2 additions & 0 deletions xbmc/filesystem/Directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions xbmc/filesystem/IDirectory.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,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.
Expand Down
50 changes: 50 additions & 0 deletions xbmc/filesystem/posix/PosixDirectory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions xbmc/filesystem/posix/PosixDirectory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
}
56 changes: 56 additions & 0 deletions xbmc/filesystem/win32/Win32Directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 7 additions & 6 deletions xbmc/filesystem/win32/Win32Directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}