GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/directory_entry.h Lines: 91 103 88.3 %
Date: 2019-02-03 02:48:13 Branches: 18 36 50.0 %

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_