GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository_util.cc
Date: 2025-06-29 02:35:41
Exec Total Coverage
Lines: 0 111 0.0%
Branches: 0 228 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/posix.h"
21 #include "util/string.h"
22
23 namespace publish {
24
25 CheckoutMarker *CheckoutMarker::CreateFrom(const std::string &path) {
26 if (!FileExists(path))
27 return NULL;
28
29 FILE *f = fopen(path.c_str(), "r");
30 if (f == NULL)
31 throw publish::EPublish("cannot open checkout marker");
32 std::string line;
33 const bool retval = GetLineFile(f, &line);
34 fclose(f);
35 if (!retval)
36 throw publish::EPublish("empty checkout marker");
37 line = Trim(line, true /* trim_newline */);
38 std::vector<std::string> tokens = SplitString(line, ' ');
39 std::string previous_branch;
40 if (tokens.size() == 4)
41 previous_branch = tokens[3];
42 if (tokens.size() < 3 || tokens.size() > 4)
43 throw publish::EPublish("checkout marker not parsable: " + line);
44
45 CheckoutMarker *marker = new CheckoutMarker(
46 tokens[0], tokens[2],
47 shash::MkFromHexPtr(shash::HexPtr(tokens[1]), shash::kSuffixCatalog),
48 previous_branch);
49 return marker;
50 }
51
52 void CheckoutMarker::SaveAs(const std::string &path) const {
53 std::string marker = tag_ + " " + hash_.ToString(false /* with_suffix */)
54 + " " + branch_;
55 if (!previous_branch_.empty())
56 marker += " " + previous_branch_;
57 marker += "\n";
58 SafeWriteToFile(marker, path, kDefaultFileMode);
59 }
60
61
62 //------------------------------------------------------------------------------
63
64
65 void ServerLockFile::Lock() {
66 if (!TryLock()) {
67 throw EPublish("Could not acquire lock " + path_,
68 EPublish::kFailTransactionState);
69 }
70 }
71
72
73 bool ServerLockFile::TryLock() {
74 const int new_fd = TryLockFile(path_);
75 if (new_fd >= 0) {
76 assert(fd_ < 0);
77 fd_ = new_fd;
78 return true;
79 } else if (new_fd == -1) {
80 throw EPublish("Error while attempting to acquire lock " + path_);
81 } else {
82 return false;
83 }
84 }
85
86
87 void ServerLockFile::Unlock() {
88 const int old_fd = fd_;
89 assert(old_fd >= 0);
90 fd_ = -1;
91 unlink(path_.c_str());
92 close(old_fd);
93 }
94
95
96 //------------------------------------------------------------------------------
97
98
99 void ServerFlagFile::Set() {
100 const int fd = open(path_.c_str(), O_CREAT | O_RDWR, 0600);
101 if (fd < 0)
102 throw EPublish("cannot create flag file " + path_);
103 close(fd);
104 }
105
106
107 void ServerFlagFile::Clear() { unlink(path_.c_str()); }
108
109
110 bool ServerFlagFile::IsSet() const { return FileExists(path_); }
111
112
113 //------------------------------------------------------------------------------
114
115
116 void RunSuidHelper(const std::string &verb, const std::string &fqrn) {
117 std::vector<std::string> cmd_line;
118 cmd_line.push_back("/usr/bin/cvmfs_suid_helper");
119 cmd_line.push_back(verb);
120 cmd_line.push_back(fqrn);
121 std::set<int> preserved_fds;
122 preserved_fds.insert(1);
123 preserved_fds.insert(2);
124 pid_t child_pid;
125 const bool retval = ManagedExec(cmd_line, preserved_fds, std::map<int, int>(),
126 false /* drop_credentials */,
127 true /* clear_env */, false /* double_fork */,
128 &child_pid);
129 if (!retval)
130 throw EPublish("cannot spawn suid helper");
131 const int exit_code = WaitForChild(child_pid);
132 if (exit_code != 0)
133 throw EPublish("error calling suid helper: " + StringifyInt(exit_code));
134 }
135
136
137 void SetInConfig(const std::string &path, const std::string &key,
138 const std::string &value) {
139 const int fd = open(path.c_str(), O_RDWR | O_CREAT, kDefaultFileMode);
140 if (fd < 0)
141 throw EPublish("cannot modify configuration file " + path);
142
143 std::string new_content;
144 std::string line;
145 bool key_exists = false;
146 while (GetLineFd(fd, &line)) {
147 const std::string trimmed = Trim(line);
148 if (HasPrefix(trimmed, key + "=", false /* ignore_case */)) {
149 key_exists = true;
150 if (!value.empty())
151 new_content += key + "=" + value + "\n";
152 } else {
153 new_content += line + "\n";
154 }
155 }
156 if (!key_exists && !value.empty())
157 new_content += key + "=" + value + "\n";
158
159 const off_t off_zero = lseek(fd, 0, SEEK_SET);
160 if (off_zero != 0) {
161 close(fd);
162 throw EPublish("cannot rewind configuration file " + path);
163 }
164 const int rvi = ftruncate(fd, 0);
165 if (rvi != 0) {
166 close(fd);
167 throw EPublish("cannot truncate configuration file " + path);
168 }
169 const bool rvb = SafeWrite(fd, new_content.data(), new_content.length());
170 close(fd);
171 if (!rvb)
172 throw EPublish("cannot rewrite configuration file " + path);
173 }
174
175
176 std::string SendTalkCommand(const std::string &socket, const std::string &cmd) {
177 const int fd = ConnectSocket(socket);
178 if (fd < 0) {
179 if (errno == ENOENT)
180 throw EPublish("Socket " + socket + " not found");
181 throw EPublish("Socket " + socket + " inaccessible");
182 }
183
184 WritePipe(fd, cmd.data(), cmd.size());
185
186 std::string result;
187 char buf;
188 int retval;
189 while ((retval = read(fd, &buf, 1)) == 1) {
190 result.push_back(buf);
191 }
192 close(fd);
193 if (retval != 0)
194 throw EPublish("Broken socket: " + socket);
195
196 return result;
197 }
198
199 } // namespace publish
200