Ticket #2641: vfs_DELETED_folders+fix.patch
File vfs_DELETED_folders+fix.patch, 11.0 KB (added by , 8 years ago) |
---|
-
source/lib/file/vfs/tests/test_vfs_tree.h
1 /* Copyright (c) 201 3Wildfire Games1 /* Copyright (c) 2016 Wildfire Games 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the … … 22 22 23 23 #include "lib/self_test.h" 24 24 25 #include "lib/file/vfs/vfs_tree.h"26 25 #include "lib/file/common/file_loader.h" 26 #include "lib/file/vfs/vfs.h" 27 #include "lib/file/vfs/vfs_lookup.h" 28 #include "lib/file/vfs/vfs_tree.h" 27 29 28 30 class MockLoader : public IFileLoader 29 31 { … … 43 45 44 46 class TestVfsTree : public CxxTest::TestSuite 45 47 { 48 /** 49 * We create a few different "mods" here to test proper .DELETED 50 * behavior. 51 * 52 * To check which file is used we use the priority. 53 * 54 * 1 55 * +--a 56 * +--b/ 57 * | +--a 58 * | \--b/ 59 * | \--a 60 * \--c/ 61 * +--a 62 * \--b 63 * 64 * 2 65 * +--a.DELETED 66 * +--b/ 67 * | +--a 68 * | \--b.DELETED 69 * +--c.DELETED 70 * \--c/ 71 * +--a 72 * \--b 73 * 74 * 3 75 * +--a 76 * \--b/ 77 * \--b/ 78 * \--a 79 */ 80 void mount_mod(size_t mod, VfsDirectory& dir) 81 { 82 size_t priority = mod; 83 PIFileLoader loader(new MockLoader(1)); 84 switch(mod) 85 { 86 case 1: 87 { 88 dir.AddFile(VfsFile("a", 0, 0, priority, loader)); 89 VfsDirectory* b = dir.AddSubdirectory("b"); 90 b->AddFile(VfsFile("a", 0, 0, priority, loader)); 91 VfsDirectory* b_b = b->AddSubdirectory("b"); 92 b_b->AddFile(VfsFile("a", 0, 0, priority, loader)); 93 VfsDirectory* c = dir.AddSubdirectory("c"); 94 c->AddFile(VfsFile("a", 0, 0, priority, loader)); 95 c->AddFile(VfsFile("b", 0, 0, priority, loader)); 96 break; 97 } 98 case 2: 99 { 100 dir.DeleteSubtree(VfsFile("a.DELETED", 0, 0, priority, loader)); 101 VfsDirectory* b = dir.AddSubdirectory("b"); 102 b->AddFile(VfsFile("a", 0, 0, priority, loader)); 103 b->DeleteSubtree(VfsFile("b.DELETED", 0, 0, priority, loader)); 104 dir.DeleteSubtree(VfsFile("c.DELETED", 0, 0, priority, loader)); 105 VfsDirectory* c = dir.AddSubdirectory("c"); 106 c->AddFile(VfsFile("a", 0, 0, priority, loader)); 107 c->AddFile(VfsFile("b", 0, 0, priority, loader)); 108 break; 109 } 110 case 3: 111 { 112 dir.AddFile(VfsFile("a", 0, 0, priority, loader)); 113 VfsDirectory* b = dir.AddSubdirectory("b"); 114 VfsDirectory* b_b = b->AddSubdirectory("b"); 115 b_b->AddFile(VfsFile("a", 0, 0, priority, loader)); 116 break; 117 } 118 NODEFAULT; 119 } 120 } 121 122 void check_priority(VfsDirectory& root, const VfsPath& path, size_t priority) 123 { 124 VfsDirectory* dir; VfsFile* file; 125 TS_ASSERT_OK(vfs_Lookup(path, &root, dir, &file, VFS_LOOKUP_SKIP_POPULATE)); 126 TS_ASSERT_EQUALS(file->Priority(), priority); 127 } 128 129 void file_does_not_exists(VfsDirectory& root, const VfsPath& path) 130 { 131 VfsDirectory* dir; VfsFile* file; 132 TS_ASSERT_EQUALS(vfs_Lookup(path, &root, dir, &file, VFS_LOOKUP_SKIP_POPULATE), ERR::VFS_FILE_NOT_FOUND); 133 } 134 135 void directory_exists(VfsDirectory& root, const VfsPath& path, Status error = INFO::OK) 136 { 137 VfsDirectory* dir; 138 TS_ASSERT_EQUALS(vfs_Lookup(path, &root, dir, nullptr, VFS_LOOKUP_SKIP_POPULATE), error); 139 } 140 46 141 public: 47 142 void test_replacement() 48 143 { … … 62 157 TS_ASSERT_EQUALS(dir.AddFile(file2)->MTime(), file2.MTime()); 63 158 TS_ASSERT_EQUALS(dir.AddFile(file1)->MTime(), file2.MTime()); 64 159 } 160 161 void test_deleted() 162 { 163 VfsDirectory dir; 164 165 mount_mod(1, dir); 166 mount_mod(2, dir); 167 file_does_not_exists(dir, "a"); 168 check_priority(dir, "b/a", 2); 169 directory_exists(dir, "b/b/", ERR::VFS_DIR_NOT_FOUND); 170 directory_exists(dir, "c/"); 171 check_priority(dir, "c/a", 2); 172 check_priority(dir, "c/b", 2); 173 dir.Clear(); 174 175 176 mount_mod(1, dir); 177 mount_mod(2, dir); 178 mount_mod(3, dir); 179 check_priority(dir, "a", 3); 180 check_priority(dir, "b/b/a", 3); 181 dir.Clear(); 182 183 184 mount_mod(1, dir); 185 mount_mod(3, dir); 186 mount_mod(2, dir); 187 check_priority(dir, "a", 3); 188 check_priority(dir, "b/b/a", 3); 189 dir.Clear(); 190 } 65 191 }; -
source/lib/file/vfs/vfs_populate.cpp
1 /* Copyright (c) 201 3Wildfire Games1 /* Copyright (c) 2016 Wildfire Games 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the … … 58 58 DirectoryNames subdirectoryNames; subdirectoryNames.reserve(50); 59 59 RETURN_STATUS_IF_ERR(GetDirectoryEntries(m_realDirectory->Path(), &files, &subdirectoryNames)); 60 60 61 // to support .DELETED files inside archives safely, we need to load62 // archives and loose files in a deterministic order in case they add63 // and then delete the same file (or vice versa, depending on loading64 // order). GetDirectoryEntries has undefined order so sort its output65 std::sort(files.begin(), files.end(), CompareFileInfoByName());66 std::sort(subdirectoryNames.begin(), subdirectoryNames.end());67 61 // Since .DELETED files only remove files in lower priority mods 62 // loose files and archive files have no conflicts so we do not need 63 // to sort them. 64 // We add directories after they might have been removed by .DELETED 65 // files (as they did not contain any files at that point). The order 66 // of GetDirectoryEntries is undefined, but that does not really matter (TODO really?) 67 // so we do not need to sort its output. 68 68 RETURN_STATUS_IF_ERR(AddFiles(files)); 69 69 AddSubdirectories(subdirectoryNames); 70 70 … … 75 75 void AddFile(const CFileInfo& fileInfo) const 76 76 { 77 77 const VfsPath name = fileInfo.Name(); 78 const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), m_realDirectory->Priority(), m_realDirectory); 78 79 if(name.Extension() == L".DELETED") 79 80 { 80 m_directory-> RemoveFile(name.Basename());81 m_directory->DeleteSubtree(file); 81 82 if(!(m_realDirectory->Flags() & VFS_MOUNT_KEEP_DELETED)) 82 83 return; 83 84 } 84 85 85 const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), m_realDirectory->Priority(), m_realDirectory);86 86 m_directory->AddFile(file); 87 87 } 88 88 … … 97 97 WARN_IF_ERR(vfs_Lookup(pathname, this_->m_directory, directory, 0, flags)); 98 98 99 99 const VfsPath name = fileInfo.Name(); 100 const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), this_->m_realDirectory->Priority(), archiveFile); 100 101 if(name.Extension() == L".DELETED") 101 102 { 102 directory-> RemoveFile(name.Basename());103 directory->DeleteSubtree(file); 103 104 if(!(this_->m_realDirectory->Flags() & VFS_MOUNT_KEEP_DELETED)) 104 105 return; 105 106 } 106 107 107 const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), this_->m_realDirectory->Priority(), archiveFile);108 108 directory->AddFile(file); 109 109 } 110 110 -
source/lib/file/vfs/vfs_tree.cpp
1 /* Copyright (c) 201 3Wildfire Games1 /* Copyright (c) 2016 Wildfire Games 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the … … 49 49 { 50 50 } 51 51 52 static bool ShouldDelete(const VfsFile& file, const VfsFile& deletedFile) 53 { 54 // We only check priority here, a .DELETED file in a mod should not 55 // delete files in that mod. For the same reason we ignore loose 56 // .DELETED files next to an archive. 57 return file.Priority() < deletedFile.Priority(); 58 } 52 59 53 60 static bool ShouldReplaceWith(const VfsFile& previousFile, const VfsFile& newFile) 54 61 { … … 78 85 } 79 86 80 87 88 void VfsDirectory::DeleteSubtree(const VfsFile& file) 89 { 90 ENSURE(file.Name().Extension() == L".DELETED"); 91 92 const VfsPath basename = file.Name().Basename(); 93 std::map<VfsPath, VfsFile>::iterator fit = m_files.find(basename); 94 if(fit != m_files.end() && ShouldDelete(fit->second, file)) 95 m_files.erase(basename); 96 97 std::map<VfsPath, VfsDirectory>::iterator dit = m_subdirectories.find(basename); 98 if(dit != m_subdirectories.end() && dit->second.DeleteTree(file)) 99 m_subdirectories.erase(dit); 100 } 101 102 bool VfsDirectory::DeleteTree(const VfsFile& file) 103 { 104 for(std::map<VfsPath, VfsFile>::iterator it = m_files.begin(); it != m_files.end();) 105 if(ShouldDelete(it->second, file)) 106 it = m_files.erase(it); 107 else 108 ++it; 109 110 for(std::map<VfsPath, VfsDirectory>::iterator it = m_subdirectories.begin(); it != m_subdirectories.end();) 111 if(it->second.DeleteTree(file)) 112 it = m_subdirectories.erase(it); 113 else 114 ++it; 115 116 return m_files.empty() && m_subdirectories.empty(); 117 } 118 119 81 120 VfsFile* VfsDirectory::AddFile(const VfsFile& file) 82 121 { 83 122 std::pair<VfsPath, VfsFile> value = std::make_pair(file.Name(), file); … … 122 161 return &it->second; 123 162 } 124 163 125 126 164 VfsDirectory* VfsDirectory::GetSubdirectory(const VfsPath& name) 127 165 { 128 166 VfsSubdirectories::iterator it = m_subdirectories.find(name.string()); -
source/lib/file/vfs/vfs_tree.h
1 /* Copyright (c) 201 0Wildfire Games1 /* Copyright (c) 2016 Wildfire Games 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the … … 77 77 78 78 class VfsDirectory 79 79 { 80 /** 81 * remove all files with a lower priority than @p file 82 * and do the same for all subdirectories recursively. 83 * @return true if the directory is empty afterwards 84 **/ 85 bool DeleteTree(const VfsFile& file); 86 80 87 public: 81 88 typedef std::map<VfsPath, VfsFile> VfsFiles; 82 89 typedef std::map<VfsPath, VfsDirectory> VfsSubdirectories; … … 84 91 VfsDirectory(); 85 92 86 93 /** 94 * remove the given file or subdirectory according to the priority of the 95 * passed .DELETED file. 96 * CAUTION: Invalidates all previously returned pointers of the file or 97 * subdirectory (and contents) if those have lower priority 98 * than @p file. 99 **/ 100 void DeleteSubtree(const VfsFile& file); 101 102 /** 87 103 * @return address of existing or newly inserted file. 88 104 **/ 89 105 VfsFile* AddFile(const VfsFile& file); -
source/ps/ArchiveBuilder.cpp
1 /* Copyright (C) 201 4Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 77 77 78 78 CXeromyces xero; 79 79 80 for ( size_t i = 0; i < m_Files.size(); ++i)80 for (const VfsPath& path : m_Files) 81 81 { 82 82 Status ret; 83 84 const VfsPath path = m_Files[i];85 83 OsPath realPath; 86 84 ret = m_VFS->GetRealPath(path, realPath); 87 85 ENSURE(ret == INFO::OK);