GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository_util.cc
Date: 2026-10-04 02:40:33
Exec Total Coverage
Lines: 0 119 0.0%
Branches: 0 232 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "repository_util.h"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11
12 #include <cstdio>
13 #include <map>
14 #include <set>
15 #include <string>
16 #include <vector>
17
18 #include "crypto/hash.h"
19 #include "publish/except.h"
20 #include "util/logging.h"
21 #include "util/posix.h"
22 #include "util/string.h"
23
24 namespace publish {
25
26 ✗ CheckoutMarker *CheckoutMarker::CreateFrom(const std::string &path) {
27 ✗ if (!FileExists(path))
28 ✗ return NULL;
29
30 ✗ FILE *f = fopen(path.c_str(), "r");
31 ✗ if (f == NULL)
32 ✗ throw publish::EPublish("cannot open checkout marker");
33 ✗ std::string line;
34 ✗ const bool retval = GetLineFile(f, &line);
35 ✗ fclose(f);
36 ✗ if (!retval)
37 ✗ throw publish::EPublish("empty checkout marker");
38 ✗ line = Trim(line, true /* trim_newline */);
39 ✗ std::vector<std::string> tokens = SplitString(line, ' ');
40 ✗ std::string previous_branch;
41 ✗ if (tokens.size() == 4)
42 ✗ previous_branch = tokens[3];
43 ✗ if (tokens.size() < 3 || tokens.size() > 4)
44 ✗ throw publish::EPublish("checkout marker not parsable: " + line);
45
46 CheckoutMarker *marker = new CheckoutMarker(
47 ✗ tokens[0], tokens[2],
48 ✗ shash::MkFromHexPtr(shash::HexPtr(tokens[1]), shash::kSuffixCatalog),
49 ✗ previous_branch);
50 ✗ return marker;
51 }
52
53 ✗ void CheckoutMarker::SaveAs(const std::string &path) const {
54 ✗ std::string marker = tag_ + " " + hash_.ToString(false /* with_suffix */)
55 ✗ + " " + branch_;
56 ✗ if (!previous_branch_.empty())
57 ✗ marker += " " + previous_branch_;
58 ✗ marker += "\n";
59 ✗ SafeWriteToFile(marker, path, kDefaultFileMode);
60 }
61
62
63 //------------------------------------------------------------------------------
64
65
66 ✗ void ServerLockFile::Lock() {
67 ✗ if (!TryLock()) {
68 ✗ throw EPublish("Could not acquire lock " + path_,
69 ✗ EPublish::kFailTransactionState);
70 }
71 }
72
73
74 ✗ bool ServerLockFile::TryLock() {
75 ✗ const int new_fd = TryLockFile(path_);
76 ✗ if (new_fd >= 0) {
77 ✗ assert(fd_ < 0);
78 ✗ fd_ = new_fd;
79 ✗ return true;
80 ✗ } else if (new_fd == -1) {
81 ✗ throw EPublish("Error while attempting to acquire lock " + path_);
82 } else {
83 ✗ return false;
84 }
85 }
86
87
88 ✗ void ServerLockFile::Touch() {
89 ✗ if (fd_ >= 0)
90 ✗ return;
91 // Pre-create the lock file without locking it, so that a subsequent Lock()
92 // can open the existing file even when the disk is full (e.g. during abort
93 // after the repository's spool area has been filled up).
94 ✗ const int fd = open(path_.c_str(), O_WRONLY | O_CREAT, 0600);
95 ✗ if (fd >= 0) {
96 ✗ close(fd);
97 } else {
98 ✗ LogCvmfs(kLogCvmfs, kLogSyslogWarn,
99 "failed to pre-create lock file %s (errno: %d)",
100 ✗ path_.c_str(), errno);
101 }
102 }
103
104
105 ✗ void ServerLockFile::Unlock() {
106 ✗ const int old_fd = fd_;
107 ✗ assert(old_fd >= 0);
108 ✗ fd_ = -1;
109 ✗ unlink(path_.c_str());
110 ✗ close(old_fd);
111 }
112
113
114 //------------------------------------------------------------------------------
115
116
117 ✗ void ServerFlagFile::Set() {
118 ✗ const int fd = open(path_.c_str(), O_CREAT | O_RDWR, 0600);
119 ✗ if (fd < 0)
120 ✗ throw EPublish("cannot create flag file " + path_);
121 ✗ close(fd);
122 }
123
124
125 ✗ void ServerFlagFile::Clear() { unlink(path_.c_str()); }
126
127
128 ✗ bool ServerFlagFile::IsSet() const { return FileExists(path_); }
129
130
131 //------------------------------------------------------------------------------
132
133
134 ✗ void RunSuidHelper(const std::string &verb, const std::string &fqrn) {
135 ✗ std::vector<std::string> cmd_line;
136 ✗ cmd_line.push_back("/usr/bin/cvmfs_suid_helper");
137 ✗ cmd_line.push_back(verb);
138 ✗ cmd_line.push_back(fqrn);
139 ✗ std::set<int> preserved_fds;
140 ✗ preserved_fds.insert(1);
141 ✗ preserved_fds.insert(2);
142 pid_t child_pid;
143 ✗ const bool retval = ManagedExec(cmd_line, preserved_fds, std::map<int, int>(),
144 false /* drop_credentials */,
145 true /* clear_env */, false /* double_fork */,
146 &child_pid);
147 ✗ if (!retval)
148 ✗ throw EPublish("cannot spawn suid helper");
149 ✗ const int exit_code = WaitForChild(child_pid);
150 ✗ if (exit_code != 0)
151 ✗ throw EPublish("error calling suid helper: " + StringifyInt(exit_code));
152 }
153
154
155 ✗ void SetInConfig(const std::string &path, const std::string &key,
156 const std::string &value) {
157 ✗ const int fd = open(path.c_str(), O_RDWR | O_CREAT, kDefaultFileMode);
158 ✗ if (fd < 0)
159 ✗ throw EPublish("cannot modify configuration file " + path);
160
161 ✗ std::string new_content;
162 ✗ std::string line;
163 ✗ bool key_exists = false;
164 ✗ while (GetLineFd(fd, &line)) {
165 ✗ const std::string trimmed = Trim(line);
166 ✗ if (HasPrefix(trimmed, key + "=", false /* ignore_case */)) {
167 ✗ key_exists = true;
168 ✗ if (!value.empty())
169 ✗ new_content += key + "=" + value + "\n";
170 } else {
171 ✗ new_content += line + "\n";
172 }
173 }
174 ✗ if (!key_exists && !value.empty())
175 ✗ new_content += key + "=" + value + "\n";
176
177 ✗ const off_t off_zero = lseek(fd, 0, SEEK_SET);
178 ✗ if (off_zero != 0) {
179 ✗ close(fd);
180 ✗ throw EPublish("cannot rewind configuration file " + path);
181 }
182 ✗ const int rvi = ftruncate(fd, 0);
183 ✗ if (rvi != 0) {
184 ✗ close(fd);
185 ✗ throw EPublish("cannot truncate configuration file " + path);
186 }
187 ✗ const bool rvb = SafeWrite(fd, new_content.data(), new_content.length());
188 ✗ close(fd);
189 ✗ if (!rvb)
190 ✗ throw EPublish("cannot rewrite configuration file " + path);
191 }
192
193
194 ✗ std::string SendTalkCommand(const std::string &socket, const std::string &cmd) {
195 ✗ const int fd = ConnectSocket(socket);
196 ✗ if (fd < 0) {
197 ✗ if (errno == ENOENT)
198 ✗ throw EPublish("Socket " + socket + " not found");
199 ✗ throw EPublish("Socket " + socket + " inaccessible");
200 }
201
202 ✗ WritePipe(fd, cmd.data(), cmd.size());
203
204 ✗ std::string result;
205 char buf;
206 int retval;
207 ✗ while ((retval = read(fd, &buf, 1)) == 1) {
208 ✗ result.push_back(buf);
209 }
210 ✗ close(fd);
211 ✗ if (retval != 0)
212 ✗ throw EPublish("Broken socket: " + socket);
213
214 ✗ return result;
215 }
216
217 } // namespace publish
218