]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fusefs/mockfs.cc
MFC the new fusefs driver
[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 int NUM_OPS = 39;
66         const char* table[NUM_OPS] = {
67                 "Unknown (opcode 0)",
68                 "LOOKUP",
69                 "FORGET",
70                 "GETATTR",
71                 "SETATTR",
72                 "READLINK",
73                 "SYMLINK",
74                 "Unknown (opcode 7)",
75                 "MKNOD",
76                 "MKDIR",
77                 "UNLINK",
78                 "RMDIR",
79                 "RENAME",
80                 "LINK",
81                 "OPEN",
82                 "READ",
83                 "WRITE",
84                 "STATFS",
85                 "RELEASE",
86                 "Unknown (opcode 19)",
87                 "FSYNC",
88                 "SETXATTR",
89                 "GETXATTR",
90                 "LISTXATTR",
91                 "REMOVEXATTR",
92                 "FLUSH",
93                 "INIT",
94                 "OPENDIR",
95                 "READDIR",
96                 "RELEASEDIR",
97                 "FSYNCDIR",
98                 "GETLK",
99                 "SETLK",
100                 "SETLKW",
101                 "ACCESS",
102                 "CREATE",
103                 "INTERRUPT",
104                 "BMAP",
105                 "DESTROY"
106         };
107         if (opcode >= NUM_OPS)
108                 return ("Unknown (opcode > max)");
109         else
110                 return (table[opcode]);
111 }
112
113 ProcessMockerT
114 ReturnErrno(int error)
115 {
116         return([=](auto in, auto &out) {
117                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
118                 out0->header.unique = in.header.unique;
119                 out0->header.error = -error;
120                 out0->header.len = sizeof(out0->header);
121                 out.push_back(std::move(out0));
122         });
123 }
124
125 /* Helper function used for returning negative cache entries for LOOKUP */
126 ProcessMockerT
127 ReturnNegativeCache(const struct timespec *entry_valid)
128 {
129         return([=](auto in, auto &out) {
130                 /* nodeid means ENOENT and cache it */
131                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
132                 out0->body.entry.nodeid = 0;
133                 out0->header.unique = in.header.unique;
134                 out0->header.error = 0;
135                 out0->body.entry.entry_valid = entry_valid->tv_sec;
136                 out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec;
137                 SET_OUT_HEADER_LEN(*out0, entry);
138                 out.push_back(std::move(out0));
139         });
140 }
141
142 ProcessMockerT
143 ReturnImmediate(std::function<void(const mockfs_buf_in& in,
144                                    struct mockfs_buf_out &out)> f)
145 {
146         return([=](auto& in, auto &out) {
147                 std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
148                 out0->header.unique = in.header.unique;
149                 f(in, *out0);
150                 out.push_back(std::move(out0));
151         });
152 }
153
154 void sigint_handler(int __unused sig) {
155         // Don't do anything except interrupt the daemon's read(2) call
156 }
157
158 void MockFS::debug_request(const mockfs_buf_in &in, ssize_t buflen)
159 {
160         printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode),
161                 in.header.nodeid);
162         if (verbosity > 1) {
163                 printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u"
164                         " buflen=%zd",
165                         in.header.uid, in.header.gid, in.header.pid,
166                         in.header.unique, in.header.len, buflen);
167         }
168         switch (in.header.opcode) {
169                 const char *name, *value;
170
171                 case FUSE_ACCESS:
172                         printf(" mask=%#x", in.body.access.mask);
173                         break;
174                 case FUSE_BMAP:
175                         printf(" block=%" PRIx64 " blocksize=%#x",
176                                 in.body.bmap.block, in.body.bmap.blocksize);
177                         break;
178                 case FUSE_CREATE:
179                         if (m_kernel_minor_version >= 12)
180                                 name = (const char*)in.body.bytes +
181                                         sizeof(fuse_create_in);
182                         else
183                                 name = (const char*)in.body.bytes +
184                                         sizeof(fuse_open_in);
185                         printf(" flags=%#x name=%s",
186                                 in.body.open.flags, name);
187                         break;
188                 case FUSE_FLUSH:
189                         printf(" fh=%#" PRIx64 " lock_owner=%" PRIu64,
190                                 in.body.flush.fh,
191                                 in.body.flush.lock_owner);
192                         break;
193                 case FUSE_FORGET:
194                         printf(" nlookup=%" PRIu64, in.body.forget.nlookup);
195                         break;
196                 case FUSE_FSYNC:
197                         printf(" flags=%#x", in.body.fsync.fsync_flags);
198                         break;
199                 case FUSE_FSYNCDIR:
200                         printf(" flags=%#x", in.body.fsyncdir.fsync_flags);
201                         break;
202                 case FUSE_INTERRUPT:
203                         printf(" unique=%" PRIu64, in.body.interrupt.unique);
204                         break;
205                 case FUSE_LINK:
206                         printf(" oldnodeid=%" PRIu64, in.body.link.oldnodeid);
207                         break;
208                 case FUSE_LISTXATTR:
209                         printf(" size=%" PRIu32, in.body.listxattr.size);
210                         break;
211                 case FUSE_LOOKUP:
212                         printf(" %s", in.body.lookup);
213                         break;
214                 case FUSE_MKDIR:
215                         name = (const char*)in.body.bytes +
216                                 sizeof(fuse_mkdir_in);
217                         printf(" name=%s mode=%#o umask=%#o", name,
218                                 in.body.mkdir.mode, in.body.mkdir.umask);
219                         break;
220                 case FUSE_MKNOD:
221                         if (m_kernel_minor_version >= 12)
222                                 name = (const char*)in.body.bytes +
223                                         sizeof(fuse_mknod_in);
224                         else
225                                 name = (const char*)in.body.bytes +
226                                         FUSE_COMPAT_MKNOD_IN_SIZE;
227                         printf(" mode=%#o rdev=%x umask=%#o name=%s",
228                                 in.body.mknod.mode, in.body.mknod.rdev,
229                                 in.body.mknod.umask, name);
230                         break;
231                 case FUSE_OPEN:
232                         printf(" flags=%#x", in.body.open.flags);
233                         break;
234                 case FUSE_OPENDIR:
235                         printf(" flags=%#x", in.body.opendir.flags);
236                         break;
237                 case FUSE_READ:
238                         printf(" offset=%" PRIu64 " size=%u",
239                                 in.body.read.offset,
240                                 in.body.read.size);
241                         if (verbosity > 1)
242                                 printf(" flags=%#x", in.body.read.flags);
243                         break;
244                 case FUSE_READDIR:
245                         printf(" fh=%#" PRIx64 " offset=%" PRIu64 " size=%u",
246                                 in.body.readdir.fh, in.body.readdir.offset,
247                                 in.body.readdir.size);
248                         break;
249                 case FUSE_RELEASE:
250                         printf(" fh=%#" PRIx64 " flags=%#x lock_owner=%" PRIu64,
251                                 in.body.release.fh,
252                                 in.body.release.flags,
253                                 in.body.release.lock_owner);
254                         break;
255                 case FUSE_SETATTR:
256                         if (verbosity <= 1) {
257                                 printf(" valid=%#x", in.body.setattr.valid);
258                                 break;
259                         }
260                         if (in.body.setattr.valid & FATTR_MODE)
261                                 printf(" mode=%#o", in.body.setattr.mode);
262                         if (in.body.setattr.valid & FATTR_UID)
263                                 printf(" uid=%u", in.body.setattr.uid);
264                         if (in.body.setattr.valid & FATTR_GID)
265                                 printf(" gid=%u", in.body.setattr.gid);
266                         if (in.body.setattr.valid & FATTR_SIZE)
267                                 printf(" size=%" PRIu64, in.body.setattr.size);
268                         if (in.body.setattr.valid & FATTR_ATIME)
269                                 printf(" atime=%" PRIu64 ".%u",
270                                         in.body.setattr.atime,
271                                         in.body.setattr.atimensec);
272                         if (in.body.setattr.valid & FATTR_MTIME)
273                                 printf(" mtime=%" PRIu64 ".%u",
274                                         in.body.setattr.mtime,
275                                         in.body.setattr.mtimensec);
276                         if (in.body.setattr.valid & FATTR_FH)
277                                 printf(" fh=%" PRIu64 "", in.body.setattr.fh);
278                         break;
279                 case FUSE_SETLK:
280                         printf(" fh=%#" PRIx64 " owner=%" PRIu64
281                                 " type=%u pid=%u",
282                                 in.body.setlk.fh, in.body.setlk.owner,
283                                 in.body.setlk.lk.type,
284                                 in.body.setlk.lk.pid);
285                         if (verbosity >= 2) {
286                                 printf(" range=[%" PRIu64 "-%" PRIu64 "]",
287                                         in.body.setlk.lk.start,
288                                         in.body.setlk.lk.end);
289                         }
290                         break;
291                 case FUSE_SETXATTR:
292                         /* 
293                          * In theory neither the xattr name and value need be
294                          * ASCII, but in this test suite they always are.
295                          */
296                         name = (const char*)in.body.bytes +
297                                 sizeof(fuse_setxattr_in);
298                         value = name + strlen(name) + 1;
299                         printf(" %s=%s", name, value);
300                         break;
301                 case FUSE_WRITE:
302                         printf(" fh=%#" PRIx64 " offset=%" PRIu64
303                                 " size=%u write_flags=%u",
304                                 in.body.write.fh,
305                                 in.body.write.offset, in.body.write.size,
306                                 in.body.write.write_flags);
307                         if (verbosity > 1)
308                                 printf(" flags=%#x", in.body.write.flags);
309                         break;
310                 default:
311                         break;
312         }
313         printf("\n");
314 }
315
316 /* 
317  * Debug a FUSE response.
318  *
319  * This is mostly useful for asynchronous notifications, which don't correspond
320  * to any request
321  */
322 void MockFS::debug_response(const mockfs_buf_out &out) {
323         const char *name;
324
325         if (verbosity == 0)
326                 return;
327
328         switch (out.header.error) {
329                 case FUSE_NOTIFY_INVAL_ENTRY:
330                         name = (const char*)out.body.bytes +
331                                 sizeof(fuse_notify_inval_entry_out);
332                         printf("<- INVAL_ENTRY parent=%" PRIu64 " %s\n",
333                                 out.body.inval_entry.parent, name);
334                         break;
335                 case FUSE_NOTIFY_INVAL_INODE:
336                         printf("<- INVAL_INODE ino=%" PRIu64 " off=%" PRIi64
337                                 " len=%" PRIi64 "\n",
338                                 out.body.inval_inode.ino,
339                                 out.body.inval_inode.off,
340                                 out.body.inval_inode.len);
341                         break;
342                 case FUSE_NOTIFY_STORE:
343                         printf("<- STORE ino=%" PRIu64 " off=%" PRIu64
344                                 " size=%" PRIu32 "\n",
345                                 out.body.store.nodeid,
346                                 out.body.store.offset,
347                                 out.body.store.size);
348                         break;
349                 default:
350                         break;
351         }
352 }
353
354 MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
355         bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags,
356         uint32_t kernel_minor_version, uint32_t max_write, bool async,
357         bool noclusterr, unsigned time_gran, bool nointr)
358 {
359         struct sigaction sa;
360         struct iovec *iov = NULL;
361         int iovlen = 0;
362         char fdstr[15];
363         const bool trueval = true;
364
365         m_daemon_id = NULL;
366         m_kernel_minor_version = kernel_minor_version;
367         m_maxreadahead = max_readahead;
368         m_maxwrite = max_write;
369         m_nready = -1;
370         m_pm = pm;
371         m_time_gran = time_gran;
372         m_quit = false;
373         if (m_pm == KQ)
374                 m_kq = kqueue();
375         else
376                 m_kq = -1;
377
378         /*
379          * Kyua sets pwd to a testcase-unique tempdir; no need to use
380          * mkdtemp
381          */
382         /*
383          * googletest doesn't allow ASSERT_ in constructors, so we must throw
384          * instead.
385          */
386         if (mkdir("mountpoint" , 0755) && errno != EEXIST)
387                 throw(std::system_error(errno, std::system_category(),
388                         "Couldn't make mountpoint directory"));
389
390         switch (m_pm) {
391         case BLOCKING:
392                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR);
393                 break;
394         default:
395                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK);
396                 break;
397         }
398         if (m_fuse_fd < 0)
399                 throw(std::system_error(errno, std::system_category(),
400                         "Couldn't open /dev/fuse"));
401
402         m_pid = getpid();
403         m_child_pid = -1;
404
405         build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
406         build_iovec(&iov, &iovlen, "fspath",
407                     __DECONST(void *, "mountpoint"), -1);
408         build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
409         sprintf(fdstr, "%d", m_fuse_fd);
410         build_iovec(&iov, &iovlen, "fd", fdstr, -1);
411         if (allow_other) {
412                 build_iovec(&iov, &iovlen, "allow_other",
413                         __DECONST(void*, &trueval), sizeof(bool));
414         }
415         if (default_permissions) {
416                 build_iovec(&iov, &iovlen, "default_permissions",
417                         __DECONST(void*, &trueval), sizeof(bool));
418         }
419         if (push_symlinks_in) {
420                 build_iovec(&iov, &iovlen, "push_symlinks_in",
421                         __DECONST(void*, &trueval), sizeof(bool));
422         }
423         if (ro) {
424                 build_iovec(&iov, &iovlen, "ro",
425                         __DECONST(void*, &trueval), sizeof(bool));
426         }
427         if (async) {
428                 build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval),
429                         sizeof(bool));
430         }
431         if (noclusterr) {
432                 build_iovec(&iov, &iovlen, "noclusterr",
433                         __DECONST(void*, &trueval), sizeof(bool));
434         }
435         if (nointr) {
436                 build_iovec(&iov, &iovlen, "nointr",
437                         __DECONST(void*, &trueval), sizeof(bool));
438         } else {
439                 build_iovec(&iov, &iovlen, "intr",
440                         __DECONST(void*, &trueval), sizeof(bool));
441         }
442         if (nmount(iov, iovlen, 0))
443                 throw(std::system_error(errno, std::system_category(),
444                         "Couldn't mount filesystem"));
445
446         // Setup default handler
447         ON_CALL(*this, process(_, _))
448                 .WillByDefault(Invoke(this, &MockFS::process_default));
449
450         init(flags);
451         bzero(&sa, sizeof(sa));
452         sa.sa_handler = sigint_handler;
453         sa.sa_flags = 0;        /* Don't set SA_RESTART! */
454         if (0 != sigaction(SIGUSR1, &sa, NULL))
455                 throw(std::system_error(errno, std::system_category(),
456                         "Couldn't handle SIGUSR1"));
457         if (pthread_create(&m_daemon_id, NULL, service, (void*)this))
458                 throw(std::system_error(errno, std::system_category(),
459                         "Couldn't Couldn't start fuse thread"));
460 }
461
462 MockFS::~MockFS() {
463         kill_daemon();
464         if (m_daemon_id != NULL) {
465                 pthread_join(m_daemon_id, NULL);
466                 m_daemon_id = NULL;
467         }
468         ::unmount("mountpoint", MNT_FORCE);
469         rmdir("mountpoint");
470         if (m_kq >= 0)
471                 close(m_kq);
472 }
473
474 void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) {
475         uint32_t inlen = in.header.len;
476         size_t fih = sizeof(in.header);
477         switch (in.header.opcode) {
478         case FUSE_LOOKUP:
479         case FUSE_RMDIR:
480         case FUSE_SYMLINK:
481         case FUSE_UNLINK:
482                 EXPECT_GT(inlen, fih) << "Missing request filename";
483                 // No redundant information for checking buflen
484                 break;
485         case FUSE_FORGET:
486                 EXPECT_EQ(inlen, fih + sizeof(in.body.forget));
487                 EXPECT_EQ((size_t)buflen, inlen);
488                 break;
489         case FUSE_GETATTR:
490                 EXPECT_EQ(inlen, fih + sizeof(in.body.getattr));
491                 EXPECT_EQ((size_t)buflen, inlen);
492                 break;
493         case FUSE_SETATTR:
494                 EXPECT_EQ(inlen, fih + sizeof(in.body.setattr));
495                 EXPECT_EQ((size_t)buflen, inlen);
496                 break;
497         case FUSE_READLINK:
498                 EXPECT_EQ(inlen, fih) << "Unexpected request body";
499                 EXPECT_EQ((size_t)buflen, inlen);
500                 break;
501         case FUSE_MKNOD:
502                 {
503                         size_t s;
504                         if (m_kernel_minor_version >= 12)
505                                 s = sizeof(in.body.mknod);
506                         else
507                                 s = FUSE_COMPAT_MKNOD_IN_SIZE;
508                         EXPECT_GE(inlen, fih + s) << "Missing request body";
509                         EXPECT_GT(inlen, fih + s) << "Missing request filename";
510                         // No redundant information for checking buflen
511                         break;
512                 }
513         case FUSE_MKDIR:
514                 EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) <<
515                         "Missing request body";
516                 EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) <<
517                         "Missing request filename";
518                 // No redundant information for checking buflen
519                 break;
520         case FUSE_RENAME:
521                 EXPECT_GE(inlen, fih + sizeof(in.body.rename)) <<
522                         "Missing request body";
523                 EXPECT_GT(inlen, fih + sizeof(in.body.rename)) <<
524                         "Missing request filename";
525                 // No redundant information for checking buflen
526                 break;
527         case FUSE_LINK:
528                 EXPECT_GE(inlen, fih + sizeof(in.body.link)) <<
529                         "Missing request body";
530                 EXPECT_GT(inlen, fih + sizeof(in.body.link)) <<
531                         "Missing request filename";
532                 // No redundant information for checking buflen
533                 break;
534         case FUSE_OPEN:
535                 EXPECT_EQ(inlen, fih + sizeof(in.body.open));
536                 EXPECT_EQ((size_t)buflen, inlen);
537                 break;
538         case FUSE_READ:
539                 EXPECT_EQ(inlen, fih + sizeof(in.body.read));
540                 EXPECT_EQ((size_t)buflen, inlen);
541                 break;
542         case FUSE_WRITE:
543                 {
544                         size_t s;
545
546                         if (m_kernel_minor_version >= 9)
547                                 s = sizeof(in.body.write);
548                         else
549                                 s = FUSE_COMPAT_WRITE_IN_SIZE;
550                         // I suppose a 0-byte write should be allowed
551                         EXPECT_GE(inlen, fih + s) << "Missing request body";
552                         EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size);
553                         break;
554                 }
555         case FUSE_DESTROY:
556         case FUSE_STATFS:
557                 EXPECT_EQ(inlen, fih);
558                 EXPECT_EQ((size_t)buflen, inlen);
559                 break;
560         case FUSE_RELEASE:
561                 EXPECT_EQ(inlen, fih + sizeof(in.body.release));
562                 EXPECT_EQ((size_t)buflen, inlen);
563                 break;
564         case FUSE_FSYNC:
565         case FUSE_FSYNCDIR:
566                 EXPECT_EQ(inlen, fih + sizeof(in.body.fsync));
567                 EXPECT_EQ((size_t)buflen, inlen);
568                 break;
569         case FUSE_SETXATTR:
570                 EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) <<
571                         "Missing request body";
572                 EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) <<
573                         "Missing request attribute name";
574                 // No redundant information for checking buflen
575                 break;
576         case FUSE_GETXATTR:
577                 EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) <<
578                         "Missing request body";
579                 EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) <<
580                         "Missing request attribute name";
581                 // No redundant information for checking buflen
582                 break;
583         case FUSE_LISTXATTR:
584                 EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr));
585                 EXPECT_EQ((size_t)buflen, inlen);
586                 break;
587         case FUSE_REMOVEXATTR:
588                 EXPECT_GT(inlen, fih) << "Missing request attribute name";
589                 // No redundant information for checking buflen
590                 break;
591         case FUSE_FLUSH:
592                 EXPECT_EQ(inlen, fih + sizeof(in.body.flush));
593                 EXPECT_EQ((size_t)buflen, inlen);
594                 break;
595         case FUSE_INIT:
596                 EXPECT_EQ(inlen, fih + sizeof(in.body.init));
597                 EXPECT_EQ((size_t)buflen, inlen);
598                 break;
599         case FUSE_OPENDIR:
600                 EXPECT_EQ(inlen, fih + sizeof(in.body.opendir));
601                 EXPECT_EQ((size_t)buflen, inlen);
602                 break;
603         case FUSE_READDIR:
604                 EXPECT_EQ(inlen, fih + sizeof(in.body.readdir));
605                 EXPECT_EQ((size_t)buflen, inlen);
606                 break;
607         case FUSE_RELEASEDIR:
608                 EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir));
609                 EXPECT_EQ((size_t)buflen, inlen);
610                 break;
611         case FUSE_GETLK:
612                 EXPECT_EQ(inlen, fih + sizeof(in.body.getlk));
613                 EXPECT_EQ((size_t)buflen, inlen);
614                 break;
615         case FUSE_SETLK:
616         case FUSE_SETLKW:
617                 EXPECT_EQ(inlen, fih + sizeof(in.body.setlk));
618                 EXPECT_EQ((size_t)buflen, inlen);
619                 break;
620         case FUSE_ACCESS:
621                 EXPECT_EQ(inlen, fih + sizeof(in.body.access));
622                 EXPECT_EQ((size_t)buflen, inlen);
623                 break;
624         case FUSE_CREATE:
625                 EXPECT_GE(inlen, fih + sizeof(in.body.create)) <<
626                         "Missing request body";
627                 EXPECT_GT(inlen, fih + sizeof(in.body.create)) <<
628                         "Missing request filename";
629                 // No redundant information for checking buflen
630                 break;
631         case FUSE_INTERRUPT:
632                 EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt));
633                 EXPECT_EQ((size_t)buflen, inlen);
634                 break;
635         case FUSE_BMAP:
636                 EXPECT_EQ(inlen, fih + sizeof(in.body.bmap));
637                 EXPECT_EQ((size_t)buflen, inlen);
638                 break;
639         case FUSE_NOTIFY_REPLY:
640         case FUSE_BATCH_FORGET:
641         case FUSE_FALLOCATE:
642         case FUSE_IOCTL:
643         case FUSE_POLL:
644         case FUSE_READDIRPLUS:
645                 FAIL() << "Unsupported opcode?";
646         default:
647                 FAIL() << "Unknown opcode " << in.header.opcode;
648         }
649 }
650
651 void MockFS::init(uint32_t flags) {
652         ssize_t buflen;
653
654         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
655         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
656
657         read_request(*in, buflen);
658         audit_request(*in, buflen);
659         ASSERT_EQ(FUSE_INIT, in->header.opcode);
660
661         out->header.unique = in->header.unique;
662         out->header.error = 0;
663         out->body.init.major = FUSE_KERNEL_VERSION;
664         out->body.init.minor = m_kernel_minor_version;;
665         out->body.init.flags = in->body.init.flags & flags;
666         out->body.init.max_write = m_maxwrite;
667         out->body.init.max_readahead = m_maxreadahead;
668
669         if (m_kernel_minor_version < 23) {
670                 SET_OUT_HEADER_LEN(*out, init_7_22);
671         } else {
672                 out->body.init.time_gran = m_time_gran;
673                 SET_OUT_HEADER_LEN(*out, init);
674         }
675
676         write(m_fuse_fd, out.get(), out->header.len);
677 }
678
679 void MockFS::kill_daemon() {
680         m_quit = true;
681         if (m_daemon_id != NULL)
682                 pthread_kill(m_daemon_id, SIGUSR1);
683         // Closing the /dev/fuse file descriptor first allows unmount to
684         // succeed even if the daemon doesn't correctly respond to commands
685         // during the unmount sequence.
686         close(m_fuse_fd);
687         m_fuse_fd = -1;
688 }
689
690 void MockFS::loop() {
691         std::vector<std::unique_ptr<mockfs_buf_out>> out;
692
693         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
694         ASSERT_TRUE(in != NULL);
695         while (!m_quit) {
696                 ssize_t buflen;
697
698                 bzero(in.get(), sizeof(*in));
699                 read_request(*in, buflen);
700                 if (m_quit)
701                         break;
702                 if (verbosity > 0)
703                         debug_request(*in, buflen);
704                 audit_request(*in, buflen);
705                 if (pid_ok((pid_t)in->header.pid)) {
706                         process(*in, out);
707                 } else {
708                         /* 
709                          * Reject any requests from unknown processes.  Because
710                          * we actually do mount a filesystem, plenty of
711                          * unrelated system daemons may try to access it.
712                          */
713                         if (verbosity > 1)
714                                 printf("\tREJECTED (wrong pid %d)\n",
715                                         in->header.pid);
716                         process_default(*in, out);
717                 }
718                 for (auto &it: out)
719                         write_response(*it);
720                 out.clear();
721         }
722 }
723
724 int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen)
725 {
726         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
727
728         out->header.unique = 0; /* 0 means asynchronous notification */
729         out->header.error = FUSE_NOTIFY_INVAL_ENTRY;
730         out->body.inval_entry.parent = parent;
731         out->body.inval_entry.namelen = namelen;
732         strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry),
733                 name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry));
734         out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) +
735                 namelen;
736         debug_response(*out);
737         write_response(*out);
738         return 0;
739 }
740
741 int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len)
742 {
743         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
744
745         out->header.unique = 0; /* 0 means asynchronous notification */
746         out->header.error = FUSE_NOTIFY_INVAL_INODE;
747         out->body.inval_inode.ino = ino;
748         out->body.inval_inode.off = off;
749         out->body.inval_inode.len = len;
750         out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode);
751         debug_response(*out);
752         write_response(*out);
753         return 0;
754 }
755
756 int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size)
757 {
758         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
759
760         out->header.unique = 0; /* 0 means asynchronous notification */
761         out->header.error = FUSE_NOTIFY_STORE;
762         out->body.store.nodeid = ino;
763         out->body.store.offset = off;
764         out->body.store.size = size;
765         bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size);
766         out->header.len = sizeof(out->header) + sizeof(out->body.store) + size;
767         debug_response(*out);
768         write_response(*out);
769         return 0;
770 }
771
772 bool MockFS::pid_ok(pid_t pid) {
773         if (pid == m_pid) {
774                 return (true);
775         } else if (pid == m_child_pid) {
776                 return (true);
777         } else {
778                 struct kinfo_proc *ki;
779                 bool ok = false;
780
781                 ki = kinfo_getproc(pid);
782                 if (ki == NULL)
783                         return (false);
784                 /* 
785                  * Allow access by the aio daemon processes so that our tests
786                  * can use aio functions
787                  */
788                 if (0 == strncmp("aiod", ki->ki_comm, 4))
789                         ok = true;
790                 free(ki);
791                 return (ok);
792         }
793 }
794
795 void MockFS::process_default(const mockfs_buf_in& in,
796                 std::vector<std::unique_ptr<mockfs_buf_out>> &out)
797 {
798         std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
799         out0->header.unique = in.header.unique;
800         out0->header.error = -EOPNOTSUPP;
801         out0->header.len = sizeof(out0->header);
802         out.push_back(std::move(out0));
803 }
804
805 void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) {
806         int nready = 0;
807         fd_set readfds;
808         pollfd fds[1];
809         struct kevent changes[1];
810         struct kevent events[1];
811         struct timespec timeout_ts;
812         struct timeval timeout_tv;
813         const int timeout_ms = 999;
814         int timeout_int, nfds;
815
816         switch (m_pm) {
817         case BLOCKING:
818                 break;
819         case KQ:
820                 timeout_ts.tv_sec = 0;
821                 timeout_ts.tv_nsec = timeout_ms * 1'000'000;
822                 while (nready == 0) {
823                         EV_SET(&changes[0], m_fuse_fd, EVFILT_READ, EV_ADD, 0,
824                                 0, 0);
825                         nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
826                                 &timeout_ts);
827                         if (m_quit)
828                                 return;
829                 }
830                 ASSERT_LE(0, nready) << strerror(errno);
831                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
832                 if (events[0].flags & EV_ERROR)
833                         FAIL() << strerror(events[0].data);
834                 else if (events[0].flags & EV_EOF)
835                         FAIL() << strerror(events[0].fflags);
836                 m_nready = events[0].data;
837                 break;
838         case POLL:
839                 timeout_int = timeout_ms;
840                 fds[0].fd = m_fuse_fd;
841                 fds[0].events = POLLIN;
842                 while (nready == 0) {
843                         nready = poll(fds, 1, timeout_int);
844                         if (m_quit)
845                                 return;
846                 }
847                 ASSERT_LE(0, nready) << strerror(errno);
848                 ASSERT_TRUE(fds[0].revents & POLLIN);
849                 break;
850         case SELECT:
851                 timeout_tv.tv_sec = 0;
852                 timeout_tv.tv_usec = timeout_ms * 1'000;
853                 nfds = m_fuse_fd + 1;
854                 while (nready == 0) {
855                         FD_ZERO(&readfds);
856                         FD_SET(m_fuse_fd, &readfds);
857                         nready = select(nfds, &readfds, NULL, NULL,
858                                 &timeout_tv);
859                         if (m_quit)
860                                 return;
861                 }
862                 ASSERT_LE(0, nready) << strerror(errno);
863                 ASSERT_TRUE(FD_ISSET(m_fuse_fd, &readfds));
864                 break;
865         default:
866                 FAIL() << "not yet implemented";
867         }
868         res = read(m_fuse_fd, &in, sizeof(in));
869
870         if (res < 0 && !m_quit) {
871                 m_quit = true;
872                 FAIL() << "read: " << strerror(errno);
873         }
874         ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit);
875         /*
876          * Inconsistently, fuse_in_header.len is the size of the entire
877          * request,including header, even though fuse_out_header.len excludes
878          * the size of the header.
879          */
880         ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit);
881 }
882
883 void MockFS::write_response(const mockfs_buf_out &out) {
884         fd_set writefds;
885         pollfd fds[1];
886         int nready, nfds;
887         ssize_t r;
888
889         switch (m_pm) {
890         case BLOCKING:
891         case KQ:        /* EVFILT_WRITE is not supported */
892                 break;
893         case POLL:
894                 fds[0].fd = m_fuse_fd;
895                 fds[0].events = POLLOUT;
896                 nready = poll(fds, 1, INFTIM);
897                 ASSERT_LE(0, nready) << strerror(errno);
898                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
899                 ASSERT_TRUE(fds[0].revents & POLLOUT);
900                 break;
901         case SELECT:
902                 FD_ZERO(&writefds);
903                 FD_SET(m_fuse_fd, &writefds);
904                 nfds = m_fuse_fd + 1;
905                 nready = select(nfds, NULL, &writefds, NULL, NULL);
906                 ASSERT_LE(0, nready) << strerror(errno);
907                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
908                 ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds));
909                 break;
910         default:
911                 FAIL() << "not yet implemented";
912         }
913         r = write(m_fuse_fd, &out, out.header.len);
914         ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno);
915 }
916
917 void* MockFS::service(void *pthr_data) {
918         MockFS *mock_fs = (MockFS*)pthr_data;
919
920         mock_fs->loop();
921
922         return (NULL);
923 }
924
925 void MockFS::unmount() {
926         ::unmount("mountpoint", 0);
927 }