diff --git a/source/lib/file/vfs/vfs_populate.cpp b/source/lib/file/vfs/vfs_populate.cpp index fe763ae2b5..d9348ce4e4 100644 --- a/source/lib/file/vfs/vfs_populate.cpp +++ b/source/lib/file/vfs/vfs_populate.cpp @@ -39,6 +39,14 @@ static std::vector s_looseFiles; static size_t s_numArchivedFiles; #endif +struct CompareFileInfoByName +{ + bool operator()(const FileInfo& a, const FileInfo& b) + { + return a.Name() < b.Name(); + } +}; + // helper class that allows breaking up the logic into sub-functions without // always having to pass directory/realDirectory as parameters. class PopulateHelper @@ -60,6 +68,13 @@ public: DirectoryNames subdirectoryNames; subdirectoryNames.reserve(50); RETURN_STATUS_IF_ERR(GetDirectoryEntries(m_realDirectory->Path(), &files, &subdirectoryNames)); + // to support .DELETED files inside archives safely, we need to load + // archives and loose files in a deterministic order in case they add + // and then delete the same file (or vice versa, depending on loading + // order). GetDirectoryEntries has undefined order so sort its output + std::sort(files.begin(), files.end(), CompareFileInfoByName()); + std::sort(subdirectoryNames.begin(), subdirectoryNames.end()); + RETURN_STATUS_IF_ERR(AddFiles(files)); AddSubdirectories(subdirectoryNames);