GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/nfs4/nfs4_server.cc
Date: 2026-10-18 02:40:11
Exec Total Coverage
Lines: 980 1390 70.5%
Branches: 799 1651 48.4%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "nfs4/nfs4_server.h"
6
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <sys/stat.h>
10
11 #include <chrono>
12 #include <cstdio>
13 #include <cstring>
14 #include <ctime>
15
16 #include "nfs4/logging.h"
17
18 #ifndef ENODATA
19 #define ENODATA ENOATTR
20 #endif
21
22 namespace nfs4 {
23
24 namespace {
25
26 const uint32_t kMaxName = 255;
27 const uint64_t kAttrDirFileIdBit = 1ull << 63;
28 const uint64_t kNamedAttrFileIdBit = 1ull << 62;
29
30 // Attributes this server can return, as bitmap words 0 and 1
31 const unsigned kSupportedAttrs[] = {FATTR4_SUPPORTED_ATTRS,
32 FATTR4_TYPE,
33 FATTR4_FH_EXPIRE_TYPE,
34 FATTR4_CHANGE,
35 FATTR4_SIZE,
36 FATTR4_LINK_SUPPORT,
37 FATTR4_SYMLINK_SUPPORT,
38 FATTR4_NAMED_ATTR,
39 FATTR4_FSID,
40 FATTR4_UNIQUE_HANDLES,
41 FATTR4_LEASE_TIME,
42 FATTR4_RDATTR_ERROR,
43 FATTR4_ACLSUPPORT,
44 FATTR4_CANSETTIME,
45 FATTR4_CASE_INSENSITIVE,
46 FATTR4_CASE_PRESERVING,
47 FATTR4_CHOWN_RESTRICTED,
48 FATTR4_FILEHANDLE,
49 FATTR4_FILEID,
50 FATTR4_FILES_AVAIL,
51 FATTR4_FILES_FREE,
52 FATTR4_FILES_TOTAL,
53 FATTR4_HOMOGENEOUS,
54 FATTR4_MAXFILESIZE,
55 FATTR4_MAXLINK,
56 FATTR4_MAXNAME,
57 FATTR4_MAXREAD,
58 FATTR4_MAXWRITE,
59 FATTR4_MODE,
60 FATTR4_NO_TRUNC,
61 FATTR4_NUMLINKS,
62 FATTR4_OWNER,
63 FATTR4_OWNER_GROUP,
64 FATTR4_RAWDEV,
65 FATTR4_SPACE_AVAIL,
66 FATTR4_SPACE_FREE,
67 FATTR4_SPACE_TOTAL,
68 FATTR4_SPACE_USED,
69 FATTR4_TIME_ACCESS,
70 FATTR4_TIME_DELTA,
71 FATTR4_TIME_METADATA,
72 FATTR4_TIME_MODIFY,
73 FATTR4_MOUNTED_ON_FILEID};
74
75 const unsigned kNumBitmapWords = 2;
76
77 910 void SupportedBitmap(uint32_t *words) {
78 910 words[0] = words[1] = 0;
79
2/2
✓ Branch 0 taken 39130 times.
✓ Branch 1 taken 910 times.
40040 for (unsigned i = 0; i < sizeof(kSupportedAttrs) / sizeof(unsigned); ++i)
80 39130 words[kSupportedAttrs[i] / 32] |= 1u << (kSupportedAttrs[i] % 32);
81 910 }
82
83 62049 bool IsSet(const uint32_t *bitmap, unsigned len, unsigned attr) {
84
3/4
✓ Branch 0 taken 62049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 884 times.
✓ Branch 3 taken 61165 times.
62049 return (attr / 32 < len) && (bitmap[attr / 32] & (1u << (attr % 32)));
85 }
86
87 26 void PutTime(const Timespec &t, XdrWriter *w) {
88 26 w->PutI64(t.sec);
89 26 w->PutU32(t.nsec);
90 26 }
91
92 884 void PutBitmap(const uint32_t *words, unsigned len, XdrWriter *w) {
93 // Trailing zero words are dropped, as recommended by RFC 7530
94
4/4
✓ Branch 0 taken 1742 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 897 times.
✓ Branch 3 taken 845 times.
1781 while (len > 0 && words[len - 1] == 0)
95 897 len--;
96 884 w->PutU32(len);
97
2/2
✓ Branch 0 taken 871 times.
✓ Branch 1 taken 884 times.
1755 for (unsigned i = 0; i < len; ++i)
98 871 w->PutU32(words[i]);
99 884 }
100
101 780 uint32_t FileType(const FileHandle &fh, mode_t mode) {
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
780 if (fh.kind == FileHandle::kAttrDir)
103 ✗ return NF4ATTRDIR;
104
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 767 times.
780 if (fh.kind == FileHandle::kNamedAttr)
105 13 return NF4NAMEDATTR;
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISDIR(mode))
107 ✗ return NF4DIR;
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISLNK(mode))
109 ✗ return NF4LNK;
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISCHR(mode))
111 ✗ return NF4CHR;
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISBLK(mode))
113 ✗ return NF4BLK;
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISFIFO(mode))
115 ✗ return NF4FIFO;
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
767 if (S_ISSOCK(mode))
117 ✗ return NF4SOCK;
118 767 return NF4REG;
119 }
120
121 2600 bool IsValidUtf8(const std::string &s) {
122 2600 unsigned i = 0;
123
2/2
✓ Branch 1 taken 15249 times.
✓ Branch 2 taken 2600 times.
17849 while (i < s.size()) {
124 15249 const unsigned char c = s[i];
125 unsigned n;
126
1/2
✓ Branch 0 taken 15249 times.
✗ Branch 1 not taken.
15249 if (c < 0x80)
127 15249 n = 0;
128 ✗ else if ((c & 0xE0) == 0xC0)
129 ✗ n = 1;
130 ✗ else if ((c & 0xF0) == 0xE0)
131 ✗ n = 2;
132 ✗ else if ((c & 0xF8) == 0xF0)
133 ✗ n = 3;
134 else
135 ✗ return false;
136
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 15249 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15249 times.
15249 if (i + n >= s.size() && n > 0)
137 ✗ return false;
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15249 times.
15249 for (unsigned j = 1; j <= n; ++j) {
139 ✗ if ((static_cast<unsigned char>(s[i + j]) & 0xC0) != 0x80)
140 ✗ return false;
141 }
142 15249 i += n + 1;
143 }
144 2600 return true;
145 }
146
147 1820 uint32_t CheckName(const std::string &name) {
148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1820 times.
1820 if (name.empty())
149 ✗ return NFS4ERR_INVAL;
150
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1820 times.
1820 if (name.size() > kMaxName)
151 ✗ return NFS4ERR_NAMETOOLONG;
152
6/8
✓ Branch 1 taken 1820 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1807 times.
✓ Branch 5 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1807 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 1807 times.
1820 if (name == "." || name == ".." || name.find('/') != std::string::npos)
153 13 return NFS4ERR_BADNAME;
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1807 times.
1807 if (!IsValidUtf8(name))
155 ✗ return NFS4ERR_INVAL;
156 1807 return NFS4_OK;
157 }
158
159 ✗ std::string NumericId(uint32_t id) {
160 char buf[16];
161 ✗ snprintf(buf, sizeof(buf), "%u", id);
162 ✗ return buf;
163 }
164
165 /**
166 * Permission check against the mode bits. Write access is never granted.
167 */
168 156 uint32_t AccessFromMode(const Attr &attr, const Credentials &creds) {
169 unsigned perms;
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if (creds.uid == 0) {
171 ✗ perms = 04 | ((attr.mode & 0111) ? 01 : 0);
172
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 26 times.
156 } else if (creds.uid == attr.uid) {
173 130 perms = (attr.mode >> 6) & 07;
174 } else {
175 26 bool in_group = (creds.gid == attr.gid);
176
4/6
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
26 for (unsigned i = 0; !in_group && i < creds.gids.size(); ++i)
177 ✗ in_group = (creds.gids[i] == attr.gid);
178
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 perms = in_group ? (attr.mode >> 3) & 07 : attr.mode & 07;
179 }
180
181 156 uint32_t granted = 0;
182
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 26 times.
156 if (perms & 04)
183 130 granted |= ACCESS4_READ;
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if (perms & 01)
185 ✗ granted |= S_ISDIR(attr.mode) ? ACCESS4_LOOKUP : ACCESS4_EXECUTE;
186 156 return granted;
187 }
188
189 // Errors after which an open-owner's seqid is not advanced (RFC 7530 9.1.7)
190 182 bool SeqidAdvances(uint32_t status) {
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 switch (status) {
192 ✗ case NFS4ERR_STALE_CLIENTID:
193 case NFS4ERR_STALE_STATEID:
194 case NFS4ERR_BAD_STATEID:
195 case NFS4ERR_BAD_SEQID:
196 case NFS4ERR_BADXDR:
197 case NFS4ERR_RESOURCE:
198 case NFS4ERR_NOFILEHANDLE:
199 case NFS4ERR_MOVED:
200 ✗ return false;
201 182 default:
202 182 return true;
203 }
204 }
205
206 } // anonymous namespace
207
208
209 156 uint32_t ErrnoToStatus(int err) {
210
2/18
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
156 switch (err) {
211 130 case 0:
212 130 return NFS4_OK;
213 ✗ case EPERM:
214 ✗ return NFS4ERR_PERM;
215 26 case ENOENT:
216 case ENODATA:
217 26 return NFS4ERR_NOENT;
218 ✗ case EACCES:
219 ✗ return NFS4ERR_ACCESS;
220 ✗ case ENOTDIR:
221 ✗ return NFS4ERR_NOTDIR;
222 ✗ case EISDIR:
223 ✗ return NFS4ERR_ISDIR;
224 ✗ case EINVAL:
225 ✗ return NFS4ERR_INVAL;
226 ✗ case ENAMETOOLONG:
227 ✗ return NFS4ERR_NAMETOOLONG;
228 ✗ case EROFS:
229 ✗ return NFS4ERR_ROFS;
230 ✗ case ESTALE:
231 ✗ return NFS4ERR_STALE;
232 ✗ case EAGAIN:
233 case EBUSY:
234 ✗ return NFS4ERR_DELAY;
235 ✗ case ENOSPC:
236 ✗ return NFS4ERR_NOSPC;
237 ✗ case EFBIG:
238 ✗ return NFS4ERR_FBIG;
239 ✗ case ERANGE:
240 ✗ return NFS4ERR_TOOSMALL;
241 ✗ case ELOOP:
242 ✗ return NFS4ERR_SYMLINK;
243 ✗ case EMFILE:
244 case ENFILE:
245 ✗ return NFS4ERR_DELAY;
246 ✗ case EIO:
247 ✗ return NFS4ERR_IO;
248 ✗ default:
249 ✗ Log(kLogLevelWarn, "mapping unexpected errno %d to NFS4ERR_IO", err);
250 ✗ return NFS4ERR_IO;
251 }
252 }
253
254
255 234 Nfs4Server::Nfs4Server(Backend *backend, const Options &options)
256 234 : backend_(backend)
257 234 , options_(options)
258 468 , fsid_(backend->FsId())
259 234 , boot_(static_cast<uint32_t>(time(NULL)))
260 234 , next_clientid_(1)
261 234 , next_stateid_(1)
262 234 , num_frozen_attrs_(0)
263 234 , last_generation_(0)
264 234 , monitor_stopping_(false)
265
2/4
✓ Branch 2 taken 234 times.
✗ Branch 3 not taken.
✓ Branch 17 taken 234 times.
✗ Branch 18 not taken.
702 , executors_stopping_(false) { }
266
267
268 910 Nfs4Server::~Nfs4Server() {
269 {
270 468 std::lock_guard<std::mutex> const lock(state_lock_);
271 468 monitor_stopping_ = true;
272 }
273 468 monitor_cond_.notify_all();
274
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 221 times.
468 if (monitor_.joinable())
275 26 monitor_.join();
276 {
277 468 std::lock_guard<std::mutex> const lock(executor_lock_);
278 468 executors_stopping_ = true;
279 }
280 468 executor_cond_.notify_all();
281
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 234 times.
520 for (unsigned i = 0; i < executors_.size(); ++i)
282 52 executors_[i].join();
283 910 }
284
285
286 52 void Nfs4Server::ExecutorLoop() {
287 while (true) {
288 52 TaskPtr task;
289 {
290
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 std::unique_lock<std::mutex> lock(executor_lock_);
291 52 executor_cond_.wait(
292
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 26 times.
78 lock, [this] { return executors_stopping_ || !tasks_.empty(); });
293
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
52 if (tasks_.empty())
294 52 return;
295 26 task = tasks_.front();
296 26 tasks_.pop_front();
297
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
52 }
298 26 XdrReader args(reinterpret_cast<const unsigned char *>(task->args.data()),
299 52 task->args.size());
300
1/2
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
26 ProcessCompound(task->call, &args, &task->res);
301 {
302
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 std::lock_guard<std::mutex> const lock(executor_lock_);
303 26 task->done = true;
304 26 }
305 26 task->done_cond.notify_one();
306
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
78 }
307 }
308
309
310 26 void Nfs4Server::RunWithDeadline(const RpcCall &call, XdrReader *args,
311 XdrWriter *res) {
312
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
26 TaskPtr task(new Task());
313
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
26 task->call = call;
314
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
26 task->args.assign(reinterpret_cast<const char *>(args->cursor()),
315 args->remaining());
316 26 task->call.args = NULL;
317 26 task->call.args_size = 0;
318
319
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 std::unique_lock<std::mutex> lock(executor_lock_);
320
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
26 if (executors_.empty()) {
321
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 13 times.
39 for (unsigned i = 0; i < options_.executor_threads; ++i)
322
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
26 executors_.push_back(std::thread(&Nfs4Server::ExecutorLoop, this));
323 }
324
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 tasks_.push_back(task);
325 26 executor_cond_.notify_one();
326
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 const bool done = task->done_cond.wait_for(
327 26 lock, std::chrono::milliseconds(options_.delay_after_ms),
328 52 [&task] { return task->done; });
329
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (done) {
330
1/2
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
13 res->PutRaw(task->res.buffer().data(), task->res.size());
331 13 return;
332 }
333
334 // Still queued or running: the task completes on its own, and the client's
335 // retry benefits from the warmed cache (or the open-owner replay cache)
336
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
13 for (std::deque<TaskPtr>::iterator it = tasks_.begin(); it != tasks_.end();
337 ✗ ++it) {
338 ✗ if (*it == task) {
339 ✗ tasks_.erase(it);
340 ✗ break;
341 }
342 }
343
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 lock.unlock();
344
345 13 XdrReader r(reinterpret_cast<const unsigned char *>(task->args.data()),
346 26 task->args.size());
347 13 std::string tag;
348 13 uint32_t minor_version = 0, num_ops = 0, first_op = 0;
349
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 r.GetOpaque(&tag, kNfs4OpaqueLimit);
350
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 r.GetU32(&minor_version);
351
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 r.GetU32(&num_ops);
352
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 r.GetU32(&first_op);
353
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 Log(kLogLevelDebug, "xid %u delayed", call.xid);
354
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutU32(NFS4ERR_DELAY);
355
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutOpaque(tag);
356
3/6
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
13 if (num_ops == 0 || !r.ok()) {
357 ✗ res->PutU32(0);
358 ✗ return;
359 }
360
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutU32(1);
361
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutU32(first_op);
362
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutU32(NFS4ERR_DELAY);
363
5/6
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 13 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 13 times.
39 }
364
365
366 1456 AcceptStat Nfs4Server::Dispatch(const RpcCall &call, XdrReader *args,
367 XdrWriter *res) {
368
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 switch (call.procedure) {
369 ✗ case kNfsProcNull:
370 ✗ return kAcceptSuccess;
371 1456 case kNfsProcCompound:
372
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1430 times.
1456 if (options_.delay_after_ms > 0)
373 26 RunWithDeadline(call, args, res);
374 else
375 1430 ProcessCompound(call, args, res);
376 1456 return kAcceptSuccess;
377 ✗ default:
378 ✗ return kAcceptProcUnavail;
379 }
380 }
381
382
383 1456 uint32_t Nfs4Server::ProcessCompound(const RpcCall &call, XdrReader *args,
384 XdrWriter *res) {
385 1456 std::string tag;
386 1456 uint32_t minor_version = 0, num_ops = 0;
387
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 args->GetOpaque(&tag, kNfs4OpaqueLimit);
388
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 args->GetU32(&minor_version);
389
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 args->GetU32(&num_ops);
390
391
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 const size_t status_offset = res->ReserveU32();
392
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 res->PutOpaque(tag);
393
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 const size_t count_offset = res->ReserveU32();
394
395 1456 uint32_t status = NFS4_OK;
396 1456 uint32_t num_results = 0;
397
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1456 times.
1456 if (!args->ok()) {
398 ✗ status = NFS4ERR_BADXDR;
399
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1443 times.
1456 } else if (minor_version != 0) {
400 13 status = NFS4ERR_MINOR_VERS_MISMATCH;
401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1443 times.
1443 } else if (num_ops > options_.max_compound_ops) {
402 ✗ status = NFS4ERR_RESOURCE;
403 } else {
404 1443 Compound c;
405 1443 c.call = &call;
406
2/2
✓ Branch 0 taken 3601 times.
✓ Branch 1 taken 1105 times.
4706 for (uint32_t i = 0; i < num_ops; ++i) {
407 uint32_t op;
408
2/4
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3601 times.
3601 if (!args->GetU32(&op)) {
409 ✗ status = NFS4ERR_BADXDR;
410 338 break;
411 }
412 // The op's result is written in place; on failure it is cut off again
413
1/2
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
3601 const size_t op_offset = res->ReserveU32();
414
1/2
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
3601 const size_t status_offset_op = res->ReserveU32();
415 3601 const size_t body_offset = res->size();
416
1/2
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
3601 status = ProcessOp(op, args, &c, res);
417
4/6
✓ Branch 0 taken 3263 times.
✓ Branch 1 taken 338 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3263 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3601 times.
3601 if (status == NFS4_OK && !args->ok())
418 ✗ status = NFS4ERR_BADXDR;
419
1/2
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
3601 Log(kLogLevelDebug, "xid %u op %u -> %u", call.xid, op, status);
420 3601 const bool illegal = (status == NFS4ERR_OP_ILLEGAL);
421
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3588 times.
✓ Branch 3 taken 3601 times.
✗ Branch 4 not taken.
3601 res->PatchU32(op_offset, illegal ? static_cast<uint32_t>(OP_ILLEGAL) : op);
422
1/2
✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
3601 res->PatchU32(status_offset_op, status);
423
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 3263 times.
3601 if (status != NFS4_OK) {
424
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 res->Truncate(body_offset);
425
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 325 times.
338 if (op == OP_SETATTR)
426
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res->PutU32(0); // attrsset is returned on failure, too
427 }
428 3601 num_results++;
429
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 3263 times.
3601 if (status != NFS4_OK)
430 338 break;
431 }
432 }
433
434
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1443 times.
1456 if (num_results == 0) {
435
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 Log(kLogLevelDebug, "xid %u: compound of %u ops rejected -> %u", call.xid,
436 num_ops, status);
437 }
438
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 res->PatchU32(status_offset, status);
439
1/2
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
1456 res->PatchU32(count_offset, num_results);
440 1456 return status;
441 1456 }
442
443
444 3601 uint32_t Nfs4Server::ProcessOp(uint32_t op, XdrReader *args, Compound *c,
445 XdrWriter *body) {
446
21/28
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 533 times.
✓ Branch 4 taken 858 times.
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 195 times.
✓ Branch 9 taken 39 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 689 times.
✓ Branch 13 taken 572 times.
✓ Branch 14 taken 91 times.
✓ Branch 15 taken 156 times.
✓ Branch 16 taken 13 times.
✓ Branch 17 taken 26 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 65 times.
✓ Branch 22 taken 65 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 26 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 26 times.
✓ Branch 27 taken 13 times.
3601 switch (op) {
447 26 case OP_ACCESS:
448 26 return OpAccess(args, c, body);
449 39 case OP_CLOSE:
450 39 return OpClose(args, c, body);
451 78 case OP_GETATTR:
452 78 return OpGetattr(args, c, body);
453 533 case OP_GETFH:
454 533 return OpGetfh(c, body);
455 858 case OP_LOOKUP:
456 858 return OpLookup(args, c);
457 65 case OP_LOOKUPP:
458 65 return OpLookupp(c);
459 13 case OP_NVERIFY:
460 13 return OpVerify(args, c, true);
461 13 case OP_VERIFY:
462 13 return OpVerify(args, c, false);
463 195 case OP_OPEN:
464 195 return OpOpen(args, c, body);
465 39 case OP_OPENATTR:
466 39 return OpOpenattr(args, c);
467 ✗ case OP_OPEN_CONFIRM:
468 ✗ return OpOpenConfirm(args, c, body);
469 ✗ case OP_OPEN_DOWNGRADE:
470 ✗ return OpOpenDowngrade(args, c, body);
471 689 case OP_PUTFH:
472 689 return OpPutfh(args, c);
473 572 case OP_PUTPUBFH:
474 case OP_PUTROOTFH:
475 572 c->fh = FileHandle(FileHandle::kObject, fsid_, backend_->RootInode());
476 572 c->has_fh = true;
477 572 return NFS4_OK;
478 91 case OP_READ:
479 91 return OpRead(args, c, body);
480 156 case OP_READDIR:
481 156 return OpReaddir(args, c, body);
482 13 case OP_READLINK:
483 13 return OpReadlink(c, body);
484 26 case OP_RENEW:
485 26 return OpRenew(args);
486 ✗ case OP_RESTOREFH:
487 ✗ if (!c->has_saved)
488 ✗ return NFS4ERR_RESTOREFH;
489 ✗ c->fh = c->saved;
490 ✗ c->has_fh = true;
491 ✗ return NFS4_OK;
492 ✗ case OP_SAVEFH:
493 ✗ if (!c->has_fh)
494 ✗ return NFS4ERR_NOFILEHANDLE;
495 ✗ c->saved = c->fh;
496 ✗ c->has_saved = true;
497 ✗ return NFS4_OK;
498 ✗ case OP_SECINFO:
499 ✗ return OpSecinfo(args, c, body);
500 65 case OP_SETCLIENTID:
501 65 return OpSetclientid(args, body);
502 65 case OP_SETCLIENTID_CONFIRM:
503 65 return OpSetclientidConfirm(args);
504 ✗ case OP_RELEASE_LOCKOWNER:
505 ✗ return NFS4_OK;
506 26 case OP_DELEGRETURN:
507 26 return OpDelegreturn(args);
508 ✗ case OP_DELEGPURGE:
509 case OP_LOCK:
510 case OP_LOCKT:
511 case OP_LOCKU:
512 ✗ return NFS4ERR_NOTSUPP;
513 26 case OP_COMMIT:
514 case OP_CREATE:
515 case OP_LINK:
516 case OP_REMOVE:
517 case OP_RENAME:
518 case OP_SETATTR:
519 case OP_WRITE:
520
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 return c->has_fh ? NFS4ERR_ROFS : NFS4ERR_NOFILEHANDLE;
521 13 default:
522 13 return NFS4ERR_OP_ILLEGAL;
523 }
524 }
525
526
527 //------------------------------------------------------------------------------
528 // Object resolution
529
530
531 65 uint32_t Nfs4Server::ResolveXattrName(uint64_t ino, uint32_t hash,
532 std::string *name) {
533 65 std::vector<std::string> names;
534
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 const int retval = backend_->ListXattr(ino, &names);
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
65 if (retval != 0)
536 ✗ return ErrnoToStatus(retval);
537
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 for (unsigned i = 0; i < names.size(); ++i) {
538
3/4
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 52 times.
117 if (HashName(names[i]) == hash) {
539
1/2
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
65 *name = names[i];
540 65 return NFS4_OK;
541 }
542 }
543 ✗ return NFS4ERR_STALE;
544 65 }
545
546
547 1534 uint32_t Nfs4Server::Resolve(const FileHandle &fh, const Credentials &creds,
548 Object *obj) {
549 1534 obj->fh = fh;
550 1534 int retval = backend_->GetAttr(fh.ino, &obj->attr);
551
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1521 times.
1534 if (retval == ENOENT)
552 13 return NFS4ERR_STALE;
553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1521 times.
1521 if (retval != 0)
554 ✗ return ErrnoToStatus(retval);
555
556
6/6
✓ Branch 0 taken 1417 times.
✓ Branch 1 taken 104 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 1352 times.
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 1456 times.
1521 if (fh.kind == FileHandle::kObject && num_frozen_attrs_ > 0) {
557
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 std::lock_guard<std::mutex> const lock(state_lock_);
558
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 std::map<uint64_t, Attr>::const_iterator const it = frozen_attrs_.find(fh.ino);
559
2/2
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 52 times.
65 if (it != frozen_attrs_.end())
560 13 obj->attr = it->second;
561 65 }
562
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1482 times.
1521 if (fh.kind == FileHandle::kAttrDir) {
563 39 obj->attr.mode = S_IFDIR | 0555;
564 39 obj->attr.nlink = 2;
565 39 obj->attr.size = 0;
566
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 1417 times.
1482 } else if (fh.kind == FileHandle::kNamedAttr) {
567
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 const uint32_t status = ResolveXattrName(fh.ino, fh.aux, &obj->xattr_name);
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
65 if (status != NFS4_OK)
569 ✗ return status;
570 65 std::string value;
571
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 retval = backend_->GetXattr(fh.ino, obj->xattr_name, creds, &value);
572 // Unreadable values (e.g. privileged attributes) still get a handle;
573 // the error surfaces on READ
574
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 obj->attr.size = (retval == 0) ? value.size() : 0;
575 65 obj->attr.mode = S_IFREG | 0444;
576 65 obj->attr.nlink = 1;
577 65 }
578 1521 return NFS4_OK;
579 }
580
581
582 1820 uint32_t Nfs4Server::LookupChild(const Object &dir, const std::string &name,
583 const Credentials &creds, Object *child) {
584 1820 uint32_t const status = CheckName(name);
585
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1807 times.
1820 if (status != NFS4_OK)
586 13 return status;
587
588
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 1755 times.
1807 if (dir.fh.kind == FileHandle::kAttrDir) {
589 52 std::vector<std::string> names;
590
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 const int retval = backend_->ListXattr(dir.fh.ino, &names);
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (retval != 0)
592 ✗ return ErrnoToStatus(retval);
593
2/2
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 13 times.
104 for (unsigned i = 0; i < names.size(); ++i) {
594
2/2
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 52 times.
91 if (names[i] == name) {
595
2/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39 times.
✗ Branch 6 not taken.
78 return Resolve(FileHandle(FileHandle::kNamedAttr, fsid_, dir.fh.ino,
596 HashName(name)),
597 39 creds, child);
598 }
599 }
600 13 return NFS4ERR_NOENT;
601 52 }
602
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1755 times.
1755 if (dir.fh.kind != FileHandle::kObject)
604 ✗ return NFS4ERR_NOTDIR;
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1755 times.
1755 if (S_ISLNK(dir.attr.mode))
606 ✗ return NFS4ERR_SYMLINK;
607
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1742 times.
1755 if (!S_ISDIR(dir.attr.mode))
608 13 return NFS4ERR_NOTDIR;
609
610 1742 const int retval = backend_->Lookup(dir.fh.ino, name, &child->attr);
611
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1716 times.
1742 if (retval != 0)
612 26 return ErrnoToStatus(retval);
613 1716 child->fh = FileHandle(FileHandle::kObject, fsid_, child->attr.ino);
614 1716 child->xattr_name.clear();
615 1716 return NFS4_OK;
616 }
617
618
619 143 uint32_t Nfs4Server::ListChildren(const Object &dir,
620 std::vector<DirEntry> *entries) {
621
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 130 times.
143 if (dir.fh.kind == FileHandle::kAttrDir) {
622 13 std::vector<std::string> names;
623
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 const int retval = backend_->ListXattr(dir.fh.ino, &names);
624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (retval != 0)
625 ✗ return ErrnoToStatus(retval);
626 13 entries->clear();
627
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 13 times.
39 for (unsigned i = 0; i < names.size(); ++i)
628
2/4
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
26 entries->push_back(DirEntry(names[i], dir.fh.ino));
629 13 return NFS4_OK;
630 13 }
631
2/4
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 130 times.
130 if (dir.fh.kind != FileHandle::kObject || !S_ISDIR(dir.attr.mode))
632 ✗ return NFS4ERR_NOTDIR;
633 130 return ErrnoToStatus(backend_->ReadDir(dir.fh.ino, entries));
634 }
635
636
637 13 uint64_t Nfs4Server::FileId(const Object &obj) const {
638
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 switch (obj.fh.kind) {
639 ✗ case FileHandle::kAttrDir:
640 ✗ return obj.fh.ino | kAttrDirFileIdBit;
641 ✗ case FileHandle::kNamedAttr:
642 ✗ return (obj.fh.ino ^ (static_cast<uint64_t>(obj.fh.aux) << 32))
643 ✗ | kNamedAttrFileIdBit;
644 13 default:
645 13 return obj.fh.ino;
646 }
647 }
648
649
650 //------------------------------------------------------------------------------
651 // Attributes
652
653
654 286 bool Nfs4Server::DecodeBitmap(XdrReader *r, std::vector<uint32_t> *bitmap) {
655 uint32_t len;
656
4/8
✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 286 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 286 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 286 times.
286 if (!r->GetU32(&len) || len > 8)
657 ✗ return false;
658
1/2
✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
286 bitmap->resize(len);
659
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 286 times.
650 for (uint32_t i = 0; i < len; ++i)
660
1/2
✓ Branch 2 taken 364 times.
✗ Branch 3 not taken.
364 r->GetU32(&(*bitmap)[i]);
661 286 return r->ok();
662 }
663
664
665 884 bool Nfs4Server::EncodeFattr(const Object &obj, const uint32_t *request,
666 unsigned request_len, const Credentials &creds,
667 XdrWriter *out) {
668 uint32_t supported[kNumBitmapWords];
669 884 SupportedBitmap(supported);
670 884 uint32_t returned[kNumBitmapWords] = {0, 0};
671
4/4
✓ Branch 0 taken 1768 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 949 times.
✓ Branch 3 taken 819 times.
1833 for (unsigned i = 0; i < kNumBitmapWords && i < request_len; ++i)
672 949 returned[i] = request[i] & supported[i];
673 // Errors are reported per op, not in the attributes of a single object
674 884 returned[0] &= ~(1u << FATTR4_RDATTR_ERROR);
675
676 884 FsStat fs;
677 884 const bool need_fs = IsSet(returned, 2, FATTR4_FILES_AVAIL)
678
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 || IsSet(returned, 2, FATTR4_FILES_FREE)
679
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 || IsSet(returned, 2, FATTR4_FILES_TOTAL)
680
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 || IsSet(returned, 2, FATTR4_SPACE_AVAIL)
681
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 || IsSet(returned, 2, FATTR4_SPACE_FREE)
682
2/4
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 884 times.
1768 || IsSet(returned, 2, FATTR4_SPACE_TOTAL);
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 884 times.
884 if (need_fs)
684 ✗ backend_->StatFs(&fs);
685
686 884 const Attr &a = obj.attr;
687 884 XdrWriter v;
688
2/2
✓ Branch 0 taken 56576 times.
✓ Branch 1 taken 884 times.
57460 for (unsigned attr = 0; attr < 32 * kNumBitmapWords; ++attr) {
689
2/2
✓ Branch 1 taken 55692 times.
✓ Branch 2 taken 884 times.
56576 if (!IsSet(returned, kNumBitmapWords, attr))
690 55692 continue;
691
4/34
✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✓ Branch 32 taken 26 times.
✗ Branch 33 not taken.
884 switch (attr) {
692 ✗ case FATTR4_SUPPORTED_ATTRS:
693 ✗ PutBitmap(supported, kNumBitmapWords, &v);
694 ✗ break;
695 780 case FATTR4_TYPE:
696
1/2
✓ Branch 2 taken 780 times.
✗ Branch 3 not taken.
780 v.PutU32(FileType(obj.fh, a.mode));
697 780 break;
698 ✗ case FATTR4_FH_EXPIRE_TYPE:
699 ✗ v.PutU32(FH4_PERSISTENT);
700 ✗ break;
701 ✗ case FATTR4_CHANGE:
702 ✗ if (obj.fh.kind == FileHandle::kObject) {
703 ✗ v.PutU64((static_cast<uint64_t>(a.ctime.sec) << 30) ^ a.ctime.nsec);
704 } else {
705 ✗ v.PutU64(backend_->Generation());
706 }
707 ✗ break;
708 65 case FATTR4_SIZE:
709
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 v.PutU64(a.size);
710 65 break;
711 ✗ case FATTR4_LINK_SUPPORT:
712 case FATTR4_SYMLINK_SUPPORT:
713 case FATTR4_UNIQUE_HANDLES:
714 case FATTR4_CASE_PRESERVING:
715 case FATTR4_CHOWN_RESTRICTED:
716 case FATTR4_HOMOGENEOUS:
717 case FATTR4_NO_TRUNC:
718 ✗ v.PutBool(true);
719 ✗ break;
720 ✗ case FATTR4_NAMED_ATTR:
721 ✗ v.PutBool(obj.fh.kind == FileHandle::kObject);
722 ✗ break;
723 ✗ case FATTR4_FSID:
724 ✗ v.PutU64(fsid_);
725 ✗ v.PutU64(0);
726 ✗ break;
727 ✗ case FATTR4_LEASE_TIME:
728 ✗ v.PutU32(options_.lease_time);
729 ✗ break;
730 ✗ case FATTR4_ACLSUPPORT:
731 ✗ v.PutU32(0);
732 ✗ break;
733 ✗ case FATTR4_CANSETTIME:
734 case FATTR4_CASE_INSENSITIVE:
735 ✗ v.PutBool(false);
736 ✗ break;
737 ✗ case FATTR4_FILEHANDLE:
738 ✗ v.PutOpaque(obj.fh.Encode());
739 ✗ break;
740 13 case FATTR4_FILEID:
741 case FATTR4_MOUNTED_ON_FILEID:
742
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 v.PutU64(FileId(obj));
743 13 break;
744 ✗ case FATTR4_FILES_AVAIL:
745 ✗ v.PutU64(fs.files_avail);
746 ✗ break;
747 ✗ case FATTR4_FILES_FREE:
748 ✗ v.PutU64(fs.files_free);
749 ✗ break;
750 ✗ case FATTR4_FILES_TOTAL:
751 ✗ v.PutU64(fs.files_total);
752 ✗ break;
753 ✗ case FATTR4_MAXFILESIZE:
754 ✗ v.PutU64(0x7fffffffffffffffull);
755 ✗ break;
756 ✗ case FATTR4_MAXLINK:
757 ✗ v.PutU32(32000);
758 ✗ break;
759 ✗ case FATTR4_MAXNAME:
760 ✗ v.PutU32(kMaxName);
761 ✗ break;
762 ✗ case FATTR4_MAXREAD:
763 case FATTR4_MAXWRITE:
764 ✗ v.PutU64(options_.max_read);
765 ✗ break;
766 ✗ case FATTR4_MODE:
767 ✗ v.PutU32(a.mode & 07777);
768 ✗ break;
769 ✗ case FATTR4_NUMLINKS:
770 ✗ v.PutU32(a.nlink);
771 ✗ break;
772 ✗ case FATTR4_OWNER:
773 ✗ v.PutString(NumericId(a.uid));
774 ✗ break;
775 ✗ case FATTR4_OWNER_GROUP:
776 ✗ v.PutString(NumericId(a.gid));
777 ✗ break;
778 ✗ case FATTR4_RAWDEV:
779 ✗ v.PutU32(static_cast<uint32_t>(a.rdev >> 32));
780 ✗ v.PutU32(static_cast<uint32_t>(a.rdev));
781 ✗ break;
782 ✗ case FATTR4_SPACE_AVAIL:
783 ✗ v.PutU64(fs.bytes_avail);
784 ✗ break;
785 ✗ case FATTR4_SPACE_FREE:
786 ✗ v.PutU64(fs.bytes_free);
787 ✗ break;
788 ✗ case FATTR4_SPACE_TOTAL:
789 ✗ v.PutU64(fs.bytes_total);
790 ✗ break;
791 ✗ case FATTR4_SPACE_USED:
792 ✗ v.PutU64(a.size);
793 ✗ break;
794 ✗ case FATTR4_TIME_ACCESS:
795 ✗ PutTime(a.atime, &v);
796 ✗ break;
797 ✗ case FATTR4_TIME_DELTA: {
798 ✗ Timespec delta;
799 ✗ delta.nsec = 1;
800 ✗ PutTime(delta, &v);
801 ✗ break;
802 }
803 ✗ case FATTR4_TIME_METADATA:
804 ✗ PutTime(a.ctime, &v);
805 ✗ break;
806 26 case FATTR4_TIME_MODIFY:
807
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 PutTime(a.mtime, &v);
808 26 break;
809 ✗ default:
810 ✗ return false;
811 }
812 }
813
814
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 PutBitmap(returned, kNumBitmapWords, out);
815
1/2
✓ Branch 2 taken 884 times.
✗ Branch 3 not taken.
884 out->PutOpaque(v.buffer());
816 (void)creds;
817 884 return true;
818 884 }
819
820
821 //------------------------------------------------------------------------------
822 // Operations
823
824
825 26 uint32_t Nfs4Server::OpAccess(XdrReader *args, Compound *c, XdrWriter *body) {
826 uint32_t requested;
827
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if (!args->GetU32(&requested))
828 ✗ return NFS4ERR_BADXDR;
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!c->has_fh)
830 ✗ return NFS4ERR_NOFILEHANDLE;
831 26 Object obj;
832
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (status != NFS4_OK)
834 ✗ return status;
835
836 26 const uint32_t supported = requested
837 26 & (ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY
838 | ACCESS4_EXTEND | ACCESS4_DELETE
839 | ACCESS4_EXECUTE);
840
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 body->PutU32(supported);
841
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
26 body->PutU32(AccessFromMode(obj.attr, c->call->creds) & supported);
842 26 return NFS4_OK;
843 26 }
844
845
846 78 uint32_t Nfs4Server::OpGetattr(XdrReader *args, Compound *c, XdrWriter *body) {
847 78 std::vector<uint32_t> request;
848
2/4
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
78 if (!DecodeBitmap(args, &request))
849 ✗ return NFS4ERR_BADXDR;
850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (!c->has_fh)
851 ✗ return NFS4ERR_NOFILEHANDLE;
852 78 Object obj;
853
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
854
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 65 times.
78 if (status != NFS4_OK)
855 13 return status;
856
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 65 times.
65 if (!EncodeFattr(obj, request.empty() ? NULL : &request[0],
857 65 static_cast<unsigned>(request.size()), c->call->creds,
858 body)) {
859 ✗ return NFS4ERR_SERVERFAULT;
860 }
861 65 return NFS4_OK;
862 78 }
863
864
865 533 uint32_t Nfs4Server::OpGetfh(Compound *c, XdrWriter *body) {
866
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 520 times.
533 if (!c->has_fh)
867 13 return NFS4ERR_NOFILEHANDLE;
868
1/2
✓ Branch 2 taken 520 times.
✗ Branch 3 not taken.
520 body->PutOpaque(c->fh.Encode());
869 520 return NFS4_OK;
870 }
871
872
873 858 uint32_t Nfs4Server::OpLookup(XdrReader *args, Compound *c) {
874 858 std::string name;
875
2/4
✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 858 times.
858 if (!args->GetString(&name, kNfs4OpaqueLimit))
876 ✗ return NFS4ERR_BADXDR;
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
858 if (!c->has_fh)
878 ✗ return NFS4ERR_NOFILEHANDLE;
879 858 Object dir, child;
880
1/2
✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
858 uint32_t status = Resolve(c->fh, c->call->creds, &dir);
881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
858 if (status != NFS4_OK)
882 ✗ return status;
883
1/2
✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
858 status = LookupChild(dir, name, c->call->creds, &child);
884
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 806 times.
858 if (status != NFS4_OK)
885 52 return status;
886 806 c->fh = child.fh;
887 806 return NFS4_OK;
888 858 }
889
890
891 65 uint32_t Nfs4Server::OpLookupp(Compound *c) {
892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
65 if (!c->has_fh)
893 ✗ return NFS4ERR_NOFILEHANDLE;
894
3/3
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 39 times.
65 switch (c->fh.kind) {
895 13 case FileHandle::kAttrDir:
896 13 c->fh.kind = FileHandle::kObject;
897 13 return NFS4_OK;
898 13 case FileHandle::kNamedAttr:
899 13 c->fh.kind = FileHandle::kAttrDir;
900 13 c->fh.aux = 0;
901 13 return NFS4_OK;
902 39 default:
903 39 break;
904 }
905
906 78 Object obj;
907
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (status != NFS4_OK)
909 ✗ return status;
910
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (!S_ISDIR(obj.attr.mode))
911
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 return S_ISLNK(obj.attr.mode) ? NFS4ERR_SYMLINK : NFS4ERR_NOTDIR;
912
3/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 13 times.
26 if (c->fh.ino == backend_->RootInode())
913 13 return NFS4ERR_NOENT;
914 13 Attr parent;
915
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 const int retval = backend_->LookupParent(c->fh.ino, &parent);
916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (retval != 0)
917 ✗ return ErrnoToStatus(retval);
918 13 c->fh = FileHandle(FileHandle::kObject, fsid_, parent.ino);
919 13 return NFS4_OK;
920 }
921
922
923 26 uint32_t Nfs4Server::OpVerify(XdrReader *args, Compound *c, bool negate) {
924 26 std::vector<uint32_t> request;
925 26 std::string values;
926
5/10
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 26 times.
26 if (!DecodeBitmap(args, &request) || !args->GetOpaque(&values))
927 ✗ return NFS4ERR_BADXDR;
928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!c->has_fh)
929 ✗ return NFS4ERR_NOFILEHANDLE;
930
931 uint32_t supported[kNumBitmapWords];
932 26 SupportedBitmap(supported);
933
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
52 for (unsigned i = 0; i < request.size(); ++i) {
934
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if (request[i] & ~(i < kNumBitmapWords ? supported[i] : 0))
935 ✗ return NFS4ERR_ATTRNOTSUPP;
936 }
937
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
26 if (IsSet(request.empty() ? NULL : &request[0],
938 26 static_cast<unsigned>(request.size()), FATTR4_RDATTR_ERROR)) {
939 ✗ return NFS4ERR_INVAL;
940 }
941
942 26 Object obj;
943
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (status != NFS4_OK)
945 ✗ return status;
946 26 XdrWriter mine;
947
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
26 EncodeFattr(obj, request.empty() ? NULL : &request[0],
948 26 static_cast<unsigned>(request.size()), c->call->creds, &mine);
949 // Skip our bitmap and the opaque length to compare the raw values
950 26 XdrReader r(reinterpret_cast<const unsigned char *>(mine.buffer().data()),
951 52 mine.size());
952 26 std::vector<uint32_t> ignored;
953 26 std::string my_values;
954
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 DecodeBitmap(&r, &ignored);
955
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 r.GetOpaque(&my_values);
956
957 26 const bool same = (my_values == values);
958
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (negate)
959
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 return same ? NFS4ERR_SAME : NFS4_OK;
960
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 return same ? NFS4_OK : NFS4ERR_NOT_SAME;
961 26 }
962
963
964 39 uint32_t Nfs4Server::OpOpenattr(XdrReader *args, Compound *c) {
965 bool create_dir;
966
2/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
39 if (!args->GetBool(&create_dir))
967 ✗ return NFS4ERR_BADXDR;
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!c->has_fh)
969 ✗ return NFS4ERR_NOFILEHANDLE;
970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (c->fh.kind != FileHandle::kObject)
971 ✗ return NFS4ERR_INVAL;
972 39 Object obj;
973
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
974
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (status != NFS4_OK)
975 ✗ return status;
976 39 c->fh.kind = FileHandle::kAttrDir;
977 39 c->fh.aux = 0;
978 39 return NFS4_OK;
979 39 }
980
981
982 689 uint32_t Nfs4Server::OpPutfh(XdrReader *args, Compound *c) {
983 689 std::string raw;
984
2/4
✓ Branch 1 taken 689 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 689 times.
689 if (!args->GetOpaque(&raw, kNfs4FhSize))
985 ✗ return NFS4ERR_BADXDR;
986 689 FileHandle fh;
987
3/4
✓ Branch 1 taken 689 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 676 times.
689 if (!FileHandle::Decode(raw, &fh))
988 13 return NFS4ERR_BADHANDLE;
989
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 663 times.
676 if (fh.fsid != fsid_)
990 13 return NFS4ERR_STALE;
991 663 c->fh = fh;
992 663 c->has_fh = true;
993 663 return NFS4_OK;
994 689 }
995
996
997 91 uint32_t Nfs4Server::OpRead(XdrReader *args, Compound *c, XdrWriter *body) {
998 91 Stateid stateid;
999 uint64_t offset;
1000 uint32_t count;
1001
3/6
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
182 if (!GetStateid(args, &stateid) || !args->GetU64(&offset)
1002
4/8
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 91 times.
182 || !args->GetU32(&count)) {
1003 ✗ return NFS4ERR_BADXDR;
1004 }
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 if (!c->has_fh)
1006 ✗ return NFS4ERR_NOFILEHANDLE;
1007
1008 91 Object obj;
1009
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 uint32_t status = Resolve(c->fh, c->call->creds, &obj);
1010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 if (status != NFS4_OK)
1011 ✗ return status;
1012
2/4
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
91 if (obj.fh.kind == FileHandle::kAttrDir || S_ISDIR(obj.attr.mode))
1013 ✗ return NFS4ERR_ISDIR;
1014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 if (!S_ISREG(obj.attr.mode))
1015 ✗ return NFS4ERR_INVAL;
1016 {
1017
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 std::lock_guard<std::mutex> const lock(state_lock_);
1018
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 status = CheckReadStateid(stateid, c->fh);
1019 91 }
1020
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 78 times.
91 if (status != NFS4_OK)
1021 13 return status;
1022
1023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (count > options_.max_read)
1024 ✗ count = options_.max_read;
1025 78 std::string data;
1026
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 65 times.
78 if (obj.fh.kind == FileHandle::kNamedAttr) {
1027 13 std::string value;
1028 26 const int retval = backend_->GetXattr(obj.fh.ino, obj.xattr_name,
1029
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 c->call->creds, &value);
1030
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (retval != 0)
1031 ✗ return ErrnoToStatus(retval);
1032
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (offset < value.size())
1033
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 data = value.substr(offset, count);
1034
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
13 body->PutBool(offset + data.size() >= value.size());
1035
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 body->PutOpaque(data);
1036 13 return NFS4_OK;
1037 13 }
1038
1039
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (count > 0) {
1040
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 const int retval = backend_->Read(obj.fh.ino, offset, count, &data);
1041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
65 if (retval != 0)
1042 ✗ return ErrnoToStatus(retval);
1043 }
1044 65 const bool eof = (data.size() < count)
1045
3/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 52 times.
65 || (offset + data.size() >= obj.attr.size);
1046
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 body->PutBool(eof);
1047
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 body->PutOpaque(data);
1048 65 return NFS4_OK;
1049 91 }
1050
1051
1052 156 uint32_t Nfs4Server::OpReaddir(XdrReader *args, Compound *c, XdrWriter *body) {
1053 uint64_t cookie;
1054 unsigned char verifier[kNfs4VerifierSize];
1055 uint32_t dircount, maxcount;
1056 156 std::vector<uint32_t> request;
1057
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 if (!args->GetU64(&cookie)
1058
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
156 || !args->GetFixedOpaque(verifier, kNfs4VerifierSize)
1059
4/8
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
✗ Branch 9 not taken.
156 || !args->GetU32(&dircount) || !args->GetU32(&maxcount)
1060
4/8
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
312 || !DecodeBitmap(args, &request)) {
1061 ✗ return NFS4ERR_BADXDR;
1062 }
1063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if (!c->has_fh)
1064 ✗ return NFS4ERR_NOFILEHANDLE;
1065
1066 156 Object dir;
1067
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 uint32_t status = Resolve(c->fh, c->call->creds, &dir);
1068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if (status != NFS4_OK)
1069 ✗ return status;
1070
2/4
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
156 if (dir.fh.kind == FileHandle::kNamedAttr || !S_ISDIR(dir.attr.mode))
1071 ✗ return NFS4ERR_NOTDIR;
1072
1073 156 XdrWriter my_verifier_w;
1074
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
156 my_verifier_w.PutU64(backend_->Generation());
1075 156 const std::string &my_verifier = my_verifier_w.buffer();
1076
2/4
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
156 if (cookie == 1 || cookie == 2)
1077 ✗ return NFS4ERR_BAD_COOKIE;
1078 312 if (cookie != 0
1079
6/6
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 39 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 104 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 143 times.
156 && memcmp(verifier, my_verifier.data(), kNfs4VerifierSize) != 0) {
1080 13 return NFS4ERR_NOT_SAME;
1081 }
1082
1083 143 std::vector<DirEntry> entries;
1084
1/2
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
143 status = ListChildren(dir, &entries);
1085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 if (status != NFS4_OK)
1086 ✗ return status;
1087
1088 // Cookies 0, 1 and 2 are reserved; entry i has cookie i + 3
1089
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 39 times.
143 size_t index = (cookie == 0) ? 0 : static_cast<size_t>(cookie - 2);
1090
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
143 if (index > entries.size())
1091 ✗ return NFS4ERR_BAD_COOKIE;
1092
1093
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
143 const bool want_rdattr_error = IsSet(request.empty() ? NULL : &request[0],
1094 143 static_cast<unsigned>(request.size()),
1095 FATTR4_RDATTR_ERROR);
1096
1097
1/2
✓ Branch 2 taken 143 times.
✗ Branch 3 not taken.
143 body->PutFixedOpaque(my_verifier.data(), kNfs4VerifierSize);
1098 // Fixed part: verifier, end-of-list marker, eof flag
1099 143 const size_t fixed_size = kNfs4VerifierSize + 4 + 4;
1100 143 unsigned num_encoded = 0;
1101
2/2
✓ Branch 1 taken 793 times.
✓ Branch 2 taken 26 times.
819 for (; index < entries.size(); ++index) {
1102 793 const DirEntry &e = entries[index];
1103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 793 times.
793 if (!IsValidUtf8(e.name)) {
1104 ✗ Log(kLogLevelDebug, "skipping non-UTF-8 name in listing");
1105 ✗ continue;
1106 }
1107
1108 793 XdrWriter entry;
1109
1/2
✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
793 entry.PutBool(true);
1110
1/2
✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
793 entry.PutU64(index + 3);
1111
1/2
✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
793 entry.PutString(e.name);
1112 793 Object child;
1113
1/2
✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
793 const uint32_t child_status = LookupChild(dir, e.name, c->call->creds,
1114 &child);
1115
1/2
✓ Branch 0 taken 793 times.
✗ Branch 1 not taken.
793 if (child_status == NFS4_OK) {
1116
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 793 times.
✓ Branch 5 taken 793 times.
✗ Branch 6 not taken.
793 EncodeFattr(child, request.empty() ? NULL : &request[0],
1117 793 static_cast<unsigned>(request.size()), c->call->creds,
1118 &entry);
1119 ✗ } else if (want_rdattr_error) {
1120 ✗ uint32_t words[1] = {1u << FATTR4_RDATTR_ERROR};
1121 ✗ PutBitmap(words, 1, &entry);
1122 ✗ XdrWriter value;
1123 ✗ value.PutU32(child_status);
1124 ✗ entry.PutOpaque(value.buffer());
1125 ✗ } else {
1126 // Vanished between listing and lookup; skip it
1127 ✗ continue;
1128 }
1129
1130 793 if (body->size() + entry.size() + fixed_size - kNfs4VerifierSize
1131
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 676 times.
793 > maxcount) {
1132
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
117 if (num_encoded == 0)
1133 13 return NFS4ERR_TOOSMALL;
1134 104 break;
1135 }
1136
1/2
✓ Branch 4 taken 676 times.
✗ Branch 5 not taken.
676 body->PutRaw(entry.buffer().data(), entry.size());
1137 676 num_encoded++;
1138
6/8
✓ Branch 1 taken 676 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 104 times.
✓ Branch 6 taken 676 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 104 times.
910 }
1139
1/2
✓ Branch 1 taken 130 times.
✗ Branch 2 not taken.
130 body->PutBool(false);
1140
1/2
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
130 body->PutBool(index >= entries.size());
1141 130 return NFS4_OK;
1142 156 }
1143
1144
1145 13 uint32_t Nfs4Server::OpReadlink(Compound *c, XdrWriter *body) {
1146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!c->has_fh)
1147 ✗ return NFS4ERR_NOFILEHANDLE;
1148 13 Object obj;
1149
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 const uint32_t status = Resolve(c->fh, c->call->creds, &obj);
1150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (status != NFS4_OK)
1151 ✗ return status;
1152
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if (obj.fh.kind != FileHandle::kObject || !S_ISLNK(obj.attr.mode))
1153 ✗ return S_ISDIR(obj.attr.mode) ? NFS4ERR_ISDIR : NFS4ERR_INVAL;
1154 13 std::string target;
1155
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 const int retval = backend_->ReadLink(obj.fh.ino, &target);
1156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (retval != 0)
1157 ✗ return ErrnoToStatus(retval);
1158
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 body->PutString(target);
1159 13 return NFS4_OK;
1160 13 }
1161
1162
1163 ✗ uint32_t Nfs4Server::OpSecinfo(XdrReader *args, Compound *c, XdrWriter *body) {
1164 ✗ std::string name;
1165 ✗ if (!args->GetString(&name, kNfs4OpaqueLimit))
1166 ✗ return NFS4ERR_BADXDR;
1167 ✗ if (!c->has_fh)
1168 ✗ return NFS4ERR_NOFILEHANDLE;
1169 ✗ Object dir, child;
1170 ✗ uint32_t status = Resolve(c->fh, c->call->creds, &dir);
1171 ✗ if (status != NFS4_OK)
1172 ✗ return status;
1173 ✗ status = LookupChild(dir, name, c->call->creds, &child);
1174 ✗ if (status != NFS4_OK)
1175 ✗ return status;
1176 // RFC 7530 16.31.4: SECINFO consumes the current file handle
1177 ✗ c->has_fh = false;
1178 ✗ body->PutU32(1);
1179 ✗ body->PutU32(kAuthSys);
1180 ✗ return NFS4_OK;
1181 }
1182
1183
1184 //------------------------------------------------------------------------------
1185 // Client and open state
1186
1187
1188 143 void Nfs4Server::PutStateid(const Stateid &stateid, XdrWriter *w) {
1189 143 w->PutU32(stateid.seqid);
1190 143 w->PutFixedOpaque(stateid.other.data(), kStateidOtherSize);
1191 143 }
1192
1193
1194 156 bool Nfs4Server::GetStateid(XdrReader *r, Stateid *stateid) {
1195 unsigned char other[kStateidOtherSize];
1196
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 if (!r->GetU32(&stateid->seqid)
1197
4/8
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
156 || !r->GetFixedOpaque(other, kStateidOtherSize)) {
1198 ✗ return false;
1199 }
1200
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 stateid->other.assign(reinterpret_cast<char *>(other), kStateidOtherSize);
1201 156 return true;
1202 }
1203
1204
1205 52 std::string Nfs4Server::NewStateidOther() {
1206 52 XdrWriter w;
1207
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 w.PutU32(boot_);
1208
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 w.PutU64(next_stateid_++);
1209
1/2
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
104 return w.buffer();
1210 52 }
1211
1212
1213 221 uint32_t Nfs4Server::CheckClient(uint64_t clientid) {
1214
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 208 times.
221 if (static_cast<uint32_t>(clientid >> 32) != boot_)
1215 13 return NFS4ERR_STALE_CLIENTID;
1216
1/2
✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
208 std::map<uint64_t, Client>::const_iterator const it = clients_.find(clientid);
1217
5/6
✓ Branch 3 taken 195 times.
✓ Branch 4 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 195 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 195 times.
208 if (it == clients_.end() || !it->second.confirmed)
1218 13 return NFS4ERR_STALE_CLIENTID;
1219 195 return NFS4_OK;
1220 }
1221
1222
1223 195 Nfs4Server::SeqidCheck Nfs4Server::CheckSeqid(const OwnerKey &owner,
1224 uint32_t seqid, uint32_t op,
1225 bool create_owner,
1226 uint32_t *status,
1227 std::string *body) {
1228
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 std::map<OwnerKey, OpenOwner>::iterator const it = owners_.find(owner);
1229
2/2
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 143 times.
195 if (it == owners_.end()) {
1230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (!create_owner) {
1231 ✗ *status = NFS4ERR_BAD_SEQID;
1232 ✗ return kSeqidBad;
1233 }
1234 52 return kSeqidProcess;
1235 }
1236
2/2
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 13 times.
143 if (seqid == it->second.seqid + 1)
1237 130 return kSeqidProcess;
1238
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
13 if (seqid == it->second.seqid && it->second.last_op == op) {
1239 ✗ *status = it->second.last_status;
1240 ✗ *body = it->second.last_body;
1241 ✗ return kSeqidReplay;
1242 }
1243 13 *status = NFS4ERR_BAD_SEQID;
1244 13 return kSeqidBad;
1245 }
1246
1247
1248 182 void Nfs4Server::RecordSeqid(const OwnerKey &owner, uint32_t seqid, uint32_t op,
1249 uint32_t status, const std::string &body) {
1250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 182 times.
182 if (!SeqidAdvances(status))
1251 ✗ return;
1252 182 OpenOwner &o = owners_[owner];
1253 182 o.seqid = seqid;
1254 182 o.last_op = op;
1255 182 o.last_status = status;
1256 182 o.last_body = body;
1257 }
1258
1259
1260 78 uint32_t Nfs4Server::FindOpenState(
1261 const Stateid &stateid, bool exact_seqid,
1262 std::map<std::string, OpenState>::iterator *it) {
1263 78 XdrReader r(reinterpret_cast<const unsigned char *>(stateid.other.data()),
1264 156 stateid.other.size());
1265 uint32_t boot;
1266
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 r.GetU32(&boot);
1267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (boot != boot_)
1268 ✗ return NFS4ERR_STALE_STATEID;
1269
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 *it = open_states_.find(stateid.other);
1270
2/2
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 52 times.
78 if (*it == open_states_.end())
1271 26 return NFS4ERR_BAD_STATEID;
1272 52 const uint32_t current = (*it)->second.seqid;
1273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (stateid.seqid > current)
1274 ✗ return NFS4ERR_BAD_STATEID;
1275
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
52 if (exact_seqid && stateid.seqid < current)
1276 13 return NFS4ERR_OLD_STATEID;
1277 39 return NFS4_OK;
1278 }
1279
1280
1281 91 uint32_t Nfs4Server::CheckReadStateid(const Stateid &stateid,
1282 const FileHandle &fh) {
1283
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 const std::string zeros(kStateidOtherSize, '\0');
1284
1/2
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
91 const std::string ones(kStateidOtherSize, '\xff');
1285
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
52 if ((stateid.seqid == 0 && stateid.other == zeros)
1286
5/8
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 52 times.
✓ Branch 8 taken 39 times.
143 || (stateid.seqid == 0xffffffffu && stateid.other == ones)) {
1287 52 return NFS4_OK;
1288 }
1289 39 std::map<std::string, OpenState>::iterator it;
1290
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const uint32_t status = FindOpenState(stateid, false, &it);
1291
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (status == NFS4ERR_BAD_STATEID) {
1292 std::map<std::string, Delegation>::const_iterator const d =
1293
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 delegations_.find(stateid.other);
1294
3/6
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
13 if (d != delegations_.end() && d->second.fh == fh)
1295 13 return NFS4_OK;
1296 }
1297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (status != NFS4_OK)
1298 ✗ return status;
1299
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
26 if (!(it->second.fh == fh))
1300 13 return NFS4ERR_BAD_STATEID;
1301 13 return NFS4_OK;
1302 91 }
1303
1304
1305 13 void Nfs4Server::DropClient(uint64_t clientid) {
1306
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 clients_.erase(clientid);
1307 struct Refreeze {
1308 13 explicit Refreeze(Nfs4Server *s) : server(s) { }
1309 13 ~Refreeze() { server->UpdateFrozenAttrs(); }
1310 Nfs4Server *server;
1311 13 } const refreeze(this);
1312 13 for (std::set<std::pair<uint64_t, uint64_t> >::iterator it =
1313 13 recalled_files_.begin();
1314
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 it != recalled_files_.end();) {
1315 ✗ if (it->first == clientid)
1316 ✗ recalled_files_.erase(it++);
1317 else
1318 ✗ ++it;
1319 }
1320 13 for (std::map<std::string, Delegation>::iterator it = delegations_.begin();
1321
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 it != delegations_.end();) {
1322 ✗ if (it->second.clientid == clientid)
1323 ✗ delegations_.erase(it++);
1324 else
1325 ✗ ++it;
1326 }
1327 13 for (std::map<std::string, OpenState>::iterator it = open_states_.begin();
1328
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
26 it != open_states_.end();) {
1329
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (it->second.owner.first == clientid)
1330
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 open_states_.erase(it++);
1331 else
1332 ✗ ++it;
1333 }
1334 13 for (std::map<OwnerKey, OpenOwner>::iterator it = owners_.begin();
1335
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
26 it != owners_.end();) {
1336
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (it->first.first == clientid)
1337
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 owners_.erase(it++);
1338 else
1339 ✗ ++it;
1340 }
1341 13 }
1342
1343
1344 65 void Nfs4Server::UpdateFrozenAttrs() {
1345 65 frozen_attrs_.clear();
1346 65 for (std::map<std::string, Delegation>::const_iterator it =
1347 65 delegations_.begin();
1348
2/2
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 65 times.
91 it != delegations_.end();
1349 26 ++it) {
1350
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 if (it->second.recalled != 0)
1351
1/2
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
26 frozen_attrs_[it->second.fh.ino] = it->second.attr;
1352 }
1353 65 num_frozen_attrs_ = frozen_attrs_.size();
1354 65 }
1355
1356
1357 117 void Nfs4Server::PutDelegation(uint64_t clientid, const FileHandle &fh,
1358 const Attr &attr, XdrWriter *w) {
1359
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 std::map<uint64_t, Client>::const_iterator const client = clients_.find(clientid);
1360
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 bool grant = options_.delegations && fh.kind == FileHandle::kObject
1361
5/6
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 39 times.
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 65 times.
195 && client != clients_.end() && client->second.callback_ok;
1362 117 for (std::map<std::string, Delegation>::const_iterator it =
1363 117 delegations_.begin();
1364
4/6
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
117 grant && it != delegations_.end();
1365 ✗ ++it) {
1366 // One delegation per client and file; none while a recall is going on
1367 ✗ if ((it->second.clientid == clientid && it->second.fh == fh)
1368 ✗ || it->second.recalled != 0) {
1369 ✗ grant = false;
1370 }
1371 }
1372
6/10
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 117 times.
117 if (grant && recalled_files_.erase(std::make_pair(clientid, fh.ino)) > 0)
1373 ✗ grant = false;
1374
5/6
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 104 times.
✓ Branch 6 taken 13 times.
117 if (!grant || delegations_.size() >= options_.max_stateids) {
1375
1/2
✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
104 w->PutU32(OPEN_DELEGATE_NONE);
1376 104 return;
1377 }
1378
1379 13 Stateid stateid;
1380
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 stateid.other = NewStateidOther();
1381
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 Delegation &delegation = delegations_[stateid.other];
1382 13 delegation.clientid = clientid;
1383 13 delegation.fh = fh;
1384 13 delegation.attr = attr;
1385 13 stateid.seqid = delegation.seqid;
1386
1387
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 w->PutU32(OPEN_DELEGATE_READ);
1388
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 PutStateid(stateid, w);
1389
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 w->PutBool(false); // recall
1390 // permissions: none granted in advance, the client still asks ACCESS
1391
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 w->PutU32(0); // ACE4_ACCESS_ALLOWED_ACE_TYPE
1392
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 w->PutU32(0); // flags
1393
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 w->PutU32(0); // access mask
1394
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
13 w->PutString("EVERYONE@");
1395 13 }
1396
1397
1398 26 uint32_t Nfs4Server::OpDelegreturn(XdrReader *args) {
1399 26 Stateid stateid;
1400
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if (!GetStateid(args, &stateid))
1401 ✗ return NFS4ERR_BADXDR;
1402
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 std::lock_guard<std::mutex> const lock(state_lock_);
1403 26 XdrReader r(reinterpret_cast<const unsigned char *>(stateid.other.data()),
1404 52 stateid.other.size());
1405 uint32_t boot;
1406
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 r.GetU32(&boot);
1407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (boot != boot_)
1408 ✗ return NFS4ERR_STALE_STATEID;
1409
3/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 13 times.
26 if (delegations_.erase(stateid.other) == 0)
1410 13 return NFS4ERR_BAD_STATEID;
1411
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (num_frozen_attrs_ > 0)
1412
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 UpdateFrozenAttrs();
1413 13 return NFS4_OK;
1414 26 }
1415
1416
1417 13 void Nfs4Server::StartMonitor() {
1418
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (!monitor_.joinable())
1419
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 monitor_ = std::thread(&Nfs4Server::MonitorLoop, this);
1420 13 }
1421
1422
1423 13 void Nfs4Server::MonitorLoop() {
1424 13 const unsigned kCallbackTimeoutMs = 5000;
1425
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 std::unique_lock<std::mutex> lock(state_lock_);
1426
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 while (!monitor_stopping_) {
1427
1/2
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
39 monitor_cond_.wait_for(lock, std::chrono::seconds(1));
1428
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (monitor_stopping_)
1429 13 break;
1430
1431 // Probe new callback paths
1432 26 std::vector<uint64_t> probes;
1433 26 probes.swap(pending_probes_);
1434 26 std::vector<std::pair<uint64_t, std::shared_ptr<CallbackClient> > > cbs;
1435
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
39 for (unsigned i = 0; i < probes.size(); ++i) {
1436
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 std::map<uint64_t, Client>::iterator const c = clients_.find(probes[i]);
1437
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
13 if (c != clients_.end() && c->second.callback)
1438
2/4
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
13 cbs.push_back(std::make_pair(probes[i], c->second.callback));
1439 }
1440
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 lock.unlock();
1441 26 std::vector<bool> probe_ok;
1442
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
39 for (unsigned i = 0; i < cbs.size(); ++i)
1443
2/4
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
13 probe_ok.push_back(cbs[i].second->Null(kCallbackTimeoutMs));
1444
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 const uint64_t generation = backend_->Generation();
1445
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 lock.lock();
1446
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
39 for (unsigned i = 0; i < cbs.size(); ++i) {
1447
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 std::map<uint64_t, Client>::iterator const c = clients_.find(cbs[i].first);
1448
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
13 if (c != clients_.end() && c->second.callback == cbs[i].second) {
1449
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 c->second.callback_ok = probe_ok[i];
1450
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
26 Log(kLogLevelDebug, "callback path of client %" PRIx64 " %s",
1451
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
39 cbs[i].first, probe_ok[i] ? "works" : "is down");
1452 }
1453 }
1454
1455 // Recall everything when the exported tree changed; revoke what was not
1456 // returned within a lease period
1457 26 const time_t now = time(NULL);
1458 52 const bool changed = (last_generation_ != 0)
1459
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
26 && (generation != last_generation_);
1460 26 last_generation_ = generation;
1461 struct Recall {
1462 std::string other;
1463 uint32_t seqid;
1464 std::string fh;
1465 std::shared_ptr<CallbackClient> callback;
1466 };
1467 26 std::vector<Recall> recalls;
1468 26 for (std::map<std::string, Delegation>::iterator it = delegations_.begin();
1469
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 26 times.
39 it != delegations_.end();) {
1470 13 Delegation &d = it->second;
1471
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13 if (d.recalled != 0 && now - d.recalled > options_.lease_time) {
1472 ✗ Log(kLogLevelWarn, "revoking unreturned delegation");
1473 ✗ delegations_.erase(it++);
1474 ✗ continue;
1475 }
1476
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 if (changed && d.recalled == 0) {
1477
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 std::map<uint64_t, Client>::iterator const c = clients_.find(d.clientid);
1478
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
13 if (c == clients_.end() || !c->second.callback) {
1479 ✗ delegations_.erase(it++);
1480 ✗ continue;
1481 }
1482 13 d.recalled = now;
1483
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 recalled_files_.insert(std::make_pair(d.clientid, d.fh.ino));
1484 13 Recall recall;
1485
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 recall.other = it->first;
1486 13 recall.seqid = d.seqid;
1487
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 recall.fh = d.fh.Encode();
1488 13 recall.callback = c->second.callback;
1489
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 recalls.push_back(recall);
1490 13 }
1491 13 ++it;
1492 }
1493
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 UpdateFrozenAttrs();
1494
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
26 if (recalls.empty())
1495 13 continue;
1496
1497
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 lock.unlock();
1498
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 Log(kLogLevelInfo, "recalling %zu delegations", recalls.size());
1499 13 std::vector<std::string> failed;
1500 13 const time_t recall_start = time(NULL);
1501
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
26 for (unsigned i = 0; i < recalls.size(); ++i) {
1502
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
26 const int result = recalls[i].callback->Recall(
1503 13 recalls[i].seqid, recalls[i].other, recalls[i].fh,
1504 kCallbackTimeoutMs);
1505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (result != NFS4_OK) {
1506 ✗ Log(kLogLevelWarn, "delegation recall failed (%d)", result);
1507 ✗ failed.push_back(recalls[i].other);
1508 }
1509 }
1510
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
26 Log(kLogLevelInfo, "sent %zu recalls in %lds, %zu failed", recalls.size(),
1511 13 static_cast<long>(time(NULL) - recall_start), failed.size()); // NOLINT
1512
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 lock.lock();
1513
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 for (unsigned i = 0; i < failed.size(); ++i)
1514 ✗ delegations_.erase(failed[i]);
1515
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 UpdateFrozenAttrs();
1516
8/8
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 13 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 13 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 13 times.
65 }
1517 13 }
1518
1519
1520 26 size_t Nfs4Server::NumDelegations() {
1521
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 std::lock_guard<std::mutex> const lock(state_lock_);
1522 52 return delegations_.size();
1523 26 }
1524
1525
1526 78 size_t Nfs4Server::NumOpenStates() {
1527
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 std::lock_guard<std::mutex> const lock(state_lock_);
1528 156 return open_states_.size();
1529 78 }
1530
1531
1532 65 uint32_t Nfs4Server::OpSetclientid(XdrReader *args, XdrWriter *body) {
1533 unsigned char verifier[kNfs4VerifierSize];
1534 65 std::string name, netid, addr;
1535 uint32_t cb_program, cb_ident;
1536
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetFixedOpaque(verifier, kNfs4VerifierSize);
1537
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetOpaque(&name, kNfs4OpaqueLimit);
1538
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetU32(&cb_program);
1539
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetString(&netid);
1540
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetString(&addr);
1541
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 args->GetU32(&cb_ident);
1542
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 if (!args->ok())
1543 ✗ return NFS4ERR_BADXDR;
1544
1/2
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
65 const std::string verf(reinterpret_cast<char *>(verifier), kNfs4VerifierSize);
1545
1546
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 std::lock_guard<std::mutex> const lock(state_lock_);
1547 65 uint64_t clientid = 0;
1548 65 for (std::map<uint64_t, Client>::iterator it = clients_.begin();
1549
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 65 times.
78 it != clients_.end();
1550 13 ++it) {
1551
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
26 if (it->second.name == name && it->second.confirmed
1552
3/6
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
26 && it->second.verifier == verf) {
1553 // Same client instance, e.g. callback update: keep the client id
1554 ✗ clientid = it->first;
1555 ✗ break;
1556 }
1557 }
1558
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (clientid == 0) {
1559 65 for (std::map<uint64_t, Client>::iterator it = clients_.begin();
1560
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 65 times.
78 it != clients_.end();) {
1561
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
13 if (it->second.name == name && !it->second.confirmed)
1562 ✗ clients_.erase(it++);
1563 else
1564 13 ++it;
1565 }
1566 65 clientid = (static_cast<uint64_t>(boot_) << 32) | next_clientid_++;
1567
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 Client &client = clients_[clientid];
1568
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 client.name = name;
1569
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 client.verifier = verf;
1570 }
1571
1572 65 XdrWriter confirm;
1573 130 confirm.PutU64((static_cast<uint64_t>(next_clientid_++) << 32)
1574
1/2
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
65 ^ static_cast<uint64_t>(time(NULL)));
1575
2/4
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
65 clients_[clientid].confirm = confirm.buffer();
1576
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 52 times.
65 if (options_.delegations) {
1577
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
26 clients_[clientid].callback.reset(
1578
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 new CallbackClient(cb_program, cb_ident, netid, addr));
1579
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 clients_[clientid].callback_ok = false;
1580 }
1581
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 body->PutU64(clientid);
1582
1/2
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
65 body->PutFixedOpaque(confirm.buffer().data(), kNfs4VerifierSize);
1583 65 return NFS4_OK;
1584 65 }
1585
1586
1587 65 uint32_t Nfs4Server::OpSetclientidConfirm(XdrReader *args) {
1588 uint64_t clientid;
1589 unsigned char confirm[kNfs4VerifierSize];
1590
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 if (!args->GetU64(&clientid)
1591
4/8
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 65 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 65 times.
65 || !args->GetFixedOpaque(confirm, kNfs4VerifierSize)) {
1592 ✗ return NFS4ERR_BADXDR;
1593 }
1594
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 std::lock_guard<std::mutex> const lock(state_lock_);
1595
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 std::map<uint64_t, Client>::iterator const it = clients_.find(clientid);
1596 65 if (it == clients_.end()
1597
2/4
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 65 times.
260 || it->second.confirm
1598
4/12
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 65 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 65 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
195 != std::string(reinterpret_cast<char *>(confirm),
1599 kNfs4VerifierSize)) {
1600 ✗ return NFS4ERR_STALE_CLIENTID;
1601 }
1602
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 if (options_.delegations && it->second.callback
1603
5/6
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 52 times.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 52 times.
78 && it->second.callback->valid()) {
1604
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 pending_probes_.push_back(clientid);
1605
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 StartMonitor();
1606 13 monitor_cond_.notify_all();
1607 }
1608
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 if (it->second.confirmed)
1609 ✗ return NFS4_OK;
1610
1611 65 it->second.confirmed = true;
1612
1/2
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
65 const std::string name = it->second.name;
1613 // A rebooted client replaces its previous incarnation and its state
1614 65 std::vector<uint64_t> previous;
1615 65 for (std::map<uint64_t, Client>::iterator i = clients_.begin();
1616
2/2
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 65 times.
143 i != clients_.end();
1617 78 ++i) {
1618
5/6
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 65 times.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 65 times.
78 if (i->first != clientid && i->second.name == name)
1619
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 previous.push_back(i->first);
1620 }
1621
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 65 times.
78 for (unsigned i = 0; i < previous.size(); ++i)
1622
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 DropClient(previous[i]);
1623 65 return NFS4_OK;
1624 65 }
1625
1626
1627 26 uint32_t Nfs4Server::OpRenew(XdrReader *args) {
1628 uint64_t clientid;
1629
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if (!args->GetU64(&clientid))
1630 ✗ return NFS4ERR_BADXDR;
1631
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 std::lock_guard<std::mutex> const lock(state_lock_);
1632
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 return CheckClient(clientid);
1633 26 }
1634
1635
1636 195 uint32_t Nfs4Server::OpOpen(XdrReader *args, Compound *c, XdrWriter *body) {
1637 uint32_t seqid, share_access, share_deny, open_type, claim_type;
1638 uint64_t clientid;
1639 195 std::string owner, name;
1640
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetU32(&seqid);
1641
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetU32(&share_access);
1642
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetU32(&share_deny);
1643
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetU64(&clientid);
1644
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetOpaque(&owner, kNfs4OpaqueLimit);
1645
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetU32(&open_type);
1646
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
195 if (!args->ok())
1647 ✗ return NFS4ERR_BADXDR;
1648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 if (open_type == OPEN4_CREATE) {
1649 // The create arguments are not needed: the file system is read-only
1650 ✗ return c->has_fh ? NFS4ERR_ROFS : NFS4ERR_NOFILEHANDLE;
1651 }
1652
2/4
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 195 times.
195 if (!args->GetU32(&claim_type))
1653 ✗ return NFS4ERR_BADXDR;
1654
1/4
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
195 switch (claim_type) {
1655 195 case CLAIM_NULL:
1656
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 args->GetString(&name, kNfs4OpaqueLimit);
1657 195 break;
1658 ✗ case CLAIM_PREVIOUS: {
1659 uint32_t delegation_type;
1660 ✗ args->GetU32(&delegation_type);
1661 ✗ break;
1662 }
1663 ✗ case CLAIM_DELEGATE_CUR: {
1664 // The client converts local opens before returning a delegation
1665 ✗ Stateid delegation;
1666 ✗ GetStateid(args, &delegation);
1667 ✗ args->GetString(&name, kNfs4OpaqueLimit);
1668 ✗ break;
1669 }
1670 ✗ default:
1671 // State of a previous server instance is not kept
1672 ✗ return NFS4ERR_RECLAIM_BAD;
1673 }
1674
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
195 if (!args->ok())
1675 ✗ return NFS4ERR_BADXDR;
1676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 if (!c->has_fh)
1677 ✗ return NFS4ERR_NOFILEHANDLE;
1678
1679
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
390 const OwnerKey owner_key(clientid, owner);
1680 390 std::string replay_body;
1681 uint32_t status;
1682 {
1683
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 std::lock_guard<std::mutex> const lock(state_lock_);
1684
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
195 status = CheckClient(clientid);
1685
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 182 times.
195 if (status != NFS4_OK)
1686 13 return status;
1687
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
182 const SeqidCheck check = CheckSeqid(owner_key, seqid, OP_OPEN, true,
1688 &status, &replay_body);
1689
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 169 times.
182 if (check == kSeqidBad)
1690 13 return status;
1691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
169 if (check == kSeqidReplay) {
1692 ✗ body->PutRaw(replay_body.data(), replay_body.size());
1693 ✗ return status;
1694 }
1695
2/2
✓ Branch 1 taken 169 times.
✓ Branch 2 taken 26 times.
195 }
1696
1697 338 Object target;
1698 338 Object dir;
1699
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
169 if (claim_type == CLAIM_NULL || claim_type == CLAIM_DELEGATE_CUR) {
1700
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 status = Resolve(c->fh, c->call->creds, &dir);
1701
1/2
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
169 if (status == NFS4_OK)
1702
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 status = LookupChild(dir, name, c->call->creds, &target);
1703 } else {
1704 ✗ status = Resolve(c->fh, c->call->creds, &target);
1705 }
1706
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 13 times.
169 if (status == NFS4_OK) {
1707
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 13 times.
156 if ((share_access & OPEN4_SHARE_ACCESS_WRITE)
1708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 || !(share_access & OPEN4_SHARE_ACCESS_READ)) {
1709 13 status = NFS4ERR_ROFS;
1710
1/2
✓ Branch 0 taken 143 times.
✗ Branch 1 not taken.
143 } else if (target.fh.kind == FileHandle::kAttrDir
1711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 || S_ISDIR(target.attr.mode)) {
1712 ✗ status = NFS4ERR_ISDIR;
1713
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 130 times.
143 } else if (S_ISLNK(target.attr.mode)) {
1714 13 status = NFS4ERR_SYMLINK;
1715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 } else if (!S_ISREG(target.attr.mode)) {
1716 ✗ status = NFS4ERR_INVAL;
1717
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 117 times.
130 } else if (!(AccessFromMode(target.attr, c->call->creds) & ACCESS4_READ)) {
1718 13 status = NFS4ERR_ACCESS;
1719 }
1720 }
1721
1722 338 XdrWriter result;
1723
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
338 std::lock_guard<std::mutex> const lock(state_lock_);
1724
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 52 times.
169 if (status == NFS4_OK) {
1725 // Repeated opens of a file by the same owner share one stateid
1726 117 std::map<std::string, OpenState>::iterator it = open_states_.begin();
1727
2/2
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 39 times.
117 for (; it != open_states_.end(); ++it) {
1728
3/6
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 78 times.
✗ Branch 9 not taken.
78 if (it->second.owner == owner_key && it->second.fh == target.fh)
1729 78 break;
1730 }
1731
2/2
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 78 times.
117 if (it == open_states_.end()) {
1732
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if (open_states_.size() >= options_.max_stateids) {
1733 ✗ Log(kLogLevelWarn, "too many open NFS stateids (%u)", options_.max_stateids);
1734 ✗ return NFS4ERR_RESOURCE;
1735 }
1736
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const std::string other = NewStateidOther();
1737
3/6
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
39 it = open_states_.insert(std::make_pair(other, OpenState())).first;
1738
1/2
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
39 it->second.owner = owner_key;
1739 39 it->second.fh = target.fh;
1740 39 }
1741 117 it->second.seqid++;
1742 117 it->second.access |= share_access;
1743
1744 117 Stateid stateid;
1745 117 stateid.seqid = it->second.seqid;
1746
1/2
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
117 stateid.other = it->first;
1747
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 PutStateid(stateid, &result);
1748 // change_info4: nothing changes in a read-only directory
1749
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result.PutBool(true);
1750
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result.PutU64(0);
1751
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result.PutU64(0);
1752 // No OPEN4_RESULT_CONFIRM: a confirm round trip buys nothing here
1753
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result.PutU32(OPEN4_RESULT_LOCKTYPE_POSIX);
1754
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result.PutU32(0); // attrset
1755
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (claim_type == CLAIM_NULL)
1756
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 PutDelegation(clientid, target.fh, target.attr, &result);
1757 else
1758 ✗ result.PutU32(OPEN_DELEGATE_NONE);
1759 117 c->fh = target.fh;
1760 117 }
1761
1/2
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
169 RecordSeqid(owner_key, seqid, OP_OPEN, status, result.buffer());
1762
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 52 times.
169 if (status == NFS4_OK)
1763
1/2
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
117 body->PutRaw(result.buffer().data(), result.size());
1764 169 return status;
1765 195 }
1766
1767
1768 ✗ uint32_t Nfs4Server::OpOpenConfirm(XdrReader *args, Compound *c,
1769 XdrWriter *body) {
1770 ✗ Stateid stateid;
1771 uint32_t seqid;
1772 ✗ if (!GetStateid(args, &stateid) || !args->GetU32(&seqid))
1773 ✗ return NFS4ERR_BADXDR;
1774 ✗ if (!c->has_fh)
1775 ✗ return NFS4ERR_NOFILEHANDLE;
1776
1777 ✗ std::lock_guard<std::mutex> const lock(state_lock_);
1778 ✗ std::map<std::string, OpenState>::iterator it;
1779 ✗ uint32_t status = FindOpenState(stateid, true, &it);
1780 ✗ if (status != NFS4_OK)
1781 ✗ return status;
1782 ✗ const OwnerKey owner = it->second.owner;
1783 ✗ std::string replay_body;
1784 ✗ const SeqidCheck check = CheckSeqid(owner, seqid, OP_OPEN_CONFIRM, false,
1785 &status, &replay_body);
1786 ✗ if (check == kSeqidBad)
1787 ✗ return status;
1788 ✗ if (check == kSeqidReplay) {
1789 ✗ body->PutRaw(replay_body.data(), replay_body.size());
1790 ✗ return status;
1791 }
1792
1793 ✗ it->second.seqid++;
1794 ✗ Stateid result;
1795 ✗ result.seqid = it->second.seqid;
1796 ✗ result.other = it->first;
1797 ✗ XdrWriter w;
1798 ✗ PutStateid(result, &w);
1799 ✗ RecordSeqid(owner, seqid, OP_OPEN_CONFIRM, NFS4_OK, w.buffer());
1800 ✗ body->PutRaw(w.buffer().data(), w.size());
1801 ✗ return NFS4_OK;
1802 }
1803
1804
1805 ✗ uint32_t Nfs4Server::OpOpenDowngrade(XdrReader *args, Compound *c,
1806 XdrWriter *body) {
1807 ✗ Stateid stateid;
1808 uint32_t seqid, share_access, share_deny;
1809 ✗ if (!GetStateid(args, &stateid) || !args->GetU32(&seqid)
1810 ✗ || !args->GetU32(&share_access) || !args->GetU32(&share_deny)) {
1811 ✗ return NFS4ERR_BADXDR;
1812 }
1813 ✗ if (!c->has_fh)
1814 ✗ return NFS4ERR_NOFILEHANDLE;
1815
1816 ✗ std::lock_guard<std::mutex> const lock(state_lock_);
1817 ✗ std::map<std::string, OpenState>::iterator it;
1818 ✗ uint32_t status = FindOpenState(stateid, true, &it);
1819 ✗ if (status != NFS4_OK)
1820 ✗ return status;
1821 ✗ const OwnerKey owner = it->second.owner;
1822 ✗ std::string replay_body;
1823 ✗ const SeqidCheck check = CheckSeqid(owner, seqid, OP_OPEN_DOWNGRADE, false,
1824 &status, &replay_body);
1825 ✗ if (check == kSeqidBad)
1826 ✗ return status;
1827 ✗ if (check == kSeqidReplay) {
1828 ✗ body->PutRaw(replay_body.data(), replay_body.size());
1829 ✗ return status;
1830 }
1831
1832 ✗ XdrWriter w;
1833 ✗ if ((share_access & ~it->second.access) != 0) {
1834 ✗ status = NFS4ERR_INVAL;
1835 } else {
1836 ✗ it->second.access = share_access;
1837 ✗ it->second.seqid++;
1838 ✗ Stateid result;
1839 ✗ result.seqid = it->second.seqid;
1840 ✗ result.other = it->first;
1841 ✗ PutStateid(result, &w);
1842 ✗ status = NFS4_OK;
1843 }
1844 ✗ RecordSeqid(owner, seqid, OP_OPEN_DOWNGRADE, status, w.buffer());
1845 ✗ body->PutRaw(w.buffer().data(), w.size());
1846 ✗ return status;
1847 }
1848
1849
1850 39 uint32_t Nfs4Server::OpClose(XdrReader *args, Compound *c, XdrWriter *body) {
1851 uint32_t seqid;
1852 39 Stateid stateid;
1853
5/10
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 39 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 39 times.
39 if (!args->GetU32(&seqid) || !GetStateid(args, &stateid))
1854 ✗ return NFS4ERR_BADXDR;
1855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!c->has_fh)
1856 ✗ return NFS4ERR_NOFILEHANDLE;
1857
1858 39 uint64_t forget_ino = 0;
1859 {
1860
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 std::lock_guard<std::mutex> const lock(state_lock_);
1861 39 std::map<std::string, OpenState>::iterator it;
1862
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 uint32_t status = FindOpenState(stateid, true, &it);
1863
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (status == NFS4ERR_BAD_STATEID) {
1864 // The stateid is gone after a CLOSE, so a retransmitted CLOSE is only
1865 // recognizable by the owner's cached reply
1866 13 for (std::map<OwnerKey, OpenOwner>::const_iterator o = owners_.begin();
1867
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
13 o != owners_.end();
1868 ✗ ++o) {
1869 13 const OpenOwner &owner = o->second;
1870
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (owner.last_op == OP_CLOSE && owner.seqid == seqid
1871
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 && owner.last_body.size() == 4 + kStateidOtherSize
1872
4/8
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
26 && owner.last_body.compare(4, kStateidOtherSize, stateid.other)
1873 == 0) {
1874
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
13 body->PutRaw(owner.last_body.data(), owner.last_body.size());
1875 13 return owner.last_status;
1876 }
1877 }
1878 }
1879
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (status != NFS4_OK)
1880 13 return status;
1881
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 const OwnerKey owner = it->second.owner;
1882 13 std::string replay_body;
1883
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 const SeqidCheck check = CheckSeqid(owner, seqid, OP_CLOSE, false, &status,
1884 &replay_body);
1885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (check == kSeqidBad)
1886 ✗ return status;
1887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (check == kSeqidReplay) {
1888 ✗ body->PutRaw(replay_body.data(), replay_body.size());
1889 ✗ return status;
1890 }
1891
1892 13 Stateid result;
1893 13 result.seqid = it->second.seqid + 1;
1894
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 result.other = it->first;
1895 13 const FileHandle fh = it->second.fh;
1896
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 open_states_.erase(it);
1897 13 bool still_open = false;
1898
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
13 for (it = open_states_.begin(); it != open_states_.end(); ++it) {
1899 ✗ if (it->second.fh.ino == fh.ino) {
1900 ✗ still_open = true;
1901 ✗ break;
1902 }
1903 }
1904
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 if (!still_open && fh.kind == FileHandle::kObject)
1905 13 forget_ino = fh.ino;
1906
1907 13 XdrWriter w;
1908
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 PutStateid(result, &w);
1909
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 RecordSeqid(owner, seqid, OP_CLOSE, NFS4_OK, w.buffer());
1910
1/2
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 body->PutRaw(w.buffer().data(), w.size());
1911
4/6
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 26 times.
39 }
1912
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (forget_ino != 0)
1913
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 backend_->Forget(forget_ino);
1914 13 return NFS4_OK;
1915 39 }
1916
1917 } // namespace nfs4
1918