GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* This file is part of the CernVM File System. |
||
3 |
*/ |
||
4 |
|||
5 |
#ifndef CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_ |
||
6 |
#define CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_ |
||
7 |
|||
8 |
#include <string> |
||
9 |
|||
10 |
#include "catalog.h" |
||
11 |
#include "hash.h" |
||
12 |
#include "lease_path_util.h" |
||
13 |
#include "logging.h" |
||
14 |
#include "manifest.h" |
||
15 |
#include "options.h" |
||
16 |
#include "upload.h" |
||
17 |
#include "util/posix.h" |
||
18 |
#include "util/raii_temp_dir.h" |
||
19 |
|||
20 |
5 |
inline PathString MakeRelative(const PathString& path) { |
|
21 |
5 |
std::string rel_path; |
|
22 |
5 |
std::string abs_path = path.ToString(); |
|
23 |
✓✗ | 5 |
if (abs_path[0] == '/') { |
24 |
5 |
rel_path = abs_path.substr(1); |
|
25 |
} else { |
||
26 |
rel_path = abs_path; |
||
27 |
} |
||
28 |
5 |
return PathString(rel_path); |
|
29 |
} |
||
30 |
|||
31 |
2 |
inline void SplitHardlink(catalog::DirectoryEntry* entry) { |
|
32 |
✗✓ | 2 |
if (entry->linkcount() > 1) { |
33 |
LogCvmfs(kLogReceiver, kLogSyslogErr, |
||
34 |
"CatalogMergeTool - Hardlink found: %s. Hardlinks are not " |
||
35 |
"supported when publishing through repository gateway and " |
||
36 |
"will be split.", entry->name().c_str()); |
||
37 |
entry->set_linkcount(1); |
||
38 |
} |
||
39 |
2 |
} |
|
40 |
|||
41 |
2 |
inline void AbortIfHardlinked(const catalog::DirectoryEntry& entry) { |
|
42 |
✗✓ | 2 |
if (entry.linkcount() > 1) { |
43 |
LogCvmfs(kLogReceiver, kLogSyslogErr, |
||
44 |
"CatalogMergeTool - Removal of file %s with linkcount > 1 is " |
||
45 |
"not supported. Aborting", entry.name().c_str()); |
||
46 |
abort(); |
||
47 |
} |
||
48 |
2 |
} |
|
49 |
|||
50 |
namespace receiver { |
||
51 |
|||
52 |
template <typename RwCatalogMgr, typename RoCatalogMgr> |
||
53 |
1 |
bool CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::Run( |
|
54 |
const Params& params, std::string* new_manifest_path) { |
||
55 |
1 |
UniquePtr<upload::Spooler> spooler; |
|
56 |
1 |
perf::Statistics stats; |
|
57 |
1 |
UniquePtr<RaiiTempDir> raii_temp_dir(RaiiTempDir::Create(temp_dir_prefix_)); |
|
58 |
✓✗ | 1 |
if (needs_setup_) { |
59 |
upload::SpoolerDefinition definition( |
||
60 |
params.spooler_configuration, params.hash_alg, params.compression_alg, |
||
61 |
params.generate_legacy_bulk_chunks, params.use_file_chunking, |
||
62 |
params.min_chunk_size, params.avg_chunk_size, params.max_chunk_size, |
||
63 |
1 |
"dummy_token", "dummy_key"); |
|
64 |
1 |
spooler = upload::Spooler::Construct(definition); |
|
65 |
1 |
const std::string temp_dir = raii_temp_dir->dir(); |
|
66 |
1 |
output_catalog_mgr_ = new RwCatalogMgr( |
|
67 |
manifest_->catalog_hash(), repo_path_, temp_dir, spooler, |
||
68 |
download_manager_, params.enforce_limits, params.nested_kcatalog_limit, |
||
69 |
params.root_kcatalog_limit, params.file_mbyte_limit, &stats, |
||
70 |
params.use_autocatalogs, params.max_weight, params.min_weight); |
||
71 |
1 |
output_catalog_mgr_->Init(); |
|
72 |
} |
||
73 |
|||
74 |
1 |
bool ret = CatalogDiffTool<RoCatalogMgr>::Run(PathString("")); |
|
75 |
|||
76 |
1 |
ret &= CreateNewManifest(new_manifest_path); |
|
77 |
|||
78 |
1 |
output_catalog_mgr_.Destroy(); |
|
79 |
|||
80 |
1 |
return ret; |
|
81 |
} |
||
82 |
|||
83 |
template <typename RwCatalogMgr, typename RoCatalogMgr> |
||
84 |
2 |
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportAddition( |
|
85 |
const PathString& path, const catalog::DirectoryEntry& entry, |
||
86 |
const XattrList& xattrs, const FileChunkList& chunks) { |
||
87 |
2 |
const PathString rel_path = MakeRelative(path); |
|
88 |
|||
89 |
/* |
||
90 |
* Note: If the addition of a file or directory outside of the lease |
||
91 |
* path is encountered here, this means that the item was deleted |
||
92 |
* by another writer running concurrently. |
||
93 |
* The correct course of action is to ignore this change here. |
||
94 |
* */ |
||
95 |
✗✓ | 2 |
if (!IsPathInLease(lease_path_, rel_path)) { |
96 |
return; |
||
97 |
} |
||
98 |
|||
99 |
const std::string parent_path = |
||
100 |
✓✗✗✗ ✓✗ |
2 |
std::strchr(rel_path.c_str(), '/') ? GetParentPath(rel_path).c_str() : ""; |
101 |
|||
102 |
✓✓ | 2 |
if (entry.IsDirectory()) { |
103 |
1 |
output_catalog_mgr_->AddDirectory(entry, parent_path); |
|
104 |
✗✓ | 1 |
if (entry.IsNestedCatalogMountpoint()) { |
105 |
output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str())); |
||
106 |
} |
||
107 |
✗✓✗✗ ✓✗ |
1 |
} else if (entry.IsRegular() || entry.IsLink()) { |
108 |
1 |
catalog::DirectoryEntry modified_entry = entry; |
|
109 |
1 |
SplitHardlink(&modified_entry); |
|
110 |
const catalog::DirectoryEntryBase* base_entry = |
||
111 |
1 |
static_cast<const catalog::DirectoryEntryBase*>(&modified_entry); |
|
112 |
✗✓ | 1 |
if (entry.IsChunkedFile()) { |
113 |
assert(!chunks.IsEmpty()); |
||
114 |
output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path, |
||
115 |
chunks); |
||
116 |
} else { |
||
117 |
1 |
output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path); |
|
118 |
} |
||
119 |
} |
||
120 |
} |
||
121 |
|||
122 |
template <typename RwCatalogMgr, typename RoCatalogMgr> |
||
123 |
2 |
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportRemoval( |
|
124 |
const PathString& path, const catalog::DirectoryEntry& entry) { |
||
125 |
2 |
const PathString rel_path = MakeRelative(path); |
|
126 |
|||
127 |
/* |
||
128 |
* Note: If the removal of a file or directory outside of the lease |
||
129 |
* path is encountered here, this means that the item was created |
||
130 |
* by another writer running concurrently. |
||
131 |
* The correct course of action is to ignore this change here. |
||
132 |
* */ |
||
133 |
✗✓ | 2 |
if (!IsPathInLease(lease_path_, rel_path)) { |
134 |
return; |
||
135 |
} |
||
136 |
|||
137 |
✓✓ | 2 |
if (entry.IsDirectory()) { |
138 |
✗✓ | 1 |
if (entry.IsNestedCatalogMountpoint()) { |
139 |
output_catalog_mgr_->RemoveNestedCatalog(std::string(rel_path.c_str()), |
||
140 |
false); |
||
141 |
} |
||
142 |
1 |
output_catalog_mgr_->RemoveDirectory(rel_path.c_str()); |
|
143 |
✗✓✗✗ ✓✗ |
1 |
} else if (entry.IsRegular() || entry.IsLink()) { |
144 |
1 |
AbortIfHardlinked(entry); |
|
145 |
1 |
output_catalog_mgr_->RemoveFile(rel_path.c_str()); |
|
146 |
} |
||
147 |
} |
||
148 |
|||
149 |
template <typename RwCatalogMgr, typename RoCatalogMgr> |
||
150 |
1 |
void CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::ReportModification( |
|
151 |
const PathString& path, const catalog::DirectoryEntry& entry1, |
||
152 |
const catalog::DirectoryEntry& entry2, const XattrList& xattrs, |
||
153 |
const FileChunkList& chunks) { |
||
154 |
1 |
const PathString rel_path = MakeRelative(path); |
|
155 |
|||
156 |
/* |
||
157 |
* Note: If the modification of a file or directory outside of the lease |
||
158 |
* path is encountered here, this means that the item was modified |
||
159 |
* by another writer running concurrently. |
||
160 |
* The correct course of action is to ignore this change here. |
||
161 |
* */ |
||
162 |
✗✓ | 1 |
if (!IsPathInLease(lease_path_, rel_path)) { |
163 |
return; |
||
164 |
} |
||
165 |
|||
166 |
const std::string parent_path = |
||
167 |
✓✗✗✗ ✓✗ |
1 |
std::strchr(rel_path.c_str(), '/') ? GetParentPath(rel_path).c_str() : ""; |
168 |
|||
169 |
✗✓✗✗ ✗✓ |
1 |
if (entry1.IsDirectory() && entry2.IsDirectory()) { |
170 |
// From directory to directory |
||
171 |
const catalog::DirectoryEntryBase* base_entry = |
||
172 |
static_cast<const catalog::DirectoryEntryBase*>(&entry2); |
||
173 |
output_catalog_mgr_->TouchDirectory(*base_entry, rel_path.c_str()); |
||
174 |
if (!entry1.IsNestedCatalogMountpoint() && |
||
175 |
entry2.IsNestedCatalogMountpoint()) { |
||
176 |
output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str())); |
||
177 |
} else if (entry1.IsNestedCatalogMountpoint() && |
||
178 |
!entry2.IsNestedCatalogMountpoint()) { |
||
179 |
output_catalog_mgr_->RemoveNestedCatalog(std::string(rel_path.c_str())); |
||
180 |
} |
||
181 |
✗✓✗✗ ✗✓✗✓ |
1 |
} else if ((entry1.IsRegular() || entry1.IsLink()) && entry2.IsDirectory()) { |
182 |
// From file to directory |
||
183 |
AbortIfHardlinked(entry1); |
||
184 |
output_catalog_mgr_->RemoveFile(rel_path.c_str()); |
||
185 |
output_catalog_mgr_->AddDirectory(entry2, parent_path); |
||
186 |
if (entry2.IsNestedCatalogMountpoint()) { |
||
187 |
output_catalog_mgr_->CreateNestedCatalog(std::string(rel_path.c_str())); |
||
188 |
} |
||
189 |
|||
190 |
✗✓✗✗ ✗✗✗✓ |
1 |
} else if (entry1.IsDirectory() && (entry2.IsRegular() || entry2.IsLink())) { |
191 |
// From directory to file |
||
192 |
catalog::DirectoryEntry modified_entry = entry2; |
||
193 |
SplitHardlink(&modified_entry); |
||
194 |
const catalog::DirectoryEntryBase* base_entry = |
||
195 |
static_cast<const catalog::DirectoryEntryBase*>(&modified_entry); |
||
196 |
output_catalog_mgr_->RemoveDirectory(rel_path.c_str()); |
||
197 |
if (entry2.IsChunkedFile()) { |
||
198 |
assert(!chunks.IsEmpty()); |
||
199 |
output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path, |
||
200 |
chunks); |
||
201 |
} else { |
||
202 |
output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path); |
||
203 |
} |
||
204 |
|||
205 |
✗✓✗✗ ✗✓✗✗ ✓✗ |
1 |
} else if ((entry1.IsRegular() || entry1.IsLink()) && |
206 |
(entry2.IsRegular() || entry2.IsLink())) { |
||
207 |
// From file to file |
||
208 |
1 |
AbortIfHardlinked(entry1); |
|
209 |
1 |
catalog::DirectoryEntry modified_entry = entry2; |
|
210 |
1 |
SplitHardlink(&modified_entry); |
|
211 |
const catalog::DirectoryEntryBase* base_entry = |
||
212 |
1 |
static_cast<const catalog::DirectoryEntryBase*>(&modified_entry); |
|
213 |
1 |
output_catalog_mgr_->RemoveFile(rel_path.c_str()); |
|
214 |
✗✓ | 1 |
if (entry2.IsChunkedFile()) { |
215 |
assert(!chunks.IsEmpty()); |
||
216 |
output_catalog_mgr_->AddChunkedFile(*base_entry, xattrs, parent_path, |
||
217 |
chunks); |
||
218 |
} else { |
||
219 |
1 |
output_catalog_mgr_->AddFile(*base_entry, xattrs, parent_path); |
|
220 |
} |
||
221 |
} |
||
222 |
} |
||
223 |
|||
224 |
template <typename RwCatalogMgr, typename RoCatalogMgr> |
||
225 |
1 |
bool CatalogMergeTool<RwCatalogMgr, RoCatalogMgr>::CreateNewManifest( |
|
226 |
std::string* new_manifest_path) { |
||
227 |
✗✓ | 1 |
if (!output_catalog_mgr_->Commit(false, 0, manifest_)) { |
228 |
LogCvmfs(kLogReceiver, kLogSyslogErr, |
||
229 |
"CatalogMergeTool - Could not commit output catalog"); |
||
230 |
return false; |
||
231 |
} |
||
232 |
|||
233 |
1 |
const std::string new_path = CreateTempPath(temp_dir_prefix_, 0600); |
|
234 |
|||
235 |
✗✓ | 1 |
if (!manifest_->Export(new_path)) { |
236 |
LogCvmfs(kLogReceiver, kLogSyslogErr, |
||
237 |
"CatalogMergeTool - Could not export new manifest"); |
||
238 |
} |
||
239 |
|||
240 |
1 |
*new_manifest_path = new_path; |
|
241 |
|||
242 |
1 |
return true; |
|
243 |
} |
||
244 |
|||
245 |
} // namespace receiver |
||
246 |
|||
247 |
#endif // CVMFS_RECEIVER_CATALOG_MERGE_TOOL_IMPL_H_ |
Generated by: GCOVR (Version 4.1) |