GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* This file is part of the CernVM File System. |
||
3 |
* |
||
4 |
* Data wrappers for single dentries. In addition to the normal file meta data |
||
5 |
* it manages bookkeeping data specific to cvmfs such as the associated catalog. |
||
6 |
*/ |
||
7 |
|||
8 |
#ifndef CVMFS_DIRECTORY_ENTRY_H_ |
||
9 |
#define CVMFS_DIRECTORY_ENTRY_H_ |
||
10 |
|||
11 |
#include <sys/types.h> |
||
12 |
|||
13 |
#include <cassert> |
||
14 |
#include <cstring> |
||
15 |
#include <string> |
||
16 |
#include <vector> |
||
17 |
|||
18 |
#include "bigvector.h" |
||
19 |
#include "compression.h" |
||
20 |
#include "hash.h" |
||
21 |
#include "platform.h" |
||
22 |
#include "shortstring.h" |
||
23 |
|||
24 |
namespace publish { |
||
25 |
class SyncItem; |
||
26 |
class SyncItemNative; |
||
27 |
class SyncItemTar; |
||
28 |
class SyncItemDummyDir; |
||
29 |
} |
||
30 |
namespace swissknife { |
||
31 |
class CommandMigrate; |
||
32 |
} |
||
33 |
|||
34 |
namespace catalog { |
||
35 |
|||
36 |
// Create DirectoryEntries for unit test purposes. |
||
37 |
class DirectoryEntryTestFactory; |
||
38 |
|||
39 |
class MockCatalogManager; |
||
40 |
class Catalog; |
||
41 |
class WritableCatalogManager; |
||
42 |
|||
43 |
template <class CatalogMgrT> |
||
44 |
class CatalogBalancer; |
||
45 |
typedef uint64_t inode_t; |
||
46 |
|||
47 |
enum SpecialDirents { |
||
48 |
kDirentNormal = 0, |
||
49 |
kDirentNegative, |
||
50 |
}; |
||
51 |
|||
52 |
/** |
||
53 |
* Wrapper around struct dirent. Only contains file system related meta data |
||
54 |
* for a directory entry. |
||
55 |
* TODO(jblomer): separation to DirectoryEntry not quite clear: this one also |
||
56 |
* contains hash, compression algorithm and external flag |
||
57 |
*/ |
||
58 |
✗✗✗✗ ✓✗✗✗ |
2184798 |
class DirectoryEntryBase { |
59 |
// For testing the catalog balancing |
||
60 |
friend class CatalogBalancer<MockCatalogManager>; |
||
61 |
// Create .cvmfscatalog and .cvmfsautocatalog files |
||
62 |
friend class CatalogBalancer<WritableCatalogManager>; |
||
63 |
// Simplify creation of DirectoryEntry objects for write back |
||
64 |
friend class publish::SyncItem; |
||
65 |
friend class publish::SyncItemNative; |
||
66 |
friend class publish::SyncItemTar; |
||
67 |
friend class publish::SyncItemDummyDir; |
||
68 |
// Simplify file system like _touch_ of DirectoryEntry objects |
||
69 |
friend class SqlDirentTouch; |
||
70 |
// Allow creation of virtual directories and files |
||
71 |
friend class VirtualCatalog; |
||
72 |
|||
73 |
public: |
||
74 |
static const inode_t kInvalidInode = 0; |
||
75 |
|||
76 |
/** |
||
77 |
* Used in the swissknife for sanity checks and catalog migration. If |
||
78 |
* anything is added, also adjust PrintDifferences in swissknife::CommandDiff. |
||
79 |
*/ |
||
80 |
struct Difference { |
||
81 |
static const unsigned int kIdentical = 0x000; |
||
82 |
static const unsigned int kName = 0x001; |
||
83 |
static const unsigned int kLinkcount = 0x002; |
||
84 |
static const unsigned int kSize = 0x004; |
||
85 |
static const unsigned int kMode = 0x008; |
||
86 |
static const unsigned int kMtime = 0x010; |
||
87 |
static const unsigned int kSymlink = 0x020; |
||
88 |
static const unsigned int kChecksum = 0x040; |
||
89 |
static const unsigned int kHardlinkGroup = 0x080; |
||
90 |
static const unsigned int kNestedCatalogTransitionFlags = 0x100; |
||
91 |
static const unsigned int kChunkedFileFlag = 0x200; |
||
92 |
static const unsigned int kHasXattrsFlag = 0x400; |
||
93 |
static const unsigned int kExternalFileFlag = 0x800; |
||
94 |
static const unsigned int kBindMountpointFlag = 0x1000; |
||
95 |
static const unsigned int kHiddenFlag = 0x2000; |
||
96 |
}; |
||
97 |
typedef unsigned int Differences; |
||
98 |
|||
99 |
/** |
||
100 |
* Zero-constructed DirectoryEntry objects are unusable as such. |
||
101 |
*/ |
||
102 |
2182995 |
inline DirectoryEntryBase() |
|
103 |
: inode_(kInvalidInode) |
||
104 |
, mode_(0) |
||
105 |
, uid_(0) |
||
106 |
, gid_(0) |
||
107 |
, size_(0) |
||
108 |
, mtime_(0) |
||
109 |
, linkcount_(1) // generally a normal file has linkcount 1 -> default |
||
110 |
, has_xattrs_(false) |
||
111 |
, is_external_file_(false) |
||
112 |
2182995 |
, compression_algorithm_(zlib::kZlibDefault) |
|
113 |
2182995 |
{ } |
|
114 |
|||
115 |
411 |
inline bool IsRegular() const { return S_ISREG(mode_); } |
|
116 |
566 |
inline bool IsLink() const { return S_ISLNK(mode_); } |
|
117 |
513 |
inline bool IsDirectory() const { return S_ISDIR(mode_); } |
|
118 |
207 |
inline bool IsFifo() const { return S_ISFIFO(mode_); } |
|
119 |
203 |
inline bool IsSocket() const { return S_ISSOCK(mode_); } |
|
120 |
526 |
inline bool IsCharDev() const { return S_ISCHR(mode_); } |
|
121 |
526 |
inline bool IsBlockDev() const { return S_ISBLK(mode_); } |
|
122 |
207 |
inline bool IsSpecial() const { |
|
123 |
✓✓✓✗ ✓✗✗✓ |
207 |
return IsFifo() || IsSocket() || IsCharDev() || IsBlockDev(); |
124 |
} |
||
125 |
284 |
inline bool IsExternalFile() const { return is_external_file_; } |
|
126 |
330 |
inline bool HasXattrs() const { return has_xattrs_; } |
|
127 |
|||
128 |
197 |
inline inode_t inode() const { return inode_; } |
|
129 |
146 |
inline uint32_t linkcount() const { return linkcount_; } |
|
130 |
541 |
inline NameString name() const { return name_; } |
|
131 |
52 |
inline LinkString symlink() const { return symlink_; } |
|
132 |
46 |
inline time_t mtime() const { return mtime_; } |
|
133 |
46 |
inline unsigned int mode() const { return mode_; } |
|
134 |
34 |
inline uid_t uid() const { return uid_; } |
|
135 |
34 |
inline gid_t gid() const { return gid_; } |
|
136 |
87 |
inline shash::Any checksum() const { return checksum_; } |
|
137 |
364 |
inline const shash::Any *checksum_ptr() const { return &checksum_; } |
|
138 |
inline shash::Algorithms hash_algorithm() const { |
||
139 |
return checksum_.algorithm; |
||
140 |
} |
||
141 |
296 |
inline uint64_t size() const { |
|
142 |
✓✓ | 296 |
if (IsLink()) |
143 |
4 |
return symlink().GetLength(); |
|
144 |
✓✗✗✓ ✗✓ |
292 |
if (IsBlockDev() || IsCharDev()) |
145 |
return 0; |
||
146 |
292 |
return size_; |
|
147 |
} |
||
148 |
31 |
inline dev_t rdev() const { |
|
149 |
✓✗✗✓ ✗✓ |
31 |
if (IsBlockDev() || IsCharDev()) |
150 |
return size_; |
||
151 |
31 |
return 1; |
|
152 |
} |
||
153 |
150 |
inline std::string GetFullPath(const std::string &parent_directory) const { |
|
154 |
150 |
std::string file_path = parent_directory + "/"; |
|
155 |
150 |
file_path.append(name().GetChars(), name().GetLength()); |
|
156 |
150 |
return file_path; |
|
157 |
} |
||
158 |
|||
159 |
10 |
inline void set_inode(const inode_t inode) { inode_ = inode; } |
|
160 |
71 |
inline void set_linkcount(const uint32_t linkcount) { |
|
161 |
✗✓ | 71 |
assert(linkcount > 0); |
162 |
71 |
linkcount_ = linkcount; |
|
163 |
71 |
} |
|
164 |
inline void set_symlink(const LinkString &symlink) { |
||
165 |
symlink_ = symlink; |
||
166 |
} |
||
167 |
176 |
inline void set_has_xattrs(const bool has_xattrs) { |
|
168 |
176 |
has_xattrs_ = has_xattrs; |
|
169 |
176 |
} |
|
170 |
|||
171 |
111 |
inline zlib::Algorithms compression_algorithm() const { |
|
172 |
111 |
return compression_algorithm_; |
|
173 |
} |
||
174 |
|||
175 |
/** |
||
176 |
* Converts to a stat struct as required by many Fuse callbacks. |
||
177 |
* @return the struct stat for this DirectoryEntry |
||
178 |
*/ |
||
179 |
29 |
inline struct stat GetStatStructure() const { |
|
180 |
struct stat s; |
||
181 |
29 |
memset(&s, 0, sizeof(s)); |
|
182 |
29 |
s.st_dev = 1; |
|
183 |
29 |
s.st_ino = inode_; |
|
184 |
29 |
s.st_mode = mode_; |
|
185 |
29 |
s.st_nlink = linkcount(); |
|
186 |
29 |
s.st_uid = uid(); |
|
187 |
29 |
s.st_gid = gid(); |
|
188 |
29 |
s.st_rdev = rdev(); |
|
189 |
29 |
s.st_size = size(); |
|
190 |
29 |
s.st_blksize = 4096; // will be ignored by Fuse |
|
191 |
29 |
s.st_blocks = 1 + size() / 512; |
|
192 |
29 |
s.st_atime = mtime_; |
|
193 |
29 |
s.st_mtime = mtime_; |
|
194 |
29 |
s.st_ctime = mtime_; |
|
195 |
29 |
return s; |
|
196 |
} |
||
197 |
|||
198 |
Differences CompareTo(const DirectoryEntryBase &other) const; |
||
199 |
inline bool operator ==(const DirectoryEntryBase &other) const { |
||
200 |
return CompareTo(other) == Difference::kIdentical; |
||
201 |
} |
||
202 |
inline bool operator !=(const DirectoryEntryBase &other) const { |
||
203 |
return !(*this == other); |
||
204 |
} |
||
205 |
|||
206 |
protected: |
||
207 |
// Inodes are generated based on the rowid of the entry in the file catalog. |
||
208 |
inode_t inode_; |
||
209 |
|||
210 |
// Data from struct stat |
||
211 |
NameString name_; |
||
212 |
unsigned int mode_; |
||
213 |
uid_t uid_; |
||
214 |
gid_t gid_; |
||
215 |
uint64_t size_; |
||
216 |
time_t mtime_; |
||
217 |
LinkString symlink_; |
||
218 |
uint32_t linkcount_; |
||
219 |
// In order to save memory, we only indicate if a directory entry has custom |
||
220 |
// extended attributes. Another call to the file catalog is necessary to |
||
221 |
// get them. |
||
222 |
bool has_xattrs_; |
||
223 |
|||
224 |
// The cryptographic hash is not part of the file system intrinsics, though |
||
225 |
// it can be computed just using the file contents. We therefore put it in |
||
226 |
// this base class. |
||
227 |
shash::Any checksum_; |
||
228 |
|||
229 |
bool is_external_file_; |
||
230 |
|||
231 |
// The compression algorithm |
||
232 |
zlib::Algorithms compression_algorithm_; |
||
233 |
}; |
||
234 |
|||
235 |
|||
236 |
/** |
||
237 |
* In addition to the file system meta-data covered by DirectoryEntryBase, |
||
238 |
* DirectoryEntries contain cvmfs-specific meta data. Currently these are the |
||
239 |
* following things: |
||
240 |
* - Pointer to the originating catalog |
||
241 |
* - Markers for nested catalog transition points (mountpoint and root entry) |
||
242 |
* - Transient marker storing the time of caching (Fuse page caches). |
||
243 |
* This is required to invalidate caches after a catalog update |
||
244 |
* - Hardlink group used to emulate hardlinks in cvmfs |
||
245 |
*/ |
||
246 |
2184720 |
class DirectoryEntry : public DirectoryEntryBase { |
|
247 |
// Simplify creation of DirectoryEntry objects |
||
248 |
friend class SqlLookup; |
||
249 |
// Simplify write of DirectoryEntry objects in database |
||
250 |
friend class SqlDirentWrite; |
||
251 |
// For fixing DirectoryEntry glitches |
||
252 |
friend class swissknife::CommandMigrate; |
||
253 |
// TODO(rmeusel): remove this dependency |
||
254 |
friend class WritableCatalogManager; |
||
255 |
// Create DirectoryEntries for unit test purposes. |
||
256 |
friend class DirectoryEntryTestFactory; |
||
257 |
|||
258 |
public: |
||
259 |
/** |
||
260 |
* This is _kind of_ a copy constructor allowing us to create |
||
261 |
* DirectoryEntries directly from DirectoryEntryBase objects. We make it |
||
262 |
* explicit, to disallow black magic from happening. It uses the copy |
||
263 |
* constructor of DirectoryEntryBase and initializes the additional fields of |
||
264 |
* DirectoryEntry. |
||
265 |
*/ |
||
266 |
74 |
inline explicit DirectoryEntry(const DirectoryEntryBase& base) |
|
267 |
: DirectoryEntryBase(base) |
||
268 |
, hardlink_group_(0) |
||
269 |
, is_nested_catalog_root_(false) |
||
270 |
, is_nested_catalog_mountpoint_(false) |
||
271 |
, is_bind_mountpoint_(false) |
||
272 |
, is_chunked_file_(false) |
||
273 |
, is_hidden_(false) |
||
274 |
74 |
, is_negative_(false) { } |
|
275 |
|||
276 |
2182908 |
inline DirectoryEntry() |
|
277 |
: hardlink_group_(0) |
||
278 |
, is_nested_catalog_root_(false) |
||
279 |
, is_nested_catalog_mountpoint_(false) |
||
280 |
, is_bind_mountpoint_(false) |
||
281 |
, is_chunked_file_(false) |
||
282 |
, is_hidden_(false) |
||
283 |
2182908 |
, is_negative_(false) { } |
|
284 |
|||
285 |
85 |
inline explicit DirectoryEntry(SpecialDirents special_type) |
|
286 |
: hardlink_group_(0) |
||
287 |
, is_nested_catalog_root_(false) |
||
288 |
, is_nested_catalog_mountpoint_(false) |
||
289 |
, is_bind_mountpoint_(false) |
||
290 |
, is_chunked_file_(false) |
||
291 |
, is_hidden_(false) |
||
292 |
✗✓ | 85 |
, is_negative_(true) { assert(special_type == kDirentNegative); } |
293 |
|||
294 |
13 |
inline SpecialDirents GetSpecial() const { |
|
295 |
✓✓ | 13 |
return is_negative_ ? kDirentNegative : kDirentNormal; |
296 |
} |
||
297 |
|||
298 |
Differences CompareTo(const DirectoryEntry &other) const; |
||
299 |
inline bool operator ==(const DirectoryEntry &other) const { |
||
300 |
return CompareTo(other) == Difference::kIdentical; |
||
301 |
} |
||
302 |
inline bool operator !=(const DirectoryEntry &other) const { |
||
303 |
return !(*this == other); |
||
304 |
} |
||
305 |
|||
306 |
64 |
inline bool IsNegative() const { return is_negative_; } |
|
307 |
400 |
inline bool IsNestedCatalogRoot() const { return is_nested_catalog_root_; } |
|
308 |
366 |
inline bool IsNestedCatalogMountpoint() const { |
|
309 |
366 |
return is_nested_catalog_mountpoint_; |
|
310 |
} |
||
311 |
304 |
inline bool IsBindMountpoint() const { return is_bind_mountpoint_; } |
|
312 |
549 |
inline bool IsChunkedFile() const { return is_chunked_file_; } |
|
313 |
357 |
inline bool IsHidden() const { return is_hidden_; } |
|
314 |
44 |
inline uint32_t hardlink_group() const { return hardlink_group_; } |
|
315 |
|||
316 |
inline void set_hardlink_group(const uint32_t group) { |
||
317 |
hardlink_group_ = group; |
||
318 |
} |
||
319 |
7 |
inline void set_is_nested_catalog_mountpoint(const bool val) { |
|
320 |
7 |
is_nested_catalog_mountpoint_ = val; |
|
321 |
7 |
} |
|
322 |
7 |
inline void set_is_nested_catalog_root(const bool val) { |
|
323 |
7 |
is_nested_catalog_root_ = val; |
|
324 |
7 |
} |
|
325 |
inline void set_is_bind_mountpoint(const bool val) { |
||
326 |
is_bind_mountpoint_ = val; |
||
327 |
} |
||
328 |
80 |
inline void set_is_chunked_file(const bool val) { |
|
329 |
80 |
is_chunked_file_ = val; |
|
330 |
80 |
} |
|
331 |
inline void set_is_hidden(const bool val) { |
||
332 |
is_hidden_ = val; |
||
333 |
} |
||
334 |
|||
335 |
private: |
||
336 |
/** |
||
337 |
* Hardlink handling is emulated in CVMFS. Since inodes are allocated on |
||
338 |
* demand we save hardlink relationships using the same hardlink_group. |
||
339 |
*/ |
||
340 |
uint32_t hardlink_group_; |
||
341 |
|||
342 |
// TODO(jblomer): transform into bitfield to save memory |
||
343 |
bool is_nested_catalog_root_; |
||
344 |
bool is_nested_catalog_mountpoint_; |
||
345 |
bool is_bind_mountpoint_; |
||
346 |
bool is_chunked_file_; |
||
347 |
bool is_hidden_; |
||
348 |
bool is_negative_; |
||
349 |
}; |
||
350 |
|||
351 |
|||
352 |
/** |
||
353 |
* Saves memory for large directory listings. |
||
354 |
*/ |
||
355 |
22 |
struct StatEntry { |
|
356 |
NameString name; |
||
357 |
struct stat info; |
||
358 |
|||
359 |
4 |
StatEntry() { memset(&info, 0, sizeof(info)); } |
|
360 |
StatEntry(const NameString &n, const struct stat &i) : name(n), info(i) { } |
||
361 |
}; |
||
362 |
|||
363 |
|||
364 |
typedef std::vector<DirectoryEntry> DirectoryEntryList; |
||
365 |
typedef std::vector<DirectoryEntryBase> DirectoryEntryBaseList; |
||
366 |
// TODO(jblomer): use mmap for large listings |
||
367 |
typedef BigVector<StatEntry> StatEntryList; |
||
368 |
|||
369 |
} // namespace catalog |
||
370 |
|||
371 |
#endif // CVMFS_DIRECTORY_ENTRY_H_ |
Generated by: GCOVR (Version 4.1) |