]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fusefs/mockfs.cc
unbound: Vendor import 1.17.0
[FreeBSD/FreeBSD.git] / tests / sys / fs / fusefs / mockfs.cc
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 The FreeBSD Foundation
5  *
6  * This software was developed by BFF Storage Systems, LLC under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 extern "C" {
34 #include <sys/param.h>
35
36 #include <sys/mount.h>
37 #include <sys/select.h>
38 #include <sys/stat.h>
39 #include <sys/uio.h>
40 #include <sys/user.h>
41
42 #include <fcntl.h>
43 #include <libutil.h>
44 #include <poll.h>
45 #include <pthread.h>
46 #include <signal.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49
50 #include "mntopts.h"    // for build_iovec
51 }
52
53 #include <cinttypes>
54
55 #include <gtest/gtest.h>
56
57 #include "mockfs.hh"
58
59 using namespace testing;
60
61 int verbosity = 0;
62
63 const char* opcode2opname(uint32_t opcode)
64 {
65         const char* table[] = {
66                 "Unknown (opcode 0)",
67                 "LOOKUP",
68                 "FORGET",
69                 "GETATTR",
70                 "SETATTR",
71                 "READLINK",
72                 "SYMLINK",
73                 "Unknown (opcode 7)",
74                 "MKNOD",
75                 "MKDIR",
76                 "UNLINK",
77                 "RMDIR",
78                 "RENAME",
79                 "LINK",
80                 "OPEN",
81                 "READ",
82                 "WRITE",
83                 "STATFS",
84                 "RELEASE",
85                 "Unknown (opcode 19)",
86                 "FSYNC",
87                 "SETXATTR",
88                 "GETXATTR",
89                 "LISTXATTR",
90                 "REMOVEXATTR",
91                 "FLUSH",
92                 "INIT",
93                 "OPENDIR",
94                 "READDIR",
95                 "RELEASEDIR",
96                 "FSYNCDIR",
97                 "GETLK",
98                 "SETLK",
99                 "SETLKW",
100                 "ACCESS",
101                 "CREATE",
102                 "INTERRUPT",
103                 "BMAP",
104                 "DESTROY",
105                 "IOCTL",
106                 "POLL",
107                 "NOTIFY_REPLY",
108                 "BATCH_FORGET",
109                 "FALLOCATE",
110                 "READDIRPLUS",
111                 "RENAME2",
112                 "LSEEK",
113                 "COPY_FILE_RANGE",
114         };
115         if (opcode >= nitems(table))
116                 return ("Unknown (opcode > max)");
117         else
118                 return (table[opcode]);
119 }
120
121 ProcessMockerT
122 ReturnErrno(int error)
123 {
124         return([=](auto in, auto &out) {
125                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
126                 out0->header.unique = in.header.unique;
127                 out0->header.error = -error;
128                 out0->header.len = sizeof(out0->header);
129                 out.push_back(std::move(out0));
130         });
131 }
132
133 /* Helper function used for returning negative cache entries for LOOKUP */
134 ProcessMockerT
135 ReturnNegativeCache(const struct timespec *entry_valid)
136 {
137         return([=](auto in, auto &out) {
138                 /* nodeid means ENOENT and cache it */
139                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
140                 out0->body.entry.nodeid = 0;
141                 out0->header.unique = in.header.unique;
142                 out0->header.error = 0;
143                 out0->body.entry.entry_valid = entry_valid->tv_sec;
144                 out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec;
145                 SET_OUT_HEADER_LEN(*out0, entry);
146                 out.push_back(std::move(out0));
147         });
148 }
149
150 ProcessMockerT
151 ReturnImmediate(std::function<void(const mockfs_buf_in& in,
152                                    struct mockfs_buf_out &out)> f)
153 {
154         return([=](auto& in, auto &out) {
155                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
156                 out0->header.unique = in.header.unique;
157                 f(in, *out0);
158                 out.push_back(std::move(out0));
159         });
160 }
161
162 void sigint_handler(int __unused sig) {
163         // Don't do anything except interrupt the daemon's read(2) call
164 }
165
166 void MockFS::debug_request(const mockfs_buf_in &in, ssize_t buflen)
167 {
168         printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode),
169                 in.header.nodeid);
170         if (verbosity > 1) {
171                 printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u"
172                         " buflen=%zd",
173                         in.header.uid, in.header.gid, in.header.pid,
174                         in.header.unique, in.header.len, buflen);
175         }
176         switch (in.header.opcode) {
177                 const char *name, *value;
178
179                 case FUSE_ACCESS:
180                         printf(" mask=%#x", in.body.access.mask);
181                         break;
182                 case FUSE_BMAP:
183                         printf(" block=%" PRIx64 " blocksize=%#x",
184                                 in.body.bmap.block, in.body.bmap.blocksize);
185                         break;
186                 case FUSE_COPY_FILE_RANGE:
187                         printf(" off_in=%" PRIu64 " ino_out=%" PRIu64
188                                " off_out=%" PRIu64 " size=%" PRIu64,
189                                in.body.copy_file_range.off_in,
190                                in.body.copy_file_range.nodeid_out,
191                                in.body.copy_file_range.off_out,
192                                in.body.copy_file_range.len);
193                         if (verbosity > 1)
194                                 printf(" fh_in=%" PRIu64 " fh_out=%" PRIu64
195                                        " flags=%" PRIx64,
196                                        in.body.copy_file_range.fh_in,
197                                        in.body.copy_file_range.fh_out,
198                                        in.body.copy_file_range.flags);
199                         break;
200                 case FUSE_CREATE:
201                         if (m_kernel_minor_version >= 12)
202                                 name = (const char*)in.body.bytes +
203                                         sizeof(fuse_create_in);
204                         else
205                                 name = (const char*)in.body.bytes +
206                                         sizeof(fuse_open_in);
207                         printf(" flags=%#x name=%s",
208                                 in.body.open.flags, name);
209                         break;
210                 case FUSE_FALLOCATE:
211                         printf(" fh=%#" PRIx64 " offset=%" PRIu64
212                                 " length=%" PRIx64 " mode=%#x",
213                                 in.body.fallocate.fh,
214                                 in.body.fallocate.offset,
215                                 in.body.fallocate.length,
216                                 in.body.fallocate.mode);
217                         break;
218                 case FUSE_FLUSH:
219                         printf(" fh=%#" PRIx64 " lock_owner=%" PRIu64,
220                                 in.body.flush.fh,
221                                 in.body.flush.lock_owner);
222                         break;
223                 case FUSE_FORGET:
224                         printf(" nlookup=%" PRIu64, in.body.forget.nlookup);
225                         break;
226                 case FUSE_FSYNC:
227                         printf(" flags=%#x", in.body.fsync.fsync_flags);
228                         break;
229                 case FUSE_FSYNCDIR:
230                         printf(" flags=%#x", in.body.fsyncdir.fsync_flags);
231                         break;
232                 case FUSE_INTERRUPT:
233                         printf(" unique=%" PRIu64, in.body.interrupt.unique);
234                         break;
235                 case FUSE_LINK:
236                         printf(" oldnodeid=%" PRIu64, in.body.link.oldnodeid);
237                         break;
238                 case FUSE_LISTXATTR:
239                         printf(" size=%" PRIu32, in.body.listxattr.size);
240                         break;
241                 case FUSE_LOOKUP:
242                         printf(" %s", in.body.lookup);
243                         break;
244                 case FUSE_LSEEK:
245                         switch (in.body.lseek.whence) {
246                         case SEEK_HOLE:
247                                 printf(" SEEK_HOLE offset=%jd",
248                                     in.body.lseek.offset);
249                                 break;
250                         case SEEK_DATA:
251                                 printf(" SEEK_DATA offset=%jd",
252                                     in.body.lseek.offset);
253                                 break;
254                         default:
255                                 printf(" whence=%u offset=%jd",
256                                     in.body.lseek.whence, in.body.lseek.offset);
257                                 break;
258                         }
259                         break;
260                 case FUSE_MKDIR:
261                         name = (const char*)in.body.bytes +
262                                 sizeof(fuse_mkdir_in);
263                         printf(" name=%s mode=%#o umask=%#o", name,
264                                 in.body.mkdir.mode, in.body.mkdir.umask);
265                         break;
266                 case FUSE_MKNOD:
267                         if (m_kernel_minor_version >= 12)
268                                 name = (const char*)in.body.bytes +
269                                         sizeof(fuse_mknod_in);
270                         else
271                                 name = (const char*)in.body.bytes +
272                                         FUSE_COMPAT_MKNOD_IN_SIZE;
273                         printf(" mode=%#o rdev=%x umask=%#o name=%s",
274                                 in.body.mknod.mode, in.body.mknod.rdev,
275                                 in.body.mknod.umask, name);
276                         break;
277                 case FUSE_OPEN:
278                         printf(" flags=%#x", in.body.open.flags);
279                         break;
280                 case FUSE_OPENDIR:
281                         printf(" flags=%#x", in.body.opendir.flags);
282                         break;
283                 case FUSE_READ:
284                         printf(" offset=%" PRIu64 " size=%u",
285                                 in.body.read.offset,
286                                 in.body.read.size);
287                         if (verbosity > 1)
288                                 printf(" flags=%#x", in.body.read.flags);
289                         break;
290                 case FUSE_READDIR:
291                         printf(" fh=%#" PRIx64 " offset=%" PRIu64 " size=%u",
292                                 in.body.readdir.fh, in.body.readdir.offset,
293                                 in.body.readdir.size);
294                         break;
295                 case FUSE_RELEASE:
296                         printf(" fh=%#" PRIx64 " flags=%#x lock_owner=%" PRIu64,
297                                 in.body.release.fh,
298                                 in.body.release.flags,
299                                 in.body.release.lock_owner);
300                         break;
301                 case FUSE_RENAME:
302                         {
303                                 const char *src = (const char*)in.body.bytes +
304                                         sizeof(fuse_rename_in);
305                                 const char *dst = src + strlen(src) + 1;
306                                 printf(" src=%s newdir=%" PRIu64 " dst=%s",
307                                         src, in.body.rename.newdir, dst);
308                         }
309                         break;
310                 case FUSE_SETATTR:
311                         if (verbosity <= 1) {
312                                 printf(" valid=%#x", in.body.setattr.valid);
313                                 break;
314                         }
315                         if (in.body.setattr.valid & FATTR_MODE)
316                                 printf(" mode=%#o", in.body.setattr.mode);
317                         if (in.body.setattr.valid & FATTR_UID)
318                                 printf(" uid=%u", in.body.setattr.uid);
319                         if (in.body.setattr.valid & FATTR_GID)
320                                 printf(" gid=%u", in.body.setattr.gid);
321                         if (in.body.setattr.valid & FATTR_SIZE)
322                                 printf(" size=%" PRIu64, in.body.setattr.size);
323                         if (in.body.setattr.valid & FATTR_ATIME)
324                                 printf(" atime=%" PRIu64 ".%u",
325                                         in.body.setattr.atime,
326                                         in.body.setattr.atimensec);
327                         if (in.body.setattr.valid & FATTR_MTIME)
328                                 printf(" mtime=%" PRIu64 ".%u",
329                                         in.body.setattr.mtime,
330                                         in.body.setattr.mtimensec);
331                         if (in.body.setattr.valid & FATTR_FH)
332                                 printf(" fh=%" PRIu64 "", in.body.setattr.fh);
333                         break;
334                 case FUSE_SETLK:
335                         printf(" fh=%#" PRIx64 " owner=%" PRIu64
336                                 " type=%u pid=%u",
337                                 in.body.setlk.fh, in.body.setlk.owner,
338                                 in.body.setlk.lk.type,
339                                 in.body.setlk.lk.pid);
340                         if (verbosity >= 2) {
341                                 printf(" range=[%" PRIu64 "-%" PRIu64 "]",
342                                         in.body.setlk.lk.start,
343                                         in.body.setlk.lk.end);
344                         }
345                         break;
346                 case FUSE_SETXATTR:
347                         /* 
348                          * In theory neither the xattr name and value need be
349                          * ASCII, but in this test suite they always are.
350                          */
351                         name = (const char*)in.body.bytes +
352                                 sizeof(fuse_setxattr_in);
353                         value = name + strlen(name) + 1;
354                         printf(" %s=%s", name, value);
355                         break;
356                 case FUSE_WRITE:
357                         printf(" fh=%#" PRIx64 " offset=%" PRIu64
358                                 " size=%u write_flags=%u",
359                                 in.body.write.fh,
360                                 in.body.write.offset, in.body.write.size,
361                                 in.body.write.write_flags);
362                         if (verbosity > 1)
363                                 printf(" flags=%#x", in.body.write.flags);
364                         break;
365                 default:
366                         break;
367         }
368         printf("\n");
369 }
370
371 /* 
372  * Debug a FUSE response.
373  *
374  * This is mostly useful for asynchronous notifications, which don't correspond
375  * to any request
376  */
377 void MockFS::debug_response(const mockfs_buf_out &out) {
378         const char *name;
379
380         if (verbosity == 0)
381                 return;
382
383         switch (out.header.error) {
384                 case FUSE_NOTIFY_INVAL_ENTRY:
385                         name = (const char*)out.body.bytes +
386                                 sizeof(fuse_notify_inval_entry_out);
387                         printf("<- INVAL_ENTRY parent=%" PRIu64 " %s\n",
388                                 out.body.inval_entry.parent, name);
389                         break;
390                 case FUSE_NOTIFY_INVAL_INODE:
391                         printf("<- INVAL_INODE ino=%" PRIu64 " off=%" PRIi64
392                                 " len=%" PRIi64 "\n",
393                                 out.body.inval_inode.ino,
394                                 out.body.inval_inode.off,
395                                 out.body.inval_inode.len);
396                         break;
397                 case FUSE_NOTIFY_STORE:
398                         printf("<- STORE ino=%" PRIu64 " off=%" PRIu64
399                                 " size=%" PRIu32 "\n",
400                                 out.body.store.nodeid,
401                                 out.body.store.offset,
402                                 out.body.store.size);
403                         break;
404                 default:
405                         break;
406         }
407 }
408
409 MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
410         bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags,
411         uint32_t kernel_minor_version, uint32_t max_write, bool async,
412         bool noclusterr, unsigned time_gran, bool nointr, bool noatime,
413         const char *fsname, const char *subtype)
414 {
415         struct sigaction sa;
416         struct iovec *iov = NULL;
417         int iovlen = 0;
418         char fdstr[15];
419         const bool trueval = true;
420
421         m_daemon_id = NULL;
422         m_expected_write_errno = 0;
423         m_kernel_minor_version = kernel_minor_version;
424         m_maxreadahead = max_readahead;
425         m_maxwrite = MIN(max_write, max_max_write);
426         m_nready = -1;
427         m_pm = pm;
428         m_time_gran = time_gran;
429         m_quit = false;
430         m_last_unique = 0;
431         if (m_pm == KQ)
432                 m_kq = kqueue();
433         else
434                 m_kq = -1;
435
436         /*
437          * Kyua sets pwd to a testcase-unique tempdir; no need to use
438          * mkdtemp
439          */
440         /*
441          * googletest doesn't allow ASSERT_ in constructors, so we must throw
442          * instead.
443          */
444         if (mkdir("mountpoint" , 0755) && errno != EEXIST)
445                 throw(std::system_error(errno, std::system_category(),
446                         "Couldn't make mountpoint directory"));
447
448         switch (m_pm) {
449         case BLOCKING:
450                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR);
451                 break;
452         default:
453                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK);
454                 break;
455         }
456         if (m_fuse_fd < 0)
457                 throw(std::system_error(errno, std::system_category(),
458                         "Couldn't open /dev/fuse"));
459
460         m_pid = getpid();
461         m_child_pid = -1;
462
463         build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
464         build_iovec(&iov, &iovlen, "fspath",
465                     __DECONST(void *, "mountpoint"), -1);
466         build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
467         sprintf(fdstr, "%d", m_fuse_fd);
468         build_iovec(&iov, &iovlen, "fd", fdstr, -1);
469         if (allow_other) {
470                 build_iovec(&iov, &iovlen, "allow_other",
471                         __DECONST(void*, &trueval), sizeof(bool));
472         }
473         if (default_permissions) {
474                 build_iovec(&iov, &iovlen, "default_permissions",
475                         __DECONST(void*, &trueval), sizeof(bool));
476         }
477         if (push_symlinks_in) {
478                 build_iovec(&iov, &iovlen, "push_symlinks_in",
479                         __DECONST(void*, &trueval), sizeof(bool));
480         }
481         if (ro) {
482                 build_iovec(&iov, &iovlen, "ro",
483                         __DECONST(void*, &trueval), sizeof(bool));
484         }
485         if (async) {
486                 build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval),
487                         sizeof(bool));
488         }
489         if (noatime) {
490                 build_iovec(&iov, &iovlen, "noatime",
491                         __DECONST(void*, &trueval), sizeof(bool));
492         }
493         if (noclusterr) {
494                 build_iovec(&iov, &iovlen, "noclusterr",
495                         __DECONST(void*, &trueval), sizeof(bool));
496         }
497         if (nointr) {
498                 build_iovec(&iov, &iovlen, "nointr",
499                         __DECONST(void*, &trueval), sizeof(bool));
500         } else {
501                 build_iovec(&iov, &iovlen, "intr",
502                         __DECONST(void*, &trueval), sizeof(bool));
503         }
504         if (*fsname) {
505                 build_iovec(&iov, &iovlen, "fsname=",
506                         __DECONST(void*, fsname), -1);
507         }
508         if (*subtype) {
509                 build_iovec(&iov, &iovlen, "subtype=",
510                         __DECONST(void*, subtype), -1);
511         }
512         if (nmount(iov, iovlen, 0))
513                 throw(std::system_error(errno, std::system_category(),
514                         "Couldn't mount filesystem"));
515
516         // Setup default handler
517         ON_CALL(*this, process(_, _))
518                 .WillByDefault(Invoke(this, &MockFS::process_default));
519
520         init(flags);
521         bzero(&sa, sizeof(sa));
522         sa.sa_handler = sigint_handler;
523         sa.sa_flags = 0;        /* Don't set SA_RESTART! */
524         if (0 != sigaction(SIGUSR1, &sa, NULL))
525                 throw(std::system_error(errno, std::system_category(),
526                         "Couldn't handle SIGUSR1"));
527         if (pthread_create(&m_daemon_id, NULL, service, (void*)this))
528                 throw(std::system_error(errno, std::system_category(),
529                         "Couldn't Couldn't start fuse thread"));
530 }
531
532 MockFS::~MockFS() {
533         kill_daemon();
534         if (m_daemon_id != NULL) {
535                 pthread_join(m_daemon_id, NULL);
536                 m_daemon_id = NULL;
537         }
538         ::unmount("mountpoint", MNT_FORCE);
539         rmdir("mountpoint");
540         if (m_kq >= 0)
541                 close(m_kq);
542 }
543
544 void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) {
545         uint32_t inlen = in.header.len;
546         size_t fih = sizeof(in.header);
547         switch (in.header.opcode) {
548         case FUSE_LOOKUP:
549         case FUSE_RMDIR:
550         case FUSE_SYMLINK:
551         case FUSE_UNLINK:
552                 EXPECT_GT(inlen, fih) << "Missing request filename";
553                 // No redundant information for checking buflen
554                 break;
555         case FUSE_FORGET:
556                 EXPECT_EQ(inlen, fih + sizeof(in.body.forget));
557                 EXPECT_EQ((size_t)buflen, inlen);
558                 break;
559         case FUSE_GETATTR:
560                 EXPECT_EQ(inlen, fih + sizeof(in.body.getattr));
561                 EXPECT_EQ((size_t)buflen, inlen);
562                 break;
563         case FUSE_SETATTR:
564                 EXPECT_EQ(inlen, fih + sizeof(in.body.setattr));
565                 EXPECT_EQ((size_t)buflen, inlen);
566                 break;
567         case FUSE_READLINK:
568                 EXPECT_EQ(inlen, fih) << "Unexpected request body";
569                 EXPECT_EQ((size_t)buflen, inlen);
570                 break;
571         case FUSE_MKNOD:
572                 {
573                         size_t s;
574                         if (m_kernel_minor_version >= 12)
575                                 s = sizeof(in.body.mknod);
576                         else
577                                 s = FUSE_COMPAT_MKNOD_IN_SIZE;
578                         EXPECT_GE(inlen, fih + s) << "Missing request body";
579                         EXPECT_GT(inlen, fih + s) << "Missing request filename";
580                         // No redundant information for checking buflen
581                         break;
582                 }
583         case FUSE_MKDIR:
584                 EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) <<
585                         "Missing request body";
586                 EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) <<
587                         "Missing request filename";
588                 // No redundant information for checking buflen
589                 break;
590         case FUSE_RENAME:
591                 EXPECT_GE(inlen, fih + sizeof(in.body.rename)) <<
592                         "Missing request body";
593                 EXPECT_GT(inlen, fih + sizeof(in.body.rename)) <<
594                         "Missing request filename";
595                 // No redundant information for checking buflen
596                 break;
597         case FUSE_LINK:
598                 EXPECT_GE(inlen, fih + sizeof(in.body.link)) <<
599                         "Missing request body";
600                 EXPECT_GT(inlen, fih + sizeof(in.body.link)) <<
601                         "Missing request filename";
602                 // No redundant information for checking buflen
603                 break;
604         case FUSE_OPEN:
605                 EXPECT_EQ(inlen, fih + sizeof(in.body.open));
606                 EXPECT_EQ((size_t)buflen, inlen);
607                 break;
608         case FUSE_READ:
609                 EXPECT_EQ(inlen, fih + sizeof(in.body.read));
610                 EXPECT_EQ((size_t)buflen, inlen);
611                 break;
612         case FUSE_WRITE:
613                 {
614                         size_t s;
615
616                         if (m_kernel_minor_version >= 9)
617                                 s = sizeof(in.body.write);
618                         else
619                                 s = FUSE_COMPAT_WRITE_IN_SIZE;
620                         // I suppose a 0-byte write should be allowed
621                         EXPECT_GE(inlen, fih + s) << "Missing request body";
622                         EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size);
623                         break;
624                 }
625         case FUSE_DESTROY:
626         case FUSE_STATFS:
627                 EXPECT_EQ(inlen, fih);
628                 EXPECT_EQ((size_t)buflen, inlen);
629                 break;
630         case FUSE_RELEASE:
631                 EXPECT_EQ(inlen, fih + sizeof(in.body.release));
632                 EXPECT_EQ((size_t)buflen, inlen);
633                 break;
634         case FUSE_FSYNC:
635         case FUSE_FSYNCDIR:
636                 EXPECT_EQ(inlen, fih + sizeof(in.body.fsync));
637                 EXPECT_EQ((size_t)buflen, inlen);
638                 break;
639         case FUSE_SETXATTR:
640                 EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) <<
641                         "Missing request body";
642                 EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) <<
643                         "Missing request attribute name";
644                 // No redundant information for checking buflen
645                 break;
646         case FUSE_GETXATTR:
647                 EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) <<
648                         "Missing request body";
649                 EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) <<
650                         "Missing request attribute name";
651                 // No redundant information for checking buflen
652                 break;
653         case FUSE_LISTXATTR:
654                 EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr));
655                 EXPECT_EQ((size_t)buflen, inlen);
656                 break;
657         case FUSE_REMOVEXATTR:
658                 EXPECT_GT(inlen, fih) << "Missing request attribute name";
659                 // No redundant information for checking buflen
660                 break;
661         case FUSE_FLUSH:
662                 EXPECT_EQ(inlen, fih + sizeof(in.body.flush));
663                 EXPECT_EQ((size_t)buflen, inlen);
664                 break;
665         case FUSE_INIT:
666                 EXPECT_EQ(inlen, fih + sizeof(in.body.init));
667                 EXPECT_EQ((size_t)buflen, inlen);
668                 break;
669         case FUSE_OPENDIR:
670                 EXPECT_EQ(inlen, fih + sizeof(in.body.opendir));
671                 EXPECT_EQ((size_t)buflen, inlen);
672                 break;
673         case FUSE_READDIR:
674                 EXPECT_EQ(inlen, fih + sizeof(in.body.readdir));
675                 EXPECT_EQ((size_t)buflen, inlen);
676                 break;
677         case FUSE_RELEASEDIR:
678                 EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir));
679                 EXPECT_EQ((size_t)buflen, inlen);
680                 break;
681         case FUSE_GETLK:
682                 EXPECT_EQ(inlen, fih + sizeof(in.body.getlk));
683                 EXPECT_EQ((size_t)buflen, inlen);
684                 break;
685         case FUSE_SETLK:
686         case FUSE_SETLKW:
687                 EXPECT_EQ(inlen, fih + sizeof(in.body.setlk));
688                 EXPECT_EQ((size_t)buflen, inlen);
689                 break;
690         case FUSE_ACCESS:
691                 EXPECT_EQ(inlen, fih + sizeof(in.body.access));
692                 EXPECT_EQ((size_t)buflen, inlen);
693                 break;
694         case FUSE_CREATE:
695                 EXPECT_GE(inlen, fih + sizeof(in.body.create)) <<
696                         "Missing request body";
697                 EXPECT_GT(inlen, fih + sizeof(in.body.create)) <<
698                         "Missing request filename";
699                 // No redundant information for checking buflen
700                 break;
701         case FUSE_INTERRUPT:
702                 EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt));
703                 EXPECT_EQ((size_t)buflen, inlen);
704                 break;
705         case FUSE_FALLOCATE:
706                 EXPECT_EQ(inlen, fih + sizeof(in.body.fallocate));
707                 EXPECT_EQ((size_t)buflen, inlen);
708                 break;
709         case FUSE_BMAP:
710                 EXPECT_EQ(inlen, fih + sizeof(in.body.bmap));
711                 EXPECT_EQ((size_t)buflen, inlen);
712                 break;
713         case FUSE_LSEEK:
714                 EXPECT_EQ(inlen, fih + sizeof(in.body.lseek));
715                 EXPECT_EQ((size_t)buflen, inlen);
716                 break;
717         case FUSE_COPY_FILE_RANGE:
718                 EXPECT_EQ(inlen, fih + sizeof(in.body.copy_file_range));
719                 EXPECT_EQ(0ul, in.body.copy_file_range.flags);
720                 EXPECT_EQ((size_t)buflen, inlen);
721                 break;
722         case FUSE_NOTIFY_REPLY:
723         case FUSE_BATCH_FORGET:
724         case FUSE_IOCTL:
725         case FUSE_POLL:
726         case FUSE_READDIRPLUS:
727                 FAIL() << "Unsupported opcode?";
728         default:
729                 FAIL() << "Unknown opcode " << in.header.opcode;
730         }
731         /*
732          * Check that the ticket's unique value is sequential.  Technically it
733          * doesn't need to be sequential, merely unique.  But the current
734          * fusefs driver _does_ make it sequential, and that's easy to check
735          * for.
736          */
737         if (in.header.unique != ++m_last_unique)
738                 FAIL() << "Non-sequential unique value";
739 }
740
741 void MockFS::init(uint32_t flags) {
742         ssize_t buflen;
743
744         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
745         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
746
747         read_request(*in, buflen);
748         if (verbosity > 0)
749                 debug_request(*in, buflen);
750         audit_request(*in, buflen);
751         ASSERT_EQ(FUSE_INIT, in->header.opcode);
752
753         out->header.unique = in->header.unique;
754         out->header.error = 0;
755         out->body.init.major = FUSE_KERNEL_VERSION;
756         out->body.init.minor = m_kernel_minor_version;;
757         out->body.init.flags = in->body.init.flags & flags;
758         out->body.init.max_write = m_maxwrite;
759         out->body.init.max_readahead = m_maxreadahead;
760
761         if (m_kernel_minor_version < 23) {
762                 SET_OUT_HEADER_LEN(*out, init_7_22);
763         } else {
764                 out->body.init.time_gran = m_time_gran;
765                 SET_OUT_HEADER_LEN(*out, init);
766         }
767
768         write(m_fuse_fd, out.get(), out->header.len);
769 }
770
771 void MockFS::kill_daemon() {
772         m_quit = true;
773         if (m_daemon_id != NULL)
774                 pthread_kill(m_daemon_id, SIGUSR1);
775         // Closing the /dev/fuse file descriptor first allows unmount to
776         // succeed even if the daemon doesn't correctly respond to commands
777         // during the unmount sequence.
778         close(m_fuse_fd);
779         m_fuse_fd = -1;
780 }
781
782 void MockFS::loop() {
783         std::vector<std::unique_ptr<mockfs_buf_out>> out;
784
785         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
786         ASSERT_TRUE(in != NULL);
787         while (!m_quit) {
788                 ssize_t buflen;
789
790                 bzero(in.get(), sizeof(*in));
791                 read_request(*in, buflen);
792                 m_expected_write_errno = 0;
793                 if (m_quit)
794                         break;
795                 if (verbosity > 0)
796                         debug_request(*in, buflen);
797                 audit_request(*in, buflen);
798                 if (pid_ok((pid_t)in->header.pid)) {
799                         process(*in, out);
800                 } else {
801                         /* 
802                          * Reject any requests from unknown processes.  Because
803                          * we actually do mount a filesystem, plenty of
804                          * unrelated system daemons may try to access it.
805                          */
806                         if (verbosity > 1)
807                                 printf("\tREJECTED (wrong pid %d)\n",
808                                         in->header.pid);
809                         process_default(*in, out);
810                 }
811                 for (auto &it: out)
812                         write_response(*it);
813                 out.clear();
814         }
815 }
816
817 int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen)
818 {
819         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
820
821         out->header.unique = 0; /* 0 means asynchronous notification */
822         out->header.error = FUSE_NOTIFY_INVAL_ENTRY;
823         out->body.inval_entry.parent = parent;
824         out->body.inval_entry.namelen = namelen;
825         strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry),
826                 name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry));
827         out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) +
828                 namelen;
829         debug_response(*out);
830         write_response(*out);
831         return 0;
832 }
833
834 int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len)
835 {
836         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
837
838         out->header.unique = 0; /* 0 means asynchronous notification */
839         out->header.error = FUSE_NOTIFY_INVAL_INODE;
840         out->body.inval_inode.ino = ino;
841         out->body.inval_inode.off = off;
842         out->body.inval_inode.len = len;
843         out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode);
844         debug_response(*out);
845         write_response(*out);
846         return 0;
847 }
848
849 int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size)
850 {
851         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
852
853         out->header.unique = 0; /* 0 means asynchronous notification */
854         out->header.error = FUSE_NOTIFY_STORE;
855         out->body.store.nodeid = ino;
856         out->body.store.offset = off;
857         out->body.store.size = size;
858         bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size);
859         out->header.len = sizeof(out->header) + sizeof(out->body.store) + size;
860         debug_response(*out);
861         write_response(*out);
862         return 0;
863 }
864
865 bool MockFS::pid_ok(pid_t pid) {
866         if (pid == m_pid) {
867                 return (true);
868         } else if (pid == m_child_pid) {
869                 return (true);
870         } else {
871                 struct kinfo_proc *ki;
872                 bool ok = false;
873
874                 ki = kinfo_getproc(pid);
875                 if (ki == NULL)
876                         return (false);
877                 /* 
878                  * Allow access by the aio daemon processes so that our tests
879                  * can use aio functions
880                  */
881                 if (0 == strncmp("aiod", ki->ki_comm, 4))
882                         ok = true;
883                 free(ki);
884                 return (ok);
885         }
886 }
887
888 void MockFS::process_default(const mockfs_buf_in& in,
889                 std::vector<std::unique_ptr<mockfs_buf_out>> &out)
890 {
891         std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
892         out0->header.unique = in.header.unique;
893         out0->header.error = -EOPNOTSUPP;
894         out0->header.len = sizeof(out0->header);
895         out.push_back(std::move(out0));
896 }
897
898 void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) {
899         int nready = 0;
900         fd_set readfds;
901         pollfd fds[1];
902         struct kevent changes[1];
903         struct kevent events[1];
904         struct timespec timeout_ts;
905         struct timeval timeout_tv;
906         const int timeout_ms = 999;
907         int timeout_int, nfds;
908         int fuse_fd;
909
910         switch (m_pm) {
911         case BLOCKING:
912                 break;
913         case KQ:
914                 timeout_ts.tv_sec = 0;
915                 timeout_ts.tv_nsec = timeout_ms * 1'000'000;
916                 while (nready == 0) {
917                         EV_SET(&changes[0], m_fuse_fd, EVFILT_READ,
918                                 EV_ADD | EV_ONESHOT, 0, 0, 0);
919                         nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
920                                 &timeout_ts);
921                         if (m_quit)
922                                 return;
923                 }
924                 ASSERT_LE(0, nready) << strerror(errno);
925                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
926                 if (events[0].flags & EV_ERROR)
927                         FAIL() << strerror(events[0].data);
928                 else if (events[0].flags & EV_EOF)
929                         FAIL() << strerror(events[0].fflags);
930                 m_nready = events[0].data;
931                 break;
932         case POLL:
933                 timeout_int = timeout_ms;
934                 fds[0].fd = m_fuse_fd;
935                 fds[0].events = POLLIN;
936                 while (nready == 0) {
937                         nready = poll(fds, 1, timeout_int);
938                         if (m_quit)
939                                 return;
940                 }
941                 ASSERT_LE(0, nready) << strerror(errno);
942                 ASSERT_TRUE(fds[0].revents & POLLIN);
943                 break;
944         case SELECT:
945                 fuse_fd = m_fuse_fd;
946                 if (fuse_fd < 0)
947                         break;
948                 timeout_tv.tv_sec = 0;
949                 timeout_tv.tv_usec = timeout_ms * 1'000;
950                 nfds = fuse_fd + 1;
951                 while (nready == 0) {
952                         FD_ZERO(&readfds);
953                         FD_SET(fuse_fd, &readfds);
954                         nready = select(nfds, &readfds, NULL, NULL,
955                                 &timeout_tv);
956                         if (m_quit)
957                                 return;
958                 }
959                 ASSERT_LE(0, nready) << strerror(errno);
960                 ASSERT_TRUE(FD_ISSET(fuse_fd, &readfds));
961                 break;
962         default:
963                 FAIL() << "not yet implemented";
964         }
965         res = read(m_fuse_fd, &in, sizeof(in));
966
967         if (res < 0 && !m_quit) {
968                 m_quit = true;
969                 FAIL() << "read: " << strerror(errno);
970         }
971         ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit);
972         /*
973          * Inconsistently, fuse_in_header.len is the size of the entire
974          * request,including header, even though fuse_out_header.len excludes
975          * the size of the header.
976          */
977         ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit);
978 }
979
980 void MockFS::write_response(const mockfs_buf_out &out) {
981         fd_set writefds;
982         pollfd fds[1];
983         struct kevent changes[1];
984         struct kevent events[1];
985         int nready, nfds;
986         ssize_t r;
987
988         switch (m_pm) {
989         case BLOCKING:
990                 break;
991         case KQ:
992                 EV_SET(&changes[0], m_fuse_fd, EVFILT_WRITE,
993                         EV_ADD | EV_ONESHOT, 0, 0, 0);
994                 nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
995                         NULL);
996                 ASSERT_LE(0, nready) << strerror(errno);
997                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
998                 if (events[0].flags & EV_ERROR)
999                         FAIL() << strerror(events[0].data);
1000                 else if (events[0].flags & EV_EOF)
1001                         FAIL() << strerror(events[0].fflags);
1002                 m_nready = events[0].data;
1003                 break;
1004         case POLL:
1005                 fds[0].fd = m_fuse_fd;
1006                 fds[0].events = POLLOUT;
1007                 nready = poll(fds, 1, INFTIM);
1008                 ASSERT_LE(0, nready) << strerror(errno);
1009                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1010                 ASSERT_TRUE(fds[0].revents & POLLOUT);
1011                 break;
1012         case SELECT:
1013                 FD_ZERO(&writefds);
1014                 FD_SET(m_fuse_fd, &writefds);
1015                 nfds = m_fuse_fd + 1;
1016                 nready = select(nfds, NULL, &writefds, NULL, NULL);
1017                 ASSERT_LE(0, nready) << strerror(errno);
1018                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1019                 ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds));
1020                 break;
1021         default:
1022                 FAIL() << "not yet implemented";
1023         }
1024         r = write(m_fuse_fd, &out, out.header.len);
1025         if (m_expected_write_errno) {
1026                 ASSERT_EQ(-1, r);
1027                 ASSERT_EQ(m_expected_write_errno, errno) << strerror(errno);
1028         } else {
1029                 ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno);
1030         }
1031 }
1032
1033 void* MockFS::service(void *pthr_data) {
1034         MockFS *mock_fs = (MockFS*)pthr_data;
1035
1036         mock_fs->loop();
1037
1038         return (NULL);
1039 }
1040
1041 void MockFS::unmount() {
1042         ::unmount("mountpoint", 0);
1043 }