GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/swissknife_diff_tool.cc Lines: 0 94 0.0 %
Date: 2019-02-03 02:48:13 Branches: 0 122 0.0 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#define __STDC_FORMAT_MACROS
6
7
#include "swissknife_diff_tool.h"
8
9
#include <inttypes.h>
10
#include <stdint.h>
11
#include "cvmfs_config.h"
12
13
#include <vector>
14
15
#include "directory_entry.h"
16
#include "download.h"
17
#include "statistics.h"
18
19
namespace swissknife {
20
21
DiffTool::DiffTool(const std::string &repo_path,
22
                   const history::History::Tag &old_tag,
23
                   const history::History::Tag &new_tag,
24
                   const std::string &temp_dir,
25
                   download::DownloadManager *download_manager,
26
                   perf::Statistics *statistics,
27
                   bool machine_readable,
28
                   bool ignore_timediff)
29
    : CatalogDiffTool<catalog::SimpleCatalogManager>(
30
          repo_path, old_tag.root_hash, new_tag.root_hash, temp_dir,
31
          download_manager),
32
      old_tag_(old_tag),
33
      new_tag_(new_tag),
34
      machine_readable_(machine_readable),
35
      ignore_timediff_(ignore_timediff)
36
{
37
    // Created here but ownership goes to the Statistics class
38
    // owned by the server tool.
39
    counter_total_added_ = statistics->Register("difftool.added_bytes",
40
                                                "Total number of bytes added");
41
    counter_total_removed_ = statistics->Register("difftool.removed_bytes",
42
                                                  "Total number of bytes "
43
                                                  "removed");
44
}
45
46
DiffTool::~DiffTool() {}
47
48
std::string DiffTool::PrintEntryType(const catalog::DirectoryEntry &entry) {
49
  if (entry.IsRegular())
50
    return machine_readable_ ? "F" : "file";
51
  else if (entry.IsLink())
52
    return machine_readable_ ? "S" : "symlink";
53
  else if (entry.IsDirectory())
54
    return machine_readable_ ? "D" : "directory";
55
  else
56
    return machine_readable_ ? "U" : "unknown";
57
}
58
59
std::string DiffTool::PrintDifferences(
60
    catalog::DirectoryEntryBase::Differences diff) {
61
  vector<string> result_list;
62
  if (diff & catalog::DirectoryEntryBase::Difference::kName)
63
    result_list.push_back(machine_readable_ ? "N" : "name");
64
  if (diff & catalog::DirectoryEntryBase::Difference::kLinkcount)
65
    result_list.push_back(machine_readable_ ? "I" : "link-count");
66
  if (diff & catalog::DirectoryEntryBase::Difference::kSize)
67
    result_list.push_back(machine_readable_ ? "S" : "size");
68
  if (diff & catalog::DirectoryEntryBase::Difference::kMode)
69
    result_list.push_back(machine_readable_ ? "M" : "mode");
70
  if (diff & catalog::DirectoryEntryBase::Difference::kMtime)
71
    result_list.push_back(machine_readable_ ? "T" : "timestamp");
72
  if (diff & catalog::DirectoryEntryBase::Difference::kSymlink)
73
    result_list.push_back(machine_readable_ ? "L" : "symlink-target");
74
  if (diff & catalog::DirectoryEntryBase::Difference::kChecksum)
75
    result_list.push_back(machine_readable_ ? "C" : "content");
76
  if (diff & catalog::DirectoryEntryBase::Difference::kHardlinkGroup)
77
    result_list.push_back(machine_readable_ ? "G" : "hardlink-group");
78
  if (diff &
79
      catalog::DirectoryEntryBase::Difference::kNestedCatalogTransitionFlags) {
80
    result_list.push_back(machine_readable_ ? "N" : "nested-catalog");
81
  }
82
  if (diff & catalog::DirectoryEntryBase::Difference::kChunkedFileFlag)
83
    result_list.push_back(machine_readable_ ? "P" : "chunked-file");
84
  if (diff & catalog::DirectoryEntryBase::Difference::kHasXattrsFlag)
85
    result_list.push_back(machine_readable_ ? "X" : "xattrs");
86
  if (diff & catalog::DirectoryEntryBase::Difference::kExternalFileFlag)
87
    result_list.push_back(machine_readable_ ? "E" : "external-file");
88
  if (diff & catalog::DirectoryEntryBase::Difference::kBindMountpointFlag)
89
    result_list.push_back(machine_readable_ ? "B" : "bind-mountpoint");
90
  if (diff & catalog::DirectoryEntryBase::Difference::kHiddenFlag)
91
    result_list.push_back(machine_readable_ ? "H" : "hidden");
92
93
  return machine_readable_ ? ("[" + JoinStrings(result_list, "") + "]")
94
                           : (" [" + JoinStrings(result_list, ", ") + "]");
95
}
96
97
void DiffTool::ReportHeader() {
98
  if (machine_readable_) {
99
    LogCvmfs(kLogCvmfs, kLogStdout,
100
             "# line descriptor: A - add, R - remove, M - modify, "
101
             "S - statistics; modify flags: S - size, M - mode, T - timestamp, "
102
             "C - content, L - symlink target; entry types: F - regular file, "
103
             "S - symbolic link, D - directory, N - nested catalog");
104
  } else {
105
    LogCvmfs(kLogCvmfs, kLogStdout, "DELTA: %s/r%u (%s) --> %s/r%u (%s)",
106
             old_tag_.name.c_str(), old_tag_.revision,
107
             StringifyTime(old_tag_.timestamp, true).c_str(),
108
             new_tag_.name.c_str(), new_tag_.revision,
109
             StringifyTime(new_tag_.timestamp, true).c_str());
110
  }
111
}
112
113
void DiffTool::ReportAddition(const PathString &path,
114
                              const catalog::DirectoryEntry &entry,
115
                              const XattrList & /*xattrs*/,
116
                              const FileChunkList& /*chunks*/) {
117
  // XXX careful we're casting silently from usint64 to int64 there...
118
  counter_total_added_->Xadd(entry.size());
119
  string operation = machine_readable_ ? "A" : "add";
120
  if (machine_readable_) {
121
    LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s +%" PRIu64, operation.c_str(),
122
             PrintEntryType(entry).c_str(), path.c_str(), entry.size());
123
  } else {
124
    LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s +%" PRIu64 " bytes",
125
             path.c_str(), operation.c_str(),
126
             PrintEntryType(entry).c_str(), entry.size());
127
  }
128
}
129
130
void DiffTool::ReportRemoval(const PathString &path,
131
                             const catalog::DirectoryEntry &entry) {
132
  // XXX careful we're casting silently from usint64 to int64 there...
133
  counter_total_removed_->Xadd(entry.size());
134
  string operation = machine_readable_ ? "R" : "remove";
135
  if (machine_readable_) {
136
    LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s -%" PRIu64, operation.c_str(),
137
             PrintEntryType(entry).c_str(), path.c_str(), entry.size());
138
  } else {
139
    LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s -%" PRIu64 " bytes",
140
             path.c_str(), operation.c_str(),
141
             PrintEntryType(entry).c_str(), entry.size());
142
  }
143
}
144
145
void DiffTool::ReportModification(const PathString &path,
146
                                  const catalog::DirectoryEntry &entry_from,
147
                                  const catalog::DirectoryEntry &entry_to,
148
                                  const XattrList & /*xattrs*/,
149
                                  const FileChunkList& /*chunks*/) {
150
  catalog::DirectoryEntryBase::Differences diff =
151
      entry_from.CompareTo(entry_to);
152
  if (ignore_timediff_) {
153
    diff = diff & ~catalog::DirectoryEntryBase::Difference::kMtime;
154
    if (diff == 0)
155
      return;
156
  }
157
158
  string type_from = PrintEntryType(entry_from);
159
  string type_to = PrintEntryType(entry_to);
160
  string type = type_from;
161
  if (type_from != type_to) {
162
    type += machine_readable_ ? type_to : ("->" + type_to);
163
  }
164
165
  string operation = machine_readable_ ? "M" : "modify";
166
  if (machine_readable_) {
167
    LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %s %s", operation.c_str(),
168
             PrintDifferences(diff).c_str(), type.c_str(), path.c_str());
169
  } else {
170
    LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s%s", path.c_str(),
171
             operation.c_str(), type.c_str(), PrintDifferences(diff).c_str());
172
  }
173
}
174
175
void DiffTool::ReportStats() {
176
  const catalog::Catalog *catalog_from = GetOldCatalog();
177
  const catalog::Catalog *catalog_to = GetNewCatalog();
178
  const catalog::Counters counters_from = catalog_from->GetCounters();
179
  const catalog::Counters counters_to = catalog_to->GetCounters();
180
  catalog::DeltaCounters counters_diff =
181
      catalog::Counters::Diff(counters_from, counters_to);
182
  string operation = machine_readable_ ? "S " : "d(";
183
  string type_file = machine_readable_ ? "F" : "# regular files):";
184
  string type_symlink = machine_readable_ ? "S" : "# symlinks):";
185
  string type_directory = machine_readable_ ? "D" : "# directories):";
186
  string type_catalog = machine_readable_ ? "N" : "# catalogs):";
187
  int64_t diff_file =
188
      counters_diff.self.regular_files + counters_diff.subtree.regular_files;
189
  int64_t diff_symlink =
190
      counters_diff.self.symlinks + counters_diff.subtree.symlinks;
191
  int64_t diff_catalog = counters_diff.self.nested_catalogs +
192
                         counters_diff.subtree.nested_catalogs;
193
  // Nested catalogs make internally two directory entries
194
  int64_t diff_directory = counters_diff.self.directories +
195
                           counters_diff.subtree.directories - diff_catalog;
196
  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
197
           type_file.c_str(), diff_file);
198
  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
199
           type_symlink.c_str(), diff_symlink);
200
  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
201
           type_directory.c_str(), diff_directory);
202
  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
203
           type_catalog.c_str(), diff_catalog);
204
}
205
206
}  // namespace swissknife